Opening a Device Driver

Before using a device, an application must open the device driver with the MCI_OPEN command message. When MCI receives this message, MCI uses Windows to open your device driver. Windows checks if the device driver is loaded, and, if not, it sends the DRV_LOAD and DRV_ENABLE messages to DriverProc to prepare the driver for use. Your device driver will use the DRV_LOAD message to load custom command tables. (These tables and how to load them are described later in this chapter.) Other actions your device driver should take for the DRV_LOAD and DRV_ENABLE messages are those expected for a Windows installable device driver. When the device driver is loaded, Windows sends the DRV_OPEN message to DriverProc.

For the DRV_OPEN message, Windows sets dwDriverIdentifier to 0L and sets hDriver to the driver handle it creates. Windows sets lParam1 to a pointer to a null-terminated string. The string contains the information following the entry for the device driver in the SYSTEM.INI file. Windows sets lParam2 to a pointer to an MCI_OPEN_DRIVER_PARM data structure.

MCI creates an MCI_OPEN_DRIVER_PARM data structure to exchange information with your device driver. This data structure has the following form:

typedef struct {

UINT wDeviceID;// Device ID created by MCI

LPCSTRlpstrParams; // Pointer to SYSTEM.INI parameter string

UINTwCustomCommandTable;// Handle to custom command table

UINTwType; // Driver type ID

} MCI_OPEN_DRIVER_PARMS;

MCI creates the device ID and passes it to your driver in the wDeviceID field. Your device driver should return this value when it successfully finishes with the DRV_OPEN message. MCI applications use this ID to identify an MCI device driver. (MCI applications drivers do not use the handle Windows creates for hDriver. MCI intercepts this handle and does not pass it back to the calling application.)

MCI places a pointer to a null-terminated string in the lpstrParams field. (This information duplicates the information in the lParam1 parameter of DriverProc.) The string contains the parameters following the definition of the device driver in the SYSTEM.INI file. For many device drivers, no additional information is placed after the definition of the device drive. Some device drivers will include a small amount of configuration data after the definition.

In addition to the tasks your device driver needs to perform for the DRV_OPEN message, it must assign data to the remaining fields of the MCI_OPENDRIVER_PARMS data structure.

If your device driver has registered a custom command table, set the wCustomCommandTable field to its handle. (See “Registering the Command Tables with MCI,” later in this chapter, for more information on this table and obtaining the handle to it.) If your driver does not have a custom command table, set the wCustomCommandTable field to MCI_NO_COMMAND_TABLE.

Your driver must also set the value for the wType field. This value tells the system
which device type specific parsing table to use to parse the command strings. Select
the value used from the following list of MCI_DEVTYPE identifiers. Use the MCI_DEVTYPE_OTHER identifier if your device type is not listed in the table.

Device Type Identifier Description

cdaudio MCI_DEVTYPE_CD_AUDIO CD audio player
dat MCI_DEVTYPE_DAT Digital audio tape player
digitalvideo MCI_DEVTYPE_DIGITAL_VIDEO Digital video in a window
mmmovie MCI_DEVTYPE_ANIMATION Animation
other MCI_DEVTYPE_OTHER Nonstandard MCI device type
overlay MCI_DEVTYPE_OVERLAY Overlay device (analog video in a window)
scanner MCI_DEVTYPE_SCANNER Image scanner
sequencer MCI_DEVTYPE_SEQUENCER MIDI sequencer
vcr MCI_DEVTYPE_VCR Videotape recorder or player
videodisc MCI_DEVTYPE_VIDEODISC Videodisc player
waveaudio MCI_DEVTYPE_WAVEFORM_AUDIO Audio device that plays digitized waveform files

In addition to filling in the MCI_OPEN_DRIVER_PARMS, your device driver should complete any other tasks it needs for operation. For example, it might allocate any global memory it needs. When you allocate memory that is specific to the driver instance, allocate it with the GMEM_SHARE option. This prevents the memory from being freed if the calling application exits without closing your device.

MCI sends the MCI_OPEN_DRIVER message as the next message generated by MCI_OPEN. MCI sets the dwDriverID parameter of DriverProc to the same identifier created when your device driver was opened with DRV_OPEN. MCI also sets hDriver to the handle the system created for DRV_OPEN. The lParam1 parameter contains any flags set by the application opening your device driver. The following list summarizes these flags:

Command Flag Description

MCI_NOTIFY Directs the device driver to return immediately as usual as well as post the MM_MCINOTIFY message to a window function when the requested action is complete.
MCI_OPEN_TYPE Specifies that the lpstrDeviceType field of the data structure contains a pointer to a null-terminated string containing the device type.
MCI_OPEN_TYPE_ID Specifies that the lpstrDeviceType field of the data structure contains an integer device type identifier rather than a string identifier.
MCI_OPEN_ELEMENT Specifies that the lpstrElementName field of the data structure contains a pointer to a null-terminated string containing the device element name.
MCI_OPEN_ELEMENT_ID Specifies that the lpstrElementName field of the data structure contains an element ID.
MCI_OPEN_ALIAS Specifies that the lpstrAlias field of the data structure contains a device alias.
MCI_OPEN_SHAREABLE Specifies that the device or element is to be opened as shareable.
MCI_WAIT Directs the device driver to wait until the requested action is complete before returning to the user.

Your device driver can ignore the MCI_OPEN_TYPE, MCI_OPEN_TYPE_ID, and MCI_OPEN_ALIAS flags. MCI uses these flags to select and manage the MCI device drivers. The other flags used for MCI_OPEN_DRIVER are described in subsequent sections or are described with the data structure fields associated with them.

The lParam2 parameter is of type LPMCI_OPEN_PARMS and points to the data structure containing the open parameters. This structure has the following definition:

typedef struct {

DWORDdwCallback;// Callback for MCI_NOTIFY

UINTwDeviceID;// Device ID returned to user

UINTwReserved0;// Reserved field

LPCSTRlpstrDeviceType;// Device type

LPCSTRlpstrElementName;// Device element

LPCSTRlpstrAlias;// Device alias

} MCI_OPEN_PARMS;

The dwCallback field specifies the handle to the window currently used for the MCI_NOTIFY flag. This field is part of every data structure sent with MCI command messages.

The wDeviceID field contains the value returned by the DRV_OPEN message. This will usually correspond to the device ID.

Only compound device drivers will use the lpstrElementName field. This field contains the name of the device element the application associates with this instance of the driver. The MCI_OPEN_ELEMENT flag validates this field. (Simple device drivers should fail an open with this flag.)

An application might open a compound device driver without the MCI_OPEN_ELEMENT flag to query it with the MCI_GETDEVCAPS or MCI_INFO message. Your driver should fail any messages by returning MCIERR_UNSUPPORTED_FUNCTION that are not supported when a compound device is opened as a simple device.

Both simple and compound devices should allocate any memory needed for operation and associate it with the dwDriverID value when they are opened.

Your device driver can ignore the lpstrDeviceType and lpstrAlias fields of the MCI_OPEN_PARMS data structure.

Unless the application uses the MCI_WAIT flag, your device driver should return to the application as soon as it verifies that it can open successfully. During the verification, your device driver should check for any conditions that might prevent it from completing the open. If your device driver returns to the application before it is fully open, your checks should be complete enough to avoid the contradiction of returning a no error value for MCI_OPEN_DRIVER and then later posting the MM_MCINOTIFY message with MCI_NOTIFY_FAILURE flag. (The MM_MCINOTIFY message is described in the section on handling the MCI_NOTIFY flag.) For example, a device driver might need to load a large file from CD-ROM for its operation. To return to the application as soon as possible, the checks performed for the open sequence might verify only that the file can be loaded. The actual loading of the file could wait until after the device driver returns to the application. Some of the checks required would include verifying that enough memory can be allocated, verifying that the CD-ROM is functional, and verifying that the file exists on the CD-ROM.

Responding to the MCI_OPEN_SHAREABLE Flag

The MCI_OPEN_SHAREABLE flag requests that your device driver allow itself to be shared. For simple devices, this lets multiple applications have unrestricted access to your device driver. As a shared device, your device driver needs to create only one context for the mode and position of the MCI device for all the applications using it. The shared context lets each application change the mode and position of the MCI device. MCI will create a unique device ID for each shared instance of the device driver.

If your simple device cannot be shared, fail the open by returning MCIERR_UNSUPPORTED_FUNCTION. If your device driver is initially opened as shareable, return MCIERR_MUST_USE_SHAREABLE to fail any subsequent opens without the MCI_OPEN_SHAREABLE flag. If your device driver is initially opened as nonshareable, fail any subsequent opens by returning MCIERR_MUST_USE_SHAREABLE.

For compound devices, the MCI_OPEN_SHAREABLE flag applies to the device element. (Compound device drivers opened without a device element should ignore the MCI_OPEN_SHAREABLE flag.) A shared element lets multiple applications access the same context for the file element. All applications accessing the shared context have equal control over the element. If your compound device driver cannot support a shared element context, fail the open by returning MCIERR_UNSUPPORTED_FUNCTION. (The com-pound device drivers shipped with Windows do not support MCI_OPEN_SHAREABLE.)

If an element of your device driver is initially opened as a shared context, return MCIERR_MUST_USE_SHAREABLE to fail subsequent opens of that element context that do not include the MCI_OPEN_SHAREABLE flag. If an element context is initially opened as nonshareable, fail any subsequent opens with MCIERR_MUST_USE_SHAREABLE.

Your device driver might also let applications open a single device element (file) multiple times without using the MCI_OPEN_SHAREABLE flag. In this case, your device driver should treat each instance of the device element as a totally separate device element. You device driver should maintain separate position and status information for each instance.