Saw you post about this on the Cubase forums, so thought I'd take a look. Seems …to be a very useful tool!
Not sure if you tested this with 64bit hosts, but the structure size you have for MIDIHDR (set to `12 * A_PtrSize`, which comes out to 96) is smaller than the actual size of the structure in Windows. Earlier this year, that would have caused your script to fail on Windows 11 24h2/25h2 with an `E_INVALIDARG` HRESULT. The in-box workaround for that just finished rolling out today.
Anyway, lots of folks not using the struct directly get that size incorrect. Sometimes, it causes problems, like with the Sanford library:
https://github.com/tebjan/Sanford.Multimedia.Midi/issues/40
This is what you have
```ahk
; Prepare the MIDIHDR structure
MIDIHDR := Buffer(12 * A_PtrSize)
NumPut("Ptr", sysExBuffer.ptr, MIDIHDR, 0)
NumPut("UInt", bufferSize, MIDIHDR, A_PtrSize)
NumPut("UInt", 0, MIDIHDR, 2 * A_PtrSize) ; dwBytesRecorded
NumPut("Ptr", 0, MIDIHDR, 3 * A_PtrSize) ; dwUser
NumPut("UInt", 0, MIDIHDR, 4 * A_PtrSize) ; dwFlags
NumPut("Ptr", 0, MIDIHDR, 5 * A_PtrSize) ; lpNext
NumPut("Ptr", 0, MIDIHDR, 6 * A_PtrSize) ; reserved
result := DllCall("winmm.dll\midiOutPrepareHeader", "Ptr", this._hMidiOut, "Ptr", MIDIHDR, "UInt", 12 * A_PtrSize)
```
This is the actual definition of the structure from our header files
```cpp
typedef struct midihdr_tag {
LPSTR lpData; /* pointer to locked data block */
DWORD dwBufferLength; /* length of data in data block */
DWORD dwBytesRecorded; /* used for input only */
DWORD_PTR dwUser; /* for client's use */
DWORD dwFlags; /* assorted flags (see defines) */
struct midihdr_tag far *lpNext; /* reserved for driver */
DWORD_PTR reserved; /* reserved for driver */
#if (WINVER >= 0x0400)
DWORD dwOffset; /* Callback offset into buffer */
DWORD_PTR dwReserved[8]; /* Reserved for MMSYSTEM */
#endif
} MIDIHDR, *PMIDIHDR, NEAR *NPMIDIHDR, FAR *LPMIDIHDR;
```
I don't have any ahk scripting experience, so maybe I have some incorrect assumptions here. I assume A_PtrSize is 8 (64 bits). If so, that would also result in the wrong offsets for several of the other fields, which, in the case of uint, are 4 bytes and not 8. Luckily, most of those aren't actually used, so you could just zero out the structure and not put anything past the buffersize. I've made those corrections here:
```ahk
; Prepare the MIDIHDR structure
DWORDSize := 4
DWORD_PTRSize := 8
MIDIHDRSize:= A_PtrSize + DWORDSize + DWORDSize + DWORD_PTRSize + DWORDSize + A_PtrSize + DWORD_PTRSize + DWORDSize + DWORD_PTRSize * 8 ; Total of 112 bytes on 64 bit
MIDIHDR := Buffer(MIDIHDRSize, 0) ; zero-fill the buffer so you don't have to deal with unused fields
NumPut("Ptr", sysExBuffer.ptr, MIDIHDR, 0)
NumPut("UInt", bufferSize, MIDIHDR, A_PtrSize) ; this is a DWORD, 4 bytes
NumPut("UInt", 0, MIDIHDR, A_PtrSize + DWORDSize) ; dwBytesRecorded offset 12 (lpData + dwBufferLength field sizes)
; other fields are not needed and are set to 0 by the initializer here.
; Add them back in with correct offsets if you wish to use them
result := DllCall("winmm.dll\midiOutPrepareHeader", "Ptr", this._hMidiOut, "Ptr", MIDIHDR, "UInt", MIDIHDRSize)
```
(coded that in this comment, so please double-check)
`DWORD` is a 32 bit int
`DWORD_PTR` is 64 bits (`unsigned long long`) even in a 32 bit process
Given that ahk looks to have a `UInt64` type that corresponds to `uint64_t`, I assume `UInt` is 32 bits, like `uint32_t`
The structure is byte-aligned, not word-aligned so the fields are sequential with no padding between them.
As mentioned, with the April update that finished enabling today, we've largely worked around most common incorrect MIDIHDR sizes, but you want to be correct. :)
Pete
Microsoft