This information is not yet completed.

If your application is doing some sort of MIDI sequencing (ie, playback of a musical piece), and you're not using the Stream API or High Level API (ie, MCI Sequencer Device), then you have to maintain a timer in order to figure out when it's time to output the next MIDI message (via midiOutShortMsg for example).

Windows offers a MultiMedia Timer API for such purposes. Such a timer offers much higher resolution than the typical Windows timers (ie, SetTimer and handling WM_TIMER messages). Such a timer also offers the option to directly call a function in your program when it times out, which is a lot more efficient than passing a message to a Window and waiting for your preemptively-multitasked (Win32) program to run and get around to handling that WM_TIMER message. Such efficiency is needed for high resolution MIDI playback.

To have Windows call a function you have written, when you open the timer, you specify the flag CALLBACK_FUNCTION. The third arg is a pointer to your function. (The fourth arg can be any value that you want Windows to pass to your function each time that function is called).

result = midiInOpen(&inHandle, 0, (DWORD)myFunc, 0, CALLBACK_FUNCTION);

One caveat with this first method is that your function must be contained in a Dynamic Link Library.

Another caveat is that, for solid timing under Win95, it must be a 16-bit DLL with the FIXED flag set for the code and data segments and the function name EXPORT'ed in the linker Module Definition file. This necessity is due to the fact that 32-bit Windows MultiMedia Timer callbacks under Win95 may suffer severe timing fluctuations. Since Win95's multimedia system is still 16-bit, you need to put your callback (and any functions it calls) into a 16-bit DLL in order for it to exhibit solid performance under Win95. (WinNT doesn't exhibit this aberrant behavior with 32-bit code). Obviously, this is not very friendly to 32-bit Windows development. Still another caveat is that your function is seriously limited as to the Windows functions that it may call. Essentially, it is limited to calling PostMessage, timeGetSystemTime, timeGetTime, timeSetEvent, timeKillEvent, midiOutShortMsg, midiOutLongMsg, and OutputDebugStr.

To have Windows pass a message to one of your windows, when you open the device, you specify the flag CALLBACK_WINDOW. The third arg is a handle to your window. (The fourth arg is not used).

result = midiInOpen(&inHandle, 0, (DWORD)myWindow, 0, CALLBACK_WINDOW);

One caveat with this second method is that such message passing is not very efficient. By the time that your window procedure finally got around to processing the message, a long come could have transpired. You wouldn't want to use that for time-stamping a message that had already arrived at the computer's MIDI IN. Trying to get an accurate time stamp in an efficient manner is very difficult, especially if other things are happening in the system such as mouse and window movement. For this reason, most professional Win32 apps that run under Win95, still employ 16-bit DLLs using callbacks to handle the timing of MIDI playback. Because Win95 doesn't pre-emptively multi-task 16-bit code, the use of timer callbacks in 16-bit DLLs (and doing your MIDI output in that callback) yields more reliable timing. WinNT has a 32-bit MultiMedia system, and therefore doesn't suffer the same kind of problem with 32-bit callbacks.