【发布时间】:2019-12-29 17:20:25
【问题描述】:
在下面的代码中,当输入 MIDI 消息开始变快时,即使我禁用了许多应用程序参数,Excel 也会崩溃。
当我启用每 7 毫秒发送一条消息的 MIDI 时钟时,代码几乎立即崩溃并且我正在运行 i7,所以,7 毫秒不是小菜一碟...?
好的,下面是完整的代码:
Option Explicit
Private Const CALLBACK_FUNCTION = &H30000
'For Track data
Private Const INT_TIME_SYNC As Integer = 1
'Declaration of MIDIINCAPS Type
Private Type MIDIINCAPS
wMid As Long ' Manufacturer ID
wPid As Long ' Product ID
vDriverVersion As Integer ' Driver version
szPname As String * 32 ' Product Name
dwSupport As Double ' Supported extra controllers (volume, etc)
End Type
Private deviceInCaps As MIDIINCAPS
'MIDI Functions here: https://docs.microsoft.com/en-us/windows/win32/multimedia/midi-functions
#If Win64 Then
'For MIDI device INPUT
Private Declare PtrSafe Function midiInClose Lib "winmm.dll" (ByVal hMidiIn As LongPtr) As Long
Private Declare PtrSafe Function midiInOpen Lib "winmm.dll" (lphMidiIn As LongPtr, ByVal uDeviceID As LongPtr, ByVal dwCallback As LongPtr, ByVal dwInstance As LongPtr, ByVal dwFlags As LongPtr) As Long
Private Declare PtrSafe Function midiInMessage Lib "winmm.dll" (ByVal hMidiIn As LongPtr, ByVal dwMsg As LongPtr) As Long
Private Declare PtrSafe Function midiInGetNumDevs Lib "winmm.dll" () As Long
Private Declare PtrSafe Function midiInGetDevCaps Lib "winmm.dll" Alias "midiInGetDevCapsA" (ByVal uDeviceID As LongPtr, ByRef lpCaps As MIDIINCAPS, ByVal uSize As LongPtr) As Long
Private Declare PtrSafe Function midiInStart Lib "winmm.dll" (ByVal hMidiIn As LongPtr) As Long
Private Declare PtrSafe Function midiInStop Lib "winmm.dll" (ByVal hMidiIn As LongPtr) As Long
Private Declare PtrSafe Function midiInReset Lib "winmm.dll" (ByVal hMidiIn As LongPtr) As Long
#Else
'For MIDI device INPUT
Private Declare Function midiInClose Lib "winmm.dll" (ByVal hMidiIn As Long) As Long
Private Declare Function midiInOpen Lib "winmm.dll" (lphMidiIn As Long, ByVal uDeviceID As Long, ByVal dwCallback As Long, ByVal dwInstance As Long, ByVal dwFlags As Long) As Long
Private Declare Function midiInMessage Lib "winmm.dll" (ByVal hMidiIn As Long, ByVal dwMsg As Long) As Long
Private Declare Function midiInGetNumDevs Lib "winmm.dll" () As Long
Private Declare Function midiInGetDevCaps Lib "winmm.dll" Alias "midiInGetDevCapsA" (ByVal uDeviceID As Long, ByRef lpCaps As MIDIINCAPS, ByVal uSize As Long) As Long
Private Declare Function midiInStart Lib "winmm.dll" (ByVal hMidiIn As Long) As Long
Private Declare Function midiInStop Lib "winmm.dll" (ByVal hMidiIn As Long) As Long
Private Declare Function midiInReset Lib "winmm.dll" (ByVal hMidiIn As Long) As Long
#End If
#If Win64 Then
Private mlngCurDevice As Long
Private mlngHmidi As LongPtr
Private mlngRc As LongPtr
Private mlngMidiMsg As LongPtr
#Else
Private mlngCurDevice As Long
Private mlngHmidi As Long
Private mlngRc As Long
Private mlngMidiMsg As Long
#End If
Private i As Integer
Public Sub ListInputDevices()
Dim devicesList As String
Debug.Print "------------------------------------------------------" & vbCrLf
Debug.Print "Total device number: " & midiInGetNumDevs()
For i = 1 To midiInGetNumDevs()
mlngRc = midiInGetDevCaps(i - 1, deviceInCaps, Len(deviceInCaps))
If (mlngRc = 0) Then
devicesList = devicesList & i & ": " & nTrim(deviceInCaps.szPname) & vbCrLf
Debug.Print "Manufacteur ID: " & deviceInCaps.wMid
Debug.Print "Product ID: " & deviceInCaps.wPid
Debug.Print "Driver Version: " & deviceInCaps.vDriverVersion
Debug.Print "Product Name: " & nTrim(deviceInCaps.szPname)
Debug.Print "Extra Controllers: " & deviceInCaps.dwSupport & vbCrLf
End If
Next
If devicesList = "" Then devicesList = "NONE"
MsgBox devicesList, , "Available INPUT Devices"
End Sub
'FUNCTION THAT CRASHES ALL THE TIME
Public Sub StartMidiFunction()
With Application
.Calculation = xlCalculationManual
.ScreenUpdating = False
'.DisplayStatusBar = False
.EnableEvents = False
End With
Dim lngInputIndex As Long
lngInputIndex = 8
Call midiInOpen(mlngHmidi, lngInputIndex, AddressOf MidiIn_Event, 0, CALLBACK_FUNCTION)
Call midiInStart(mlngHmidi)
Application.StatusBar = "Started"
End Sub
Public Sub EndMidiRecieve()
Call midiInReset(mlngHmidi)
Call midiInStop(mlngHmidi)
Call midiInClose(mlngHmidi)
Application.StatusBar = "Finish"
With Application
.Calculation = xlCalculationManual
.ScreenUpdating = True
.DisplayStatusBar = True
.EnableEvents = True
End With
End Sub
Private Function MidiIn_Event(ByVal mlngHmidi As Long, ByVal Message As Long, ByVal Instance As Long, ByVal dw1 As Long, ByVal dw2 As Long) As Long
Dim last_dw1
If dw1 <> last_dw1 Then
Application.StatusBar = "Message=" & Message & " | dw1=" & dw1 & " | dw2=" & dw2
last_dw1 = dw1
End If
End Function
Function nTrim(theString As String) As String
Dim iPos As Long
iPos = InStr(theString, Chr$(0))
If iPos > 0 Then theString = Left$(theString, iPos - 1)
nTrim = theString
End Function
有什么想法吗?谢谢
【问题讨论】:
-
我能问一下您为什么要使用 VBA 来完成这样的任务吗?看来 VB.NET 会是一个更好的选择。
-
在两个调用语句之间插入
DoEvents再试一次?我的意思是将DoEvents放在Call midiInStart(mlngHmidi)行之前 -
请看下面我的代码...