Client applications must open an audio device before using it and close the device when finished using it, so the device will be available to other applications. It's up to you to decide if your device driver will support more than one client simultaneously.
If you would like to support multiple clients, it's also up to you to decide if you'd like to return more than one for the XXX_GETNUMDEVS message. For example, if your device driver supports multiple clients for simultaneous PCM waveform playback, you might return one for the WODM_GETNUMDEVS message and allow multiple WODM_OPEN messages. Or, if your driver supports completely different playback formats (or routing to different playback hardware) you might wish to consider yourself as more than one device. If you do this, though, remember to always check the uDeviceID parameter to determine which device is being accessed. Also remember to set the xxxDEVCAPS structure so that clients can tell the difference between your devices. For example, your MIDI output driver might support both an external MIDI port and an internal synthesizer. It would make sense to return two for the MDOM_GETNUMDEVS message and consider device zero to be you port and device one your synthesizer.
Auxiliary audio devices are handled differently than waveform and MIDI devices. They don't have to be opened because they don't have the same resource allocation requirements. Also, there is no interrupt level or continuous data transfer associated with auxiliary audio devices.
When a driver receives an open request with a WODM_OPEN, WIDM_OPEN, MODM_OPEN, or MIDM_OPEN message, the dwUser parameter of its entry-point function points to a location that the driver can fill with a DWORD of instance data. This instance data is returned to the driver in the same dwUser parameter when other messages are sent to the driver. Drivers should use this instance data for information related to the client that opened a device. The following code fragment illustrates how the modMessage MIDI output entry-point function for the Sound Blaster handles the MODM_OPEN message:
typedef struct portalloc_tag {
DWORD dwCallback; /* client's callback */
DWORD dwInstance; /* client's instance data */
HMIDIOUT hMidi; /* handle for stream */
DWORD dwFlags; /* allocation flags */
} PORTALLOC;
PORTALLOC gMidiOutClient;
.
.
.
case MODM_OPEN:
/* Attempt to 'acquire' the MIDI output hardware. If the
* output port is already in use by another client or
* another VM owns the Sound Blaster hardware, then
* return MMSYSERR_ALLOCATED.
*/
if ( modAcquireHardware() )
return MMSYSERR_ALLOCATED;
/* Save client information
*/
gMidiOutClient.dwCallback =
((LPMIDIOPENDESC)dwParam1)->dwCallback
gMidiOutClient.dwInstance =
((LPMIDIOPENDESC)dwParam1)->dwInstance
gMidiOutClient.hMidi = ((LPMIDIOPENDESC)dwParam1)->hMidi;
gMidiOutClient.dwFlags = dwParam2;
/* Reset running status...
*/
gbMidiOutCurrentStatus = 0;
/* Notify client...
*/
midiCallback(&gMidiOutClient, MOM_OPEN, 0L, 0L);
/* Return success.
*/
return 0L;