Constructing a Command Table

Command tables are defined as raw data resources which must be compiled using the Microsoft Windows Resource Compiler, discussed in the Win32 SDK. The command table can be created as a separate DLL file, with a file extension of .mci, or it can be linked to the driver.

If you place the command table in a separate DLL, you can also include all of the driver’s string resources in the same file. This provides a convenient means for translating the driver’s text into additional languages by simply replacing this one file.

Following is a small segment, including the first and last entries, of the core command table provided in winmm.dll. This segment provides an illustration of how command tables are constructed.

core RCDATA

BEGIN

  L"open\0",            MCI_OPEN, 0,                  MCI_COMMAND_HEAD,

  L"\0",                MCI_INTEGER, 0,               MCI_RETURN,

  L"notify\0",          MCI_NOTIFY,                   MCI_FLAG,

  L"wait\0",            MCI_WAIT,                     MCI_FLAG,

  L"type\0",            MCI_OPEN_TYPE,                MCI_STRING,

  L"element\0",         MCI_OPEN_ELEMENT,             MCI_STRING,

  L"alias\0",           MCI_OPEN_ALIAS,               MCI_STRING,

  L"shareable\0",       MCI_OPEN_SHAREABLE,           MCI_FLAG,

  L"\0",                0L,                           MCI_END_COMMAND,

  L"close\0",           MCI_CLOSE, 0,                 MCI_COMMAND_HEAD,

  L"notify\0",          MCI_NOTIFY,                   MCI_FLAG,

  L"wait\0",            MCI_WAIT,                     MCI_FLAG,

  L"\0",                0L,                           MCI_END_COMMAND,

  L"play\0",            MCI_PLAY, 0,                  MCI_COMMAND_HEAD,

  L"notify\0",          MCI_NOTIFY,                   MCI_FLAG,

  L"wait\0",            MCI_WAIT,                     MCI_FLAG,

  L"from\0",            MCI_FROM,                     MCI_INTEGER,

  L"to\0",              MCI_TO,                       MCI_INTEGER,

  L"\0",                0L,                           MCI_END_COMMAND,

                       .

                       .

                       .

  L"status\0",          MCI_STATUS, 0,                MCI_COMMAND_HEAD,

  L"\0",                MCI_INTEGER, 0,               MCI_RETURN,

  L"notify\0",          MCI_NOTIFY,                   MCI_FLAG,

  L"wait\0",            MCI_WAIT,                     MCI_FLAG ,

  L"\0",                MCI_STATUS_ITEM,              MCI_CONSTANT,

  L"position\0",        MCI_STATUS_POSITION,          MCI_INTEGER,

  L"length\0",          MCI_STATUS_LENGTH,            MCI_INTEGER,

  L"number of tracks\0",MCI_STATUS_NUMBER_OF_TRACKS,  MCI_INTEGER,

  L"ready\0",           MCI_STATUS_READY,             MCI_INTEGER,

  L"mode\0",            MCI_STATUS_MODE,              MCI_INTEGER,

  L"time format\0",     MCI_STATUS_TIME_FORMAT,       MCI_INTEGER,

  L"current track\0",   MCI_STATUS_CURRENT_TRACK,     MCI_INTEGER,

  L"\0",                0L,                           MCI_END_CONSTANT,

  L"track\0",           MCI_TRACK,                    MCI_INTEGER,

  L"start\0",           MCI_STATUS_START,             MCI_FLAG,

  L"\0",                0L,                           MCI_END_COMMAND,

                       .

                       .

                       .

  L"set\0",             MCI_SET, 0,                   MCI_COMMAND_HEAD,

  L"notify\0",          MCI_NOTIFY,                   MCI_FLAG,

  L"wait\0",            MCI_WAIT,                     MCI_FLAG ,

  L"time format\0",     MCI_SET_TIME_FORMAT,          MCI_CONSTANT,

  L"milliseconds\0",    MCI_FORMAT_MILLISECONDS, 0,   MCI_INTEGER,

  L"ms\0",              MCI_FORMAT_MILLISECONDS, 0,   MCI_INTEGER,

  L"\0",                0L,                           MCI_END_CONSTANT,

  L"door open\0",       MCI_SET_DOOR_OPEN,            MCI_FLAG,

  L"door closed\0",     MCI_SET_DOOR_CLOSED,          MCI_FLAG,

  L"audio\0",           MCI_SET_AUDIO,                MCI_CONSTANT,

  L"all\0",             MCI_SET_AUDIO_ALL,            MCI_INTEGER,

  L"left\0",            MCI_SET_AUDIO_LEFT,           MCI_INTEGER,

  L"right\0",           MCI_SET_AUDIO_RIGHT,          MCI_INTEGER,

  L"\0",                0L,                           MCI_END_CONSTANT,

  L"video\0",           MCI_SET_VIDEO,                MCI_FLAG,

  L"on\0",              MCI_SET_ON,                   MCI_FLAG,

  L"off\0",             MCI_SET_OFF,                  MCI_FLAG,

  L"\0",                0L,                           MCI_END_COMMAND,

                       .

                       .

                       .

  L"resume\0",          MCI_RESUME, 0,                MCI_COMMAND_HEAD,

  L"notify\0",          MCI_NOTIFY,                   MCI_FLAG,

  L"wait\0",            MCI_WAIT,                     MCI_FLAG,

  L"\0",                0L,                           MCI_END_COMMAND,

  L"\0",                0L,                         MCI_END_COMMAND_LIST

END

 

As shown in the previous example, a command table is defined by using an RCDATA statement, which is described in the Win32 SDK.. The RCDATA declaration includes the table’s name. For the core table, the table’s name is “core”. For a device-type table, the table’s name is the device type, such as “videodisc”.

Command tables contain command table entries. Each entry contains:

·A null-terminated string identifying a command or command modifier. This is the text that applications specify with calls to mciSendString. Each string is prefaced with “L” to create wide-character storage for UNICODE characters.

·A longword value containing a command constant or modifier flag constant value. Mostly, these are the constants an application uses with the mciSendCommand function. Drivers receive the constant values as umsg and lParam1 arguments to DriverProc. Note that some predefined constants, such as MCI_INTEGER, only define single word values. These single-word constants must be padded with an extra word to create a longword.

·A single word value representing the entry type.

The table must end with an entry of type MCI_END_COMMAND_LIST.

Example

As an example of how to define a command, look at the “play” command contained in the core table. While the “play” command in the core command table is fairly simple, it illustrates several of the entry types that can be used for creating a command description.

To define a command in a command table

1.Begin with an MCI_COMMAND_HEAD entry. This entry has the following format:

L"play\0",            MCI_PLAY, 0,                  MCI_COMMAND_HEAD,

 

First, the entry contains a null-terminated, wide-character string containing the command’s string name. Next, a longword value is specified, with the MCI_PLAY bit set. (Because MCI_PLAY is defined as a 16-bit constant, an additional word of zero is added as the highword value for the longword.) Finally, the entry type is specified as MCI_COMMAND_HEAD, which labels this entry as a new command.

2.Include two entries indicating that the command accepts the MCI_NOTIFY and MCI_WAIT modifiers. (All command definitions must contain these two entries.)

L"notify\0",          MCI_NOTIFY,                   MCI_FLAG,

L"wait\0",            MCI_WAIT,                     MCI_FLAG,

 

The MCI_FLAG entry type is used for defining command modifiers that do not require either input or output members within the command’s data structure (in this case, MCI_PLAY_PARMS). (See Creating New MCI Command Structures.)

3.Include command-specific modifier definitions. The “play” command accepts two modifiers, “from” and “to”.

L"from\0",            MCI_FROM,                     MCI_INTEGER,

L"to\0",              MCI_TO,                       MCI_INTEGER,

 

The “from” and “to” modifiers both accept numeric arguments, such as “play videodisc1 from 10 to 100”. The MCI_INTEGER type indicates that for each of these arguments, an integer-typed member exists in the “play” command’s MCI_PLAY_PARMS structure. Following is a list of recognized data types:

MCI_INTEGER Integer
MCI_HWND Window handle
MCI_HPAL Palette handle
MCI_HDC Device Context handle
MCI_RECT Rectangle
MCI_STRING String

For a complete list of entry types, see Command Table Entry Types.

4.End the command definition with an MCI_END_COMMAND entry.

L"\0",                0L,                           MCI_END_COMMAND,

 

The entry must contain a null string, followed by a null longword.

Example

As another example, look at the “status” command. This command provides a return value, so its command description includes an MCI_RETURN entry. This entry must appear immediately after the MCI_COMMAND_HEAD entry.

L"status\0",          MCI_STATUS, 0,                MCI_COMMAND_HEAD,

L"\0",                MCI_INTEGER, 0,               MCI_RETURN,

 

An MCI_RETURN entry must contain a null string, followed by a longword specifiying the data type of the command’s return value. Any of the MCI data types can be used. In this case, the command returns an integer value. The command’s data structure must contain an integer-typed member for storing the return value. (See Creating New MCI Command Structures.)

Defining Constant Values

Sometimes it is necessary to define a set of constant values that can be assigned to a data structure member. Constant values are delimited by MCI_CONSTANT and MCI_END_CONSTANT entries. Here is a section of the “set” command description:

L"audio\0",           MCI_SET_AUDIO,                MCI_CONSTANT,

L"all\0",             MCI_SET_AUDIO_ALL,            MCI_INTEGER,

L"left\0",            MCI_SET_AUDIO_LEFT,           MCI_INTEGER,

L"right\0",           MCI_SET_AUDIO_RIGHT,          MCI_INTEGER,

L"\0",                0L,                           MCI_END_CONSTANT,

 

An MCI_CONSTANT entry must contain a string, followed by a longword containing a flag value. A command’s data structure must reserve a DWORD-sized member for each MCI_CONSTANT entry in the command table. Entries following the MCI_CONSTANT entry define a set of constant values that can be set in the data structure member. The set of constant entries ends with an MCI_END_CONSTANT entry, which must contain a null string and a null longword.

If an application uses mciSendString to specify the command “set vcr1 audio left”, then winmm.dll sets the MCI_SET_AUDIO flag in laram1 to indicate the dwAudio member for the MCI_SET_PARMS structure is valid, and sets MCI_SET_AUDIO_LEFT in dwAudio.

Here is another section of the “status” description:

L"\0",                MCI_STATUS_ITEM,              MCI_CONSTANT,

L"position\0",        MCI_STATUS_POSITION,          MCI_INTEGER,

L"length\0",          MCI_STATUS_LENGTH,            MCI_INTEGER,

L"number of tracks\0",MCI_STATUS_NUMBER_OF_TRACKS,  MCI_INTEGER,

L"ready\0",           MCI_STATUS_READY,             MCI_INTEGER,

L"mode\0",            MCI_STATUS_MODE,              MCI_INTEGER,

L"time format\0",     MCI_STATUS_TIME_FORMAT,       MCI_INTEGER,

L"current track\0",   MCI_STATUS_CURRENT_TRACK,     MCI_INTEGER,

L"\0",                0L,                           MCI_END_CONSTANT,

 

For this constant list, the MCI_CONSTANT entry contains a null string. A null string is allowed if the command description defines only one modifier type and, hence, one structure input member. If the description defines more than one modifier, a string must be included so the command parser can identify which command structure member to use.

For the “status” command, an application can specify “status vcr1 position”, for example, to obtain the current position, and “status vcr1 mode” to obtain the current mode. Both “position” and “mode” use the dwItem member in MCI_STATUS_PARMS. In constrast, for the “set” command an application must specify “set vcr1 time format milliseconds” to set the time format, and “set vcr1 audio all” to set all audio channels. Here, “time format” and “audio” differentiate between the dwTimeFormat and dwAudio members of MCI_SET_PARMS.