Here’s the code I use in the Sends on Fader Application to Read and Write MIDI From/To the Yamaha consoles. Should work for any MIDI messages.
Module MidiFunctions
' MIDI input device capabilities structure
<StructLayout(LayoutKind.Sequential)> _
Public Structure MIDIINCAPS
Dim wMid As Short ' Manufacturer ID
Dim wPid As Short ' Product ID
Dim vDriverVersion As Integer ' Driver version
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=32)> _
Dim szPname As String ' Product Name
Dim dwSupport As Integer ' Supported extras
End Structure
' MIDI output device capabilities structure
<StructLayout(LayoutKind.Sequential)> _
Public Structure MIDIOUTCAPS
Dim wMid As Short ' Manufacturer ID
Dim wPid As Short ' Product ID
Dim vDriverVersion As Integer ' Driver version
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=32)> _
Dim szPname As String ' Product Name
Dim wTechnology As Short ' Device type
Dim wVoices As Short ' n. of voices (internal synth only)
Dim wNotes As Short ' max n. of notes (internal synth only)
Dim wChannelMask As Short ' n. of Midi channels (internal synth only)
Dim dwSupport As Integer ' Supported extra controllers (volume, etc)
End Structure
' MIDI data block header
<StructLayout(LayoutKind.Sequential)> _
Public Structure MIDIHDR
Dim lpData As IntPtr ' pointer to locked data block
Dim dwBufferLength As Integer ' length of data in data block
Dim dwBytesRecorded As Integer ' used for input only
Dim dwUser As Integer ' for client's use
Dim dwFlags As Integer ' assorted flags (see defines)
Dim lpNext As Integer ' reserved for driver
Dim reserved As Integer ' reserved for driver
Dim dwOffset As Integer
Dim reserved1 As Integer
Dim reserved2 As Integer
Dim reserved3 As Integer
Dim reserved4 As Integer
End Structure
'Input functions
Declare Function midiInGetNumDevs Lib "winmm.dll" () As Short
Declare Function midiInGetDevCaps Lib "winmm.dll" Alias "midiInGetDevCapsA" (ByVal uDeviceID As Integer, ByRef lpCaps As MIDIINCAPS, ByVal uSize As Integer) As Integer
Declare Function midiInGetErrorText Lib "winmm.dll" Alias "midiInGetErrorTextA" (ByVal err_Renamed As Integer, ByVal lpText As String, ByVal uSize As Integer) As Integer
Declare Function midiInOpen Lib "winmm.dll" (ByRef lphMidiIn As Integer, ByVal uDeviceID As Integer, ByVal dwCallback As MidiDelegate, _
ByVal dwInstance As Integer, ByVal dwFlags As Integer) As Integer
Declare Function midiInClose Lib "winmm.dll" (ByVal hMidiIN As Integer) As Integer
Declare Function midiInPrepareHeader Lib "winmm.dll" (ByVal hMidiIN As Integer, ByRef lpMidiInHdr As MIDIHDR, ByVal uSize As Integer) As Integer
Declare Function midiInUnprepareHeader Lib "winmm.dll" (ByVal hMidiIN As Integer, ByRef lpMidiInHdr As MIDIHDR, ByVal uSize As Integer) As Integer
Declare Function midiInAddBuffer Lib "winmm.dll" (ByVal hMidiIN As Integer, ByRef lpMidiInHdr As MIDIHDR, ByVal uSize As Integer) As Integer
Declare Function midiInReset Lib "winmm.dll" (ByVal hMidiIN As Integer) As Integer
Declare Function midiInStart Lib "winmm.dll" (ByVal hMidiIN As Integer) As Integer
Declare Function midiInStop Lib "winmm.dll" (ByVal hMidiIN As Integer) As Integer
'Output functions
Declare Function midiOutGetNumDevs Lib "winmm.dll" () As Short
Declare Function midiOutGetDevCaps Lib "winmm.dll" Alias "midiOutGetDevCapsA" (ByVal uDeviceID As Integer, ByRef lpCaps As MIDIOUTCAPS, ByVal uSize As Integer) As Integer
Declare Function midiOutGetErrorText Lib "winmm.dll" Alias "midiOutGetErrorTextA" (ByVal errcode As Integer, ByVal lpText As String, ByVal uSize As Integer) As Integer
Declare Function midiOutOpen Lib "winmm.dll" (ByRef lphMidiOut As Integer, ByVal uDeviceID As Integer, ByVal dwCallback As Integer, _
ByVal dwInstance As Integer, ByVal dwFlags As Integer) As Integer
Declare Function midiOutClose Lib "winmm.dll" (ByVal hMidiOut As Integer) As Integer
Declare Function midiOutPrepareHeader Lib "winmm.dll" (ByVal hMidiOut As Integer, ByRef lpMidiOutHdr As MIDIHDR, ByVal uSize As Integer) As Integer
Declare Function midiOutUnprepareHeader Lib "winmm.dll" (ByVal hMidiOut As Integer, ByRef lpMidiOutHdr As MIDIHDR, ByVal uSize As Integer) As Integer
Declare Function midiOutShortMsg Lib "winmm.dll" (ByVal hMidiOut As Integer, ByVal dwMsg As Integer) As Integer
Declare Function midiOutLongMsg Lib "winmm.dll" (ByVal hMidiOut As Integer, ByRef lpMidiOutHdr As MIDIHDR, ByVal uSize As Integer) As Integer
Public Delegate Sub MidiDelegate(ByVal MidiHandle As Int32, ByVal wMsg As Int32, ByVal Instance As Int32, ByVal wParam As Int32, ByVal lParam As Int32)
' Callback Function constants
Public Const CALLBACK_FUNCTION As Integer = &H30000 ' dwCallback is a FARPROC
Public Const MIM_OPEN As Short = &H3C1S ' MIDI In Port Opened
Public Const MIM_CLOSE As Short = &H3C2S ' MIDI In Port Closed
Public Const MIM_DATA As Short = &H3C3S ' MIDI In Short Data (e.g. Notes & CC)
Public Const MIM_LONGDATA As Short = &H3C4S ' MIDI In Long Data (i.e. SYSEX)
Public Const MIM_ERROR As Short = &H3C5S ' MIDI In Error
Public Const MIM_LONGERROR As Short = &H3C6S ' MIDI In Long Error
Public Const MIM_MOREDATA As Short = &H3CCS ' MIDI Header Buffer is Full
Public Const MOM_OPEN As Short = &H3C7S ' MIDI Out Port Opened
Public Const MOM_CLOSE As Short = &H3C8S ' MIDI Out Port Closed
Public Const MOM_DONE As Short = &H3C9S ' MIDI Out Data sending completed
Public Const MOM_POSITIONCB As Short = &HCAS ' MIDI Out Position requested
' Midi Error Constants
Public Const MMSYSERR_NOERROR As Short = 0
Public Const MMSYSERR_ERROR As Short = 1
Public Const MMSYSERR_BADDEVICEID As Short = 2
Public Const MMSYSERR_NOTENABLED As Short = 3
Public Const MMSYSERR_ALLOCATED As Short = 4
Public Const MMSYSERR_INVALHANDLE As Short = 5
Public Const MMSYSERR_NODRIVER As Short = 6
Public Const MMSYSERR_NOMEM As Short = 7
Public Const MMSYSERR_NOTSUPPORTED As Short = 8
Public Const MMSYSERR_BADERRNUM As Short = 9
Public Const MMSYSERR_INVALFLAG As Short = 10
Public Const MMSYSERR_INVALPARAM As Short = 11
Public Const MMSYSERR_HANDLEBUSY As Short = 12
Public Const MMSYSERR_INVALIDALIAS As Short = 13
Public Const MMSYSERR_BADDB As Short = 14
Public Const MMSYSERR_KEYNOTFOUND As Short = 15
Public Const MMSYSERR_READERROR As Short = 16
Public Const MMSYSERR_WRITEERROR As Short = 17
Public Const MMSYSERR_DELETEERROR As Short = 18
Public Const MMSYSERR_VALNOTFOUND As Short = 19
Public Const MMSYSERR_NODRIVERCB As Short = 20
Public Const MMSYSERR_LASTERROR As Short = 20
Public Const MIDIERR_UNPREPARED As Short = 64 ' header not prepared
Public Const MIDIERR_STILLPLAYING As Short = 65 ' still something playing
Public Const MIDIERR_NOMAP As Short = 66 ' no current map
Public Const MIDIERR_NOTREADY As Short = 67 ' hardware is still busy
Public Const MIDIERR_NODEVICE As Short = 68 ' port no longer connected
Public Const MIDIERR_INVALIDSETUP As Short = 69 ' invalid setup
Public Const MIDIERR_LASTERROR As Short = 69 ' last error in range
' Midi Header flags
Public Const MHDR_DONE As Short = 1 ' Set by the device driver to indicate that it is finished with the buffer and is returning it to the application.
Public Const MHDR_PREPARED As Short = 2 ' Set by Windows to indicate that the buffer has been prepared
Public Const MHDR_INQUEUE As Short = 4 ' Set by Windows to indicate that the buffer is queued for playback
Public Const MHDR_ISSTRM As Short = 8 ' Set to indicate that the buffer is a stream buffer
EndModule