Hello,
I'm a bit stuck here...

Background:
a program that (eventually) will save data synchronised from a MTC. (ive worked out all the mtc stuff)
The code I am using uses winmm.dll to receive midi messages. This works fine, I can process incoming packets etc.
using vb2010

What I'm stuck with:
The callback function when a packet is received can't output anything on my form. I'm aware this is most likely a threading issue, and I have tried many ways of getting around this, and I cant figure it out. The latest is detailed below

Code:
Midi Module:

Module Module1

    'all the midi declarations
    Delegate Function MidiIn_Callback(ByVal hMidiIn As Integer, ByVal wMsg As UInteger, ByVal dwInstance As Integer, ByVal dwParam1 As Integer, ByVal dwParam2 As Integer) As Integer
    Public Declare Function midiInOpen Lib "winmm.dll" (ByRef lphMidiIn As Integer, ByVal uDeviceID As Integer, ByVal dwCallback As MidiIn_Callback, ByVal dwInstance As Integer, ByVal dwFlags As Integer) As Integer
    Public Declare Function midiInClose Lib "winmm.dll" (ByVal hMidiIn As Integer) As Integer
    Public Declare Function midiInStart Lib "winmm.dll" (ByVal hMidiIn As Integer) As Integer
    Public hMidiIn As Integer
    Public Const CALLBACK_FUNCTION As Integer = &H30000

    'these are public for debug purposes.
    Public frames As Int16
    Public seconds As Int16
    Public minutes As Int16
    Public hours As Int16
    Public timecode As Long
    Public byte1 As Byte
    Public byte2 As Byte
    Public nibble1 As Byte
    Public nibble2 As Byte

    

    Function MidiInProc(ByVal hMidiIn As Integer, ByVal wMsg As UInteger, ByVal dwInstance As Integer, ByVal dwParam1 As Integer, ByVal dwParam2 As Integer) As Integer

        'MTC is 2 bytes. Byte 1 is F1 (means its an MTC packet). Byte 2 is a frame counter & frame value
        byte1 = dwParam1 And &HFF
        'skip if it isnt a frame packet
        If byte1 <> &HF1 Then
            Return 0
            Exit Function
        End If

        'byte 2 is split into nibbles. MS Nibble is Message Type, LS Nibble is Message
        byte2 = dwParam1 >> 8
        nibble1 = byte2 And &HF
        nibble2 = byte2 >> 4

        'operate!
        Select Case nibble2
            Case 0  'frame lsb
                'mask
                frames = (frames And &HF0) Or nibble1
            Case 1  'frame msb
                'shift
                nibble1 = nibble1 << 4
                'apply
                frames = (frames And &HF) Or nibble1
            Case 2  'second lsb
                'apply
                seconds = (seconds And &HF0) Or nibble1
            Case 3  'second msb
                'shift
                nibble1 = nibble1 << 4
                'apply
                seconds = (seconds And &HF) Or nibble1
            Case 4  'minute lsb
                'apply
                minutes = (minutes And &HF0) Or nibble1
                frames = frames + 1
            Case 5  'second msb
                'shift
                nibble1 = nibble1 << 4
                'apply
                minutes = (minutes And &HF) Or nibble1
            Case 6  'hours lsb
                'apply
                hours = (hours And &HF0) Or nibble1
            Case 7  'hours msb
                'shift
                nibble1 = nibble1 << 4
                'apply
                hours = (hours And &HF) Or (nibble1 And &H1)
        End Select
'------------------ this call works, and passes the argument. debug.print(arg0) shows this, see below
        If nibble2 = 1 Or nibble2 = 5 Then
            Form1.SomeSub(hours & ":" & minutes & ":" & seconds & ":" & frames & " -- " & nibble2)
        End If
    End Function
End Module

Form Module:

Private Delegate Sub DelegateForSomeSub(ByVal arg0 As String)

    Public Sub SomeSub(ByVal arg0 As String)
        If Me.InvokeRequired Then
            ' Argument array for the delegate
            Dim args As Object() = {arg0}
            ' Method to call
            Dim SomeSubDelegate As DelegateForSomeSub
            SomeSubDelegate = AddressOf SomeSub
            ' After this you're in the main thread (UI thread)
            Me.Invoke(SomeSubDelegate, args)
            Exit Sub
        End If

        'this doesnt work
        TextBox1.AppendText(arg0)
        'this does work
        Debug.Print(arg0)
    End Sub

the delegate sub (etc) is lifted straight from this post -> http://www.daniweb.com/software-development/vbnet/threads/293937

I'd really like to understand why this isnt working. I've trawled the internet (no doubt someone will find a link i didnt), and I cant find anything that a)works or b)i can make work

Anyone have any ideas?

Recommended Answers

All 7 Replies

had a thought and tried this:

'doesnt work
TextBox1.Text = Module1.hours & ":" & Module1.minutes & ":" & Module1.seconds & ":" & Module1.frames & " -- " & Module1.nibble2
'does work
Debug.Print(Module1.hours & ":" & Module1.minutes & ":" & Module1.seconds & ":" & Module1.frames & " -- " & Module1.nibble2)

in the SomeSub... seing as debug.print would work with a passed argument, i wandered if I could just call a function that would fetch the variables itself. I was wrong

Use this code in your Form:

Private Delegate Sub DelegateForSomeSub(ByVal arg0 As String)

	Public Sub SomeSub(ByVal arg0 As String)
		If Me.InvokeRequired Then
			Me.Invoke(New DelegateForSomeSub(AddressOf AppendText), arg0)
		Else
			AppendText(arg0)
		End If
	End Sub

	Private Sub AppendText(arg0 As String)
		TextBox1.AppendText(arg0)
	End Sub

Still not working.
It looks like me.invokerequired is always returning false.

I have uploaded the project.
I use LoopBe1 to create an internal midi loopback, and MidiOX to generate the midi timecode (click the yellow 0:13 clock icon at the top, and hit play).

also, if i force it to invoke the delegate sub, i get the following error

An unhandled exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll

Additional information: Invoke or BeginInvoke cannot be called on a control until the window handle has been created.

replace:
Form1.SomeSub(hours & ":" & minutes & ":" & seconds & ":" & frames & " -- " & nibble2)

with:
DirectCast(My.Application.OpenForms.Item("Form1"),Form1).SomeSub(hours & ":" & minutes & ":" & seconds & ":" & frames & " -- " & nibble2)

Magic thanks! Thats working now.

why does it need to be cast as Form1? trying to understand this, not just solve it :).
even just some keywords to get me started...

If you call "Form1.SomeSub" then the Form1 don't need to be initialized. If this Form is not initialized then of course the controls on it are also not initialized either.

Using "DirectCast(My.Application.OpenForms.Item("Form1"),Form1).SomeSub" instead will take the already initialized Form1.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.