Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Мультимедиа для Windows

© Александр Фролов, Григорий Фролов
Том 15, М.: Диалог-МИФИ, 1994, 284 стр.

[Назад] [Содеожание] [Дальше]

2.3. Интерфейс управляющих сообщений MCI

Интерфейс управляющих сообщений более удобен для приложений, составленных на языках программирования С и С++. Он предполагает посылку устройствам мультимедиа управляющих сообщений с помощью функции mciSendCommand .

В качестве одного из параметров этой функции передается двоичный код управляющего сообщения (команды). Символические константы кодов команд определены в файле mmsystem.h. В дополнение к коду команды функции mciSendCommand передается структура параметров, формат которой зависит от кода команды, а также другая дополнительная информация, необходимая для выполнения команды.

Функция mciSendCommand

Для передачи управляющих сообщений драйверам устройств мультимедиа используется функция mciSendCommand , описание которой приведено ниже.

Функция mciSendCommand

DWORD mciSendCommand(
  UINT wDeviceID,  // идентификатор устройства
  UINT wMessage,   // код сообщения
  DWORD dwParam1,  // флаги команды
  DWORD dwParam2); // указатель на структуру параметров

Параметры функции:

wDeviceID

Идентификатор устройства, которому посылается сообщение. Для команды MCI_OPEN не используется, так как идентификатор создается в результате выполнения этой команды

wMessage

Код сообщения. Соответствует требуемой функции. Список кодов сообщений (команд) для звукового адаптера приведен в следующем разделе

dwParam1

Флаги команды. Флаги используются для того чтобы сообщить функции, какие параметры, заданные в структуре параметров, следует использовать при выполнении команды. Если ни один флаг не указан, параметры игнорируются

dwParam2

Указатель на структуру параметров. Формат этой структуры зависит от кода сообщения

Возвращаемое значение:

Нуль при нормальном завершении или код ошибки. Список кодов ошибок для функции mciSendCommand приведен в приложении 1. С помощью функции mciGetErrorString, рассмотренной нами ранее, вы можете преобразовать код ошибки в текстовую строку, передав ей этот код в качестве параметра

Формат структуры параметров (блока параметров) и используемые флаги зависят от кода управляющего сообщения, передаваемого функции mciSendCommand через параметр wMessage.

Коды управляющих сообщений MCI

Коды управляющих сообщений делятся на системные (System), обязательные (Required), базовые (Basic) и расширенные (Extended), точно также как и команды, используемые в интерфейсе управляющих строк, рассмотренном нами в предыдущем разделе.

Приведем список кодов управляющих сообщений (в дальнейшем просто команд), которые используются для управления звуковым адаптером.

Команда Тип Описание
MCI_BREAK Системная Назначение виртуального кода клавиши, с помощью которой можно прервать работу устройства
MCI_SYSINFO - Получение системной информации об устройстве (в виде текстовой строки)
MCI_GETDEVCAPS Обязательная Определение возможностей устройства
MCI_CLOSE - Закрытие устройства
MCI_INFO - Получение текстовой информации об устройстве
MCI_OPEN - Открытие устройства
MCI_STАTUS - Определение состояния устройства
MCI_LOAD Базовая Загрузка данных из файла
MCI_PAUSE - Пауза при проигрывании
MCI_PLAY - Включение режима проигрывания
MCI_RECORD - Включение режима записи
MCI_RESUME - Продолжение проигрывания после паузы
MCI_SAVE - Сохранение данных в файле
MCI_SEEK - Позиционирование
MCI_SET - Установка режима работы устройства
MCI_STOP - Останов проигрывания
MCI_CUE Расширенная Подготовка устройства для проигрывания или записи
MCI_DELETE - Удаление фрагмента данных

Как нетрудно заметить, состав и назначение групп управляющих сообщений полностью соответствует составу и назначению групп управляющих строк. Расскажем об использовании наиболее полезных управляющих сообщений (команд MCI).

MCI_OPEN

Перед использованием устройства мультимедиа вы должны его открыть, вызвав функцию mciSendCommand и указав ей в качестве второго параметра код команды MCI_OPEN .

Первый параметр (идентификатор устройства) можно указать как 0, так как пока мы не открыли устройство, ему не присвоен никакой идентификатор.

Через последний (четвертый) параметр нужно передать функции адрес заполненной структуры MCI_OPEN_PARMS , определенной в файле mmsystem.h:

typedef struct tagMCI_WAVE_OPEN_PARMS {
    DWORD   dwCallback;
    UINT    wDeviceID;
    UINT    wReserved0;
    LPCSTR  lpstrDeviceType;
    LPCSTR  lpstrElementName;
    LPCSTR  lpstrAlias;
} MCI_OPEN_PARMS;
typedef MCI_OPEN_PARMS FAR *LPMCI_OPEN_PARMS;

В этой структуре младшее слово поля dwCallback должно содержать идентификатор окна, которому после выполнения команды будет посылаться извещение в виде сообщения MM_MCINOTIFY . Если извещение не посылается, значение этого поля игнорируется.

В поле wDeviceID после возвращения из функции mciSendCommand будет записан идентификатор, присвоенный устройству при открытии. Все последующие команды MCI должны ссылаться на этот идентификатор.

Поле wReserved0 зарезервировано, в него следует записать нулевое значение.

Поле lpstrDeviceType содержит указатель на строку имени устройства, или константный идентификатор устройства. Для звукового адаптера вы можете указать имя "waveaudio " или константу MCI_DEVTYPE_WAVWFORM_AUDIO .

Через параметр lpstrElementName передается указатель на путь к файлу, если нужно проиграть звуковой фрагмент, записанный в wav-файле.

Дополнительно при открытии устройства ему можно назначить алиасное имя, записав в поле lpstrAlias указатель на строку алиасного имени.

Третий параметр функции mciSendCommand предназначен для флагов, определяющих, какие из полей структуры параметров следует использовать при открытии устройства, а также для флага MCI_WAIT, устанавливающего режим работы функции (с ожиданием или без ожидания). Флаги можно объединять с помощью логической операции ИЛИ.

Для структуры MCI_OPEN_PARMS определены следующие флаги:

Флаг Описание
MCI_NOTIFY Если установлен этот флаг, после завершения команды функции окна, адрес которой передан через поле dwCallback, будет послано сообщение MM_MCINOTIFY
MCI_WAIT Функция mciSendCommand вернет управление только после завершения процесса открытия устройства
MCI_OPEN_ALIAS Используется алиасное имя, адрес строки имени должен быть указан в поле lpstrAlias
MCI_OPEN_SHAREABLE Устройство открывается в режиме совместного использования несколькими приложениями одновременно
MCI_OPEN_ELEMENT Поле lpstrElementName содержит указатель на строку, в которой находится путь к файлу
MCI_OPEN_TYPE Поле lpstrDeviceType содержит указатель на строку имени устройства, например, адрес строки "waveaudio"
MCI_OPEN_TYPE_ID Поле lpstrDeviceType содержит константный идентификатор устройства, например, константу MCI_DEVTYPE_WAVWFORM_AUDIO

Приведенный ниже фрагмент кода открывает устройство "waveaudio", причем будет открыт файл, адрес пути к которому записан в переменной szFileName:

MCI_OPEN_PARMS mciOpen;
DWORD dwFlags;
mciOpen.lpstrDeviceType  = (LPSTR)"waveaudio";
mciOpen.lpstrElementName = (LPSTR)szFileName;
mciOpen.dwCallback = 0;
mciOpen.wDeviceID  = 0;
mciOpen.wReserved0 = 0;
mciOpen.lpstrAlias = NULL;
dwFlags = MCI_OPEN_TYPE | MCI_OPEN_ELEMENT | MCI_WAIT;
dwrc = mciSendCommand(0, MCI_OPEN,  dwFlags,
       (DWORD)(LPVOID)&mciOpen);

После выполнения этого фрагмента в переменную dwrc, будет записан код результата завершения. При успешном завершении в поле wDeviceID структуры mciOpen будет находиться идентификатор открытого устройства.

Для звукового адаптера вы можете использовать расширенную структуру MCI_WAVE_OPEN_PARMS , также определенную в файле mmsystem.h:

typedef struct tagMCI_WAVE_OPEN_PARMS {
    DWORD   dwCallback;
    UINT    wDeviceID;
    UINT    wReserved0;
    LPCSTR  lpstrDeviceType;
    LPCSTR  lpstrElementName;
    LPCSTR  lpstrAlias;
    DWORD   dwBufferSeconds;
} MCI_WAVE_OPEN_PARMS;
typedef MCI_WAVE_OPEN_PARMS FAR *LPMCI_WAVE_OPEN_PARMS;

По сравнению со структурой MCI_OPEN_PARMS в ней есть дополнительное поле dwBufferSeconds. Это поле определяет размер внутреннего буфера системы MCI для звукового драйвера. Численно размер буфера должен быть равен длительности звучания в секундах.

Чтобы задействовать это дополнительное поле, следует указать функции mciSendCommand флаг MCI_WAVE_OPEN_BUFFER .

MCI_CLOSE

Эта команда закрывает устройство. Ее необходимо выдавать после завершения работы с устройством.

Для команды MCI_CLOSE используется блок параметров в виде структуры MCI_GENERIC_PARMS , описанной в файле mmsystem.h:

typedef struct tagMCI_GENERIC_PARMS {
    DWORD   dwCallback;
} MCI_GENERIC_PARMS;
typedef MCI_GENERIC_PARMS FAR *LPMCI_GENERIC_PARMS;

Эта упрощенная структура предназначена для тех случаев, когда команде не требуются дополнительные параметры. Поле dwCallback используется также, как и в команде MCI_OPEN.

В следующем фрагменте кода закрывается устройство с идентификатором, записанным в поле wDeviceID структуры mciOpen:

MCI_GENERIC_PARMS mcigen;
DWORD dwrc;
mcigen.dwCallback = 0;
dwrc = mciSendCommand(mciOpen.wDeviceID, MCI_CLOSE, MCI_WAIT,
  (DWORD)(LPMCI_GENERIC_PARMS)&mcigen);

MCI_PLAY

Команда MCI_PLAY , как это видно из ее названия, предназначена для проигрывания файлов. Для этой команды в файле mmsystem.h определена структура блока параметров MCI_PLAY_PARMS :

typedef struct tagMCI_PLAY_PARMS {
    DWORD   dwCallback;
    DWORD   dwFrom;
    DWORD   dwTo;
} MCI_PLAY_PARMS;
typedef MCI_PLAY_PARMS FAR *LPMCI_PLAY_PARMS;

В структуре параметров можно указать начальную и конечную позиции для проигрывания. Начальная позиция задается в поле dwFrom, конечная - в поле dwTo. Перед использованием начальной позиции следует установить формат времени при помощи команды MCI_SET_TIME_FORMAT, которую мы рассмотрим позже. Формат времени определяет единицу измерения для позиции, например, миллисекунды, байты, выборки сигнала или кадры.

Для структуры MCI_PLAY_PARMS можно указывать следующие флаги:

Флаг Описание
MCI_NOTIFY Если установлен этот флаг, после завершения команды функции окна, адрес которой передан через поле dwCallback, будет послано сообщение MM_MCINOTIFY
MCI_WAIT Функция mciSendCommand вернет управление только после завершения процесса проигрывания
MCI_FROM Поле dwFrom содержит начальную позицию для проигрывания
MCI_TO Поле dwTo содержит конечную позицию для проигрывания

В приведенном ниже фрагменте запускается проигрывание с текущей позиции:

MCI_PLAY_PARMS mciPlayParms;
DWORD dwrc;
mciPlayParms.dwCallback = (DWORD)hwnd;
dwrc=mciSendCommand(wDeviceID, MCI_PLAY, MCI_NOTIFY,
  (DWORD)(LPVOID)&mciPlayParms);

Для изменения текущей позиции можно воспользоваться командой MCI_SEEK.

При завершении проигрывания окно с идентификатором hwnd получит сообщение MM_MCINOTIFY.

MCI_RECORD

Команда MCI_RECORD позволяет выполнить запись в существующий или новый файл. Если при открытии устройства вы указали имя файла, будет выполняться запись в существующий файл. Для записи в новый файл нужно использовать имя нулевой длины. Результат записи в этом случае можно сохранить в файле при помощи команды MCI_SAVE.

Приведем формат блока параметров для команды MCI_RECORD:

typedef struct tagMCI_RECORD_PARMS {
    DWORD   dwCallback;
    DWORD   dwFrom;
    DWORD   dwTo;
} MCI_RECORD_PARMS;
typedef MCI_RECORD_PARMS FAR *LPMCI_RECORD_PARMS;

Параметры dwFrom и dwTo задают, соответственно, начальную и конечную позицию для записи.

Для структуры MCI_RECORD_PARMS можно указывать следующие флаги:

Флаг Описание
MCI_NOTIFY Если установлен этот флаг, после завершения команды функции окна, адрес которой передан через поле dwCallback, будет послано сообщение MM_MCINOTIFY
MCI_WAIT Функция mciSendCommand вернет управление только после завершения процесса записи
MCI_RECORD_INSERT Необходимо вставить новую запись в уже существующие данные
MCI_RECORD_OWERWRITE Новая запись должна заместить существующие данные
MCI_FROM Поле dwFrom содержит начальную позицию для записи
MCI_TO Поле dwTo содержит конечную позицию для записи

Если при выдаче команды MCI_RECORD вы не указали конечную позицию записи, запись будет продолжаться до тех пор, пока приложение не выдаст команду MCI_STOP или пока не будет израсходовано все свободное место на диске.

В приведенном ниже фрагменте кода запускается запись, которая будет продолжаться до достижения позиции dwMSec (запись может быть также остановлена раньше при помощи команды MCI_STOP):

MCI_RECORD_PARMS mciRecordParms;
mciRecordParms.dwTo       = dwMSec;
mciRecordParms.dwCallback = (DWORD)hwnd;
dwrc=mciSendCommand(wInDeviceID,
   MCI_RECORD, MCI_NOTIFY | MCI_TO,
  (DWORD)(LPVOID)&mciRecordParms);

После завершения процесса записи окно с идентификатором hwnd получит сообщение MM_MCINOTIFY.

MCI_SAVE

Команда MCI_SAVE позволяет сохранить результат записи в файле. Для нее используется блок параметров MCI_SAVE_PARMS :

typedef struct tagMCI_SAVE_PARMS {
    DWORD   dwCallback;
    LPCSTR  lpfilename;
} MCI_SAVE_PARMS;
typedef MCI_SAVE_PARMS FAR * LPMCI_SAVE_PARMS;

Поле lpfilename должно содержать указатель на путь к файлу.

Флаги для этой команды:

Флаг Описание
MCI_NOTIFY Если установлен этот флаг, после завершения команды функции окна, адрес которой передан через поле dwCallback, будет послано сообщение MM_MCINOTIFY
MCI_WAIT Функция mciSendCommand вернет управление только после завершения процесса сохранения
MCI_SAVE_FILE Поле lpfilename содержит путь к файлу, в котором необходимо сохранить результат записи

В следующем фрагменте кода выполняется сохранение записанных данных в файле с именем recorded.wav, который будет создан в текущем каталоге:

MCI_SAVE_PARMS mciSave;
mciSave.lpfilename = "recorded.wav";
dwrc=mciSendCommand(wInDeviceID, MCI_SAVE,
   MCI_SAVE_FILE | MCI_WAIT, (DWORD)(LPVOID)&mciSave);

MCI_PAUSE

Команда MCI_PAUSE приостанавливает выполнение операции записи или воспроизведения. Она используется совместно с блоком параметров MCI_GENERIC_PARMS , который был рассмотрен выше.

Флаги для этой команды:

Флаг Описание
MCI_NOTIFY Если установлен этот флаг, после завершения команды функции окна, адрес которой передан через поле dwCallback, будет послано сообщение MM_MCINOTIFY
MCI_WAIT Функция mciSendCommand вернет управление только после завершения процесса

Пример использования команды MCI_PAUSE:

MCI_GENERIC_PARMS mcigen;
dwrc = mciSendCommand(wDeviceID, MCI_PAUSE, MCI_WAIT,
  (DWORD)(LPMCI_GENERIC_PARMS)&mcigen);

MCI_RESUME

Эта команда отменяет действие команды MCI_PAUSE, при этом приостановленная операция будет продолжена. Для команды MCI_RESUME используется блок параметров MCI_GENERIC_PARMS .

Флаги для этой команды:

Флаг Описание
MCI_NOTIFY Если установлен этот флаг, после завершения команды функции окна, адрес которой передан через поле dwCallback, будет послано сообщение MM_MCINOTIFY
MCI_WAIT Функция mciSendCommand вернет управление только после завершения процесса

Пример использования команды MCI_RESUME:

MCI_GENERIC_PARMS mcigen;
dwrc = mciSendCommand(wDeviceID, MCI_RESUME, MCI_WAIT,
  (DWORD)(LPMCI_GENERIC_PARMS)&mcigen);

MCI_STOP

Команда MCI_STOP останавливает выполнение операции записи или воспроизведения, после чего освобождает все буфера, которые были использованы для операции. Эта команда использует блок параметров MCI_GENERIC_PARMS .

Флаги для этой команды:

Флаг Описание
MCI_NOTIFY Если установлен этот флаг, после завершения команды функции окна, адрес которой передан через поле dwCallback, будет послано сообщение MM_MCINOTIFY
MCI_WAIT Функция mciSendCommand вернет управление только после завершения процесса

Пример использования команды MCI_STOP:

MCI_GENERIC_PARMS mcigen;
dwrc = mciSendCommand(wDeviceID, MCI_STOP, MCI_WAIT,
  (DWORD)(LPMCI_GENERIC_PARMS)&mcigen);

MCI_SEEK

Команда MCI_SEEK позволяет выполнять позиционирование в пределах файла. Для этой команды используется блок параметров MCI_SEEK_PARMS :

typedef struct tagMCI_SEEK_PARMS {
    DWORD   dwCallback;
    DWORD   dwTo;
} MCI_SEEK_PARMS;
typedef MCI_SEEK_PARMS FAR *LPMCI_SEEK_PARMS;

Поле dwTo задает новую позицию в единицах, установленных командой MCI_SET_TIME_FORMAT.

Флаги для этой команды:

Флаг Описание
MCI_NOTIFY Если установлен этот флаг, после завершения команды функции окна, адрес которой передан через поле dwCallback, будет послано сообщение MM_MCINOTIFY
MCI_WAIT Функция mciSendCommand вернет управление только после завершения процесса позиционирования
MCI_SEEK_TO_START Позиционирование на начало
MCI_SEEK_TO_END Позиционирование в конец
MCI_SEEK_TO Позиция определяется содержимым поля dwTo

MCI_BREAK

С помощью команды MCI_BREAK указывается виртуальный код клавиши, предназначенной для прерывания выполнения операции. Для этой команды необходимо использовать следующую структуру блока параметров:

typedef struct tagMCI_BREAK_PARMS {
    DWORD   dwCallback;
    int     nVirtKey;
    UINT    wReserved0;
    HWND    hwndBreak;
    UINT    wReserved1;
} MCI_BREAK_PARMS;
typedef MCI_BREAK_PARMS  FAR * LPMCI_BREAK_PARMS;

Поле nVirtKey определяет виртуальный код клавиши прерывания.

В поле hwndBreak можно указать идентификатор окна, которое должно быть текущим для обеспечения возможности прерывания с помощью заданной клавиши.

Поля wReserved0 и wReserved1 зарезервированы.

Для команды MCI_BREAK можно указывать следующие флаги:

Флаг Описание
MCI_NOTIFY Если установлен этот флаг, после завершения команды функции окна, адрес которой передан через поле dwCallback, будет послано сообщение MM_MCINOTIFY
MCI_WAIT Функция mciSendCommand вернет управление только после завершения процесса позиционирования
MCI_BREAK_KEY Поле nVirtKey содержит виртуальный код клавиши прерывания команды
MCI_BREAK_HWND Поле hwndBreak содержит идентификатор окна, которое должно быть текущим для обеспечения возможности прерывания команды
MCI_BREAK_OFF Используется для отключения прерывания

По умолчанию для прерывания используется комбинация клавиш <Control+Break>.

MCI_CUE

Команда MCI_CUE используется для подготовки устройства к записи или воспроизведению, после которой эти операции выполняются с минимальной задержкой. Для нее используется блок параметров в формате структуры MCI_GENERIC_PARMS и следующий набор флагов:

Флаг Описание
MCI_NOTIFY Если установлен этот флаг, после завершения команды функции окна, адрес которой передан через поле dwCallback, будет послано сообщение MM_MCINOTIFY
MCI_WAIT Функция mciSendCommand вернет управление только после завершения процесса

MCI_GETDEVCAPS

С помощью команды MCI_GETDEVCAPS можно определить возможности устройства мультимедиа. Для нее используется блок параметров в формате структуры MCI_GETDEVCAPS_PARMS , определенной в файле mmsystem.h следующим образом:

typedef struct tagMCI_GETDEVCAPS_PARMS {
    DWORD   dwCallback;
    DWORD   dwReturn;
    DWORD   dwItem;
} MCI_GETDEVCAPS_PARMS;
typedef MCI_GETDEVCAPS_PARMS FAR * LPMCI_GETDEVCAPS_PARMS;

В поле dwReturn после возврата из функции mciSendCommand будет записано значение требуемого параметра. Код нужного параметра следует записать в поле dwItem перед вызовом функции mciSendCommand.

Приведем возможные значения параметра dwItem:

Значение параметра dwItem Описание
MCI_GETDEVCAPS_CAN_EJECT Если устройство может выталкивать носитель данных (например, компакт-диск), после возврата из функции mciSendCommand в поле dwReturn будет ненулевое значение TRUE
MCI_GETDEVCAPS_CAN_PLAY Устройство может проигрывать
MCI_GETDEVCAPS_CAN_RECORD Устройство может записывать
MCI_GETDEVCAPS_CAN_SAVE Устройство может сохранять записанные данные в файле
MCI_GETDEVCAPS_COMPOUND_DEVICE Устройство может работать с файлами
MCI_GETDEVCAPS_DEVICE_TYPE Требуется определить тип устройства. Для звукового адаптера возвращается константа MCI_DEVTYPE_WAVEFORM_AUDIO
MCI_GETDEVCAPS_HAS_AUDIO Устройство имеет звуковой выход
MCI_GETDEVCAPS_HAS_VIDEO Устройство имеет видеовыход
MCI_GETDEVCAPS_USES_FILES При открытии устройства требуется указывать имя файла
MCI_WAVE_GETDEVCAPS_INPUT Количество звуковых входов
MCI_WAVE_GETDEVCAPS_OUTPUT Количество звуковых выходов (каналов)

Для команды MCI_GETDEVCAPS можно использовать следующий набор флагов:

Флаг Описание
MCI_NOTIFY Если установлен этот флаг, после завершения команды функции окна, адрес которой передан через поле dwCallback, будет послано сообщение MM_MCINOTIFY
MCI_WAIT Функция mciSendCommand вернет управление только после завершения процесса
MCI_GETDEVCAPS_ITEM Поле dwItem содержит константу, соответствующую определяемому параметру устройства

MCI_INFO

С помощью этой команды можно получить информацию об устройстве в виде текстовой строки, такую как описание аппаратуры, имя файла, связанного с устройством.

Используется блок параметров в формате структуры MCI_INFO_PARMS :

typedef struct tagMCI_INFO_PARMS {
    DWORD   dwCallback;
    LPSTR   lpstrReturn;
    DWORD   dwRetSize;
} MCI_INFO_PARMS;
typedef MCI_INFO_PARMS FAR * LPMCI_INFO_PARMS;

Поле lpstrReturn должно содержать дальний указатель на буфер, в который будет записана строка информации. Размер этого буфера следует передать через поле dwRetSize.

Приведем набор флагов для команды MCI_INFO:

Флаг Описание
MCI_NOTIFY Если установлен этот флаг, после завершения команды функции окна, адрес которой передан через поле dwCallback, будет послано сообщение MM_MCINOTIFY
MCI_WAIT Функция mciSendCommand вернет управление только после завершения процесса
MCI_INFO_PRODUCT Требуется получить описание аппаратуры устройства
MCI_INFO_FILE Требуется получить имя текущего файла, связанного с устройством
MCI_WAWE_INPUT Имя текущего устройства ввода
MCI_WAVE_OUTPUT Имя текущего устройства вывода

MCI_SYSINFO

С помощью этой команды можно получить системную информацию об устройстве в виде текстовой строки. Используется блок параметров в формате структуры MCI_SYSINFO_PARMS :

typedef struct tagMCI_SYSINFO_PARMS {
    DWORD   dwCallback;
    LPSTR   lpstrReturn;
    DWORD   dwRetSize;
    DWORD   dwNumber;
    UINT    wDeviceType;
    UINT    wReserved0;
} MCI_SYSINFO_PARMS;
typedef MCI_SYSINFO_PARMS FAR * LPMCI_SYSINFO_PARMS;

Поле lpstrReturn должно содержать дальний указатель на буфер, в который будет записана строка системной информации. Размер этого буфера следует передать через поле dwRetSize.

Поле dwNumber определяет положение устройства в таблице устройств MCI или в списке открытых устройств, если установлен флаг MCI_SYSINFO_OPEN. Поле wDeviceType определяет тип устройства. Поле wReserved0 зарезервировано.

Приведем набор флагов для команды MCI_INFO:

Флаг Описание
MCI_SYSINFO_INSTALLNAME Требуется получить имя, которое было использовано в файле win.ini при установке драйвера устройства
MCI_SYSINFO_NAME Требуется получить имя устройства, соответствующего устройству с номером, заданным в поле dwNumber
MCI_SYSINFO_OPEN Определить имя открытого устройства или количество открытых устройств
MCI_SYSINFO_QUANTITY Определить количество устройств заданного типа, перечисленных в разделе [mci] файла system.ini. Если дополнительно установлен флаг MCI_SYSINFO_OPEN, возвращается количество открытых устройств

MCI_STATUS

Команда MCI_STATUS используется для определения текущего состояния устройства.

Формат соответствующего блока параметров описывается структурой MCI_STATUS_PARMS :

typedef struct tagMCI_STATUS_PARMS {
    DWORD   dwCallback;
    DWORD   dwReturn;
    DWORD   dwItem;
    DWORD   dwTrack;
} MCI_STATUS_PARMS;
typedef MCI_STATUS_PARMS FAR * LPMCI_STATUS_PARMS;

Через поле dwReturn передается возвращаемая информация. Вид запрашиваемой информации определяется содержимым поля dwItem. Для устройств, которые работают с дорожками (например, устройство чтения компакт-дисков), в поле dwTrack можно указать размер или номер дорожки.

Приведем возможные значения параметра dwItem (для звукового адаптера):

Значение параметра dwItem Описание получаемой информации
MCI_STATUS_CURRENT_TRACK Номер текущей дорожки
MCI_STATUS_LENGTH Общий размер (длина) фрагмента
MCI_STATUS_MODE Текущий режим устройства. Может иметь следующие значения:MCI_MODE_NOT_READY не готово;MCI_MODE_PAUSE пауза;MCI_MODE_PLAY проигрывание;MCI_MODE_STOP останов;MCI_MODE_OPEN открытие;MCI_MODE_RECORD запись;MCI_MODE_SEEK позиционирование
MCI_STATUS_NUMBER_OF_TRACKS Общее количество дорожек, которые можно проиграть
MCI_STATUS_POSITION Текущая позиция
MCI_STATUS_READY Если устройство готово, возвращается значение TRUE, в противном случае - FALSE
MCI_STATUS_TIME_FORMAT Текущий формат времени. Может иметь следующие значения:MCI_FORMAT_BYTES MCI_FORMAT_FRAMES MCI_FORMAT_HMS MCI_FORMAT_MILLISECONDS MCI_FORMAT_MSF MCI_FORMAT_SAMPLES MCI_FORMAT_TMSF
MCI_STATUS_START Начальная позиция
MCI_STATUS_TRACK В поле dwTrack записывается либо начальная позиция заданной дорожки (если дополнительно используется MCI_STATUS_POSITION), либо размер дорожки (если дополнительно используется MCI_STATUS_LENGTH)
MCI_STATUS_MEDIA_PRESENT Возвращается TRUE, если носитель данных вставлен в устройство
MCI_WAVE_INPUT Устройство, используемое для записи
MCI_WAVE_OUTPUT Устройство, используемое для воспроизведения
MCI_WAVE_STATUS_AVGBYTESPERSEC Скорость потока данных при записи и воспроизведении, байты в секунду
MCI_WAVE_STATUS_BITSPERSAMPLE Количество бит, используемых для представления одной выборки сигнала
MCI_WAVE_STATUS_BLOCKALIGN Текущее выравнивание блока
MCI_WAVE_STATUS_CHANNELS Количество каналов
MCI_WAVE_FORMATTAG Тег формата, используемого для записи, воспроизведения или сохранения данных в файле
MCI_WAVE_STATUS_LEVEL Текущий уровень записи или воспроизведения, используется 8- или 16-битовое значение в зависимости от формата данных. Младшее слово содержит уровень для монофонической записи или уровень правого канала для стереофонической записи. Уровень левого канала передается через старшее слово
MCI_WAVE_STATUS_SAMPLESPERSEC Скорость выборки сигнала (частота дискретизации)

Приведем также список флагов для команды MCI_STATUS:

Флаг Описание
MCI_NOTIFY Если установлен этот флаг, после завершения команды функции окна, адрес которой передан через поле dwCallback, будет послано сообщение MM_MCINOTIFY
MCI_WAIT Функция mciSendCommand вернет управление только после завершения процесса
MCI_STATUS_ITEM Поле wItem содержит код получаемой информации

В приведенном ниже фрагменте кода определяется длительность звучания:

mciStatus.dwItem = MCI_STATUS_LENGTH;
dwrc = mciSendCommand(mciOpen.wDeviceID, MCI_STATUS,
  MCI_STATUS_ITEM | MCI_WAIT, (DWORD)(LPVOID)&mciStatus);

MCI_SET

Команда MCI_SET предназначена для установки режима работы устройства. Вместе с этой командой используется блок параметров в формате структуры MCI_SET_PARMS :

typedef struct tagMCI_SET_PARMS {
    DWORD   dwCallback;
    DWORD   dwTimeFormat;
    DWORD   dwAudio;
} MCI_SET_PARMS;
typedef MCI_SET_PARMS FAR *LPMCI_SET_PARMS;

Поле dwTimeFormat определяет формат времени для устройства, поле dwAudio определяет выходной канал.

Для звуковых устройств можно использовать другую структуру:

typedef struct tagMCI_WAVE_SET_PARMS {
    DWORD   dwCallback;
    DWORD   dwTimeFormat;
    DWORD   dwAudio;
    UINT    wInput;
    UINT    wReserved0;
    UINT    wOutput;
    UINT    wReserved1;
    UINT    wFormatTag;
    UINT    wReserved2;
    UINT    nChannels;
    UINT    wReserved3;
    DWORD   nSamplesPerSec;
    DWORD   nAvgBytesPerSec;
    UINT    nBlockAlign;
    UINT    wReserved4;
    UINT    wBitsPerSample;
    UINT    wReserved5;
} MCI_WAVE_SET_PARMS;
typedef MCI_WAVE_SET_PARMS  FAR * LPMCI_WAVE_SET_PARMS;

В этой структуре поле wInput определяет номер канала для записи, wOutput - номер канала для воспроизведения. Поле wFormatTag используется для определения формата звуковых данных. С помощью поля nChannels можно указать количество каналов - 1 (моно) или 2 (стерео). Поле nSamplesPerSec предназначено для задания частоты дискретизации (количество выборок сигнала в секунду). Поле nAvgBytesPerSec содержит скорость передачи данных (байты в секунду). С помощью поля nBlockAlign можно задать выравнивание блока, а с помощью поля wBitsPerSample - количество бит, используемых для представления одной выборки (8 или 16). Остальные поля зарезервированы.

Приведем список флагов, которые используются вместе с командой MCI_SET:

Флаг Описание
MCI_NOTIFY Если установлен этот флаг, после завершения команды функции окна, адрес которой передан через поле dwCallback, будет послано сообщение MM_MCINOTIFY
MCI_WAIT Функция mciSendCommand вернет управление только после завершения процесса
MCI_SET_AUDIO Включение или выключение каналов, используется вместе с флагами MCI_SET_ON и MCI_SET_OFF. Поле dwAudio содержит номера канала. Дополнительно можно указать следующие константы:MCI_SET_AUDIO_ALL все каналыMCI_SET_AUDIO_LEFT левый каналMCI_SET_AUDIO_RIGHT правый канал
MCI_SET_DOOR_CLOSED По этой команде устройство защелкивает носитель данных (например, компакт-диск)
MCI_SET_DOOR_OPEN Освобождение носителя данных
MCI_SET_VIDEO Включение или выключение видеосигнала, используется вместе с флагами MCI_SET_ON и MCI_SET_OFF
MCI_SET_ON Включение заданного канала
MCI_SET_OFF Выключение заданного канала
MCI_WAVE_INPUT Установка канала для записи. Номер канала должен быть указан в поле wInput структуры MCI_WAVE_SET_PARAMS
MCI_WAVE_OUTPUT Установка канала для воспроизведения. Номер канала должен быть указан в поле wInput структуры MCI_WAVE_SET_PARAMS
MCI_WAVE_SET_ANYINPUT При записи следует использовать любое устройство, совместимое с заданным форматом данных
MCI_WAVE_SET_ANYOUTPUT При воспроизведении следует использовать любое устройство, совместимое с заданным форматом данных
MCI_WAVE_SET_AVGBYTESPERSEC Установить скорость потока данных при записи и воспроизведении из поля nAvgBytesPerSec
MCI_WAVE_SET_BITSPERSAMPLE Установить количество бит, используемых для представления одной выборки сигнала из поля wBitsPerSample
MCI_WAVE_SET_BLOCKALIGN Установить выравнивание блока из поля nBlockAlign
MCI_WAVE_SET_CHANNELS Поле nChannels содержит номер канала
MCI_WAVE_SET_FORMATTAG Установить формат из поля wFormatTag
MCI_WAVE_SET_SAMPLESPERSEC Установить частоту выборки из поля nSamplesPerSec
MCI_WAVE_SET_TIME_FORMAT Установить формат времени. Используется вместе со следующими константами:MCI_FORMAT_BYTES в байтах;MCI_FORMAT_MILLISECONDS в миллисекундах;MCI_FORMAT_SAMPLES в выборках сигнала

MCI_COPY

Команда MCI_COPY предназначена для копирования данных в универсальный буфер обмена Clipboard. Для нее используется блок параметров в формате структуры MCI_GENERIC_PARMS, флаги MCI_NOTIFY и MCI_WAIT.

MCI_PASTE

Команда MCI_PASTE вставляет данные из Clipboard в текущий буфер устройства. Для нее, как и для команды MCI_COPY, используется блок параметров в формате структуры MCI_GENERIC_PARMS, флаги MCI_NOTIFY и MCI_WAIT.

MCI_CUT

Команда MCI_CUT удаляет данные из текущего буфера устройства и копирует их в универсальный буфер обмена Clipboard. Для нее используется блок параметров в формате структуры MCI_GENERIC_PARMS, флаги MCI_NOTIFY и MCI_WAIT.

MCI_DELETE

Команда MCI_DELETE удаляет данные из текущего буфера устройства без копирования их в Clipboard. Для нее используется блок параметров в формате структуры MCI_GENERIC_PARMS.

Вместе с этой командой при работе со звуковым адаптером можно использовать структуру MCI_WAVE_DELETE_PARMS :

typedef struct tagMCI_WAVE_DELETE_PARMS {
    DWORD   dwCallback;
    DWORD   dwFrom;
    DWORD   dwTo;
} MCI_WAVE_DELETE_PARMS;
typedef MCI_WAVE_DELETE_PARMS FAR *LPMCI_WAVE_DELETE_PARMS;

Поле dwFrom используется для передачи команде начальной позиции для удаления, поле dwTo - для передачи конечной позиции удаления.

Вместе с командой MCI_DELETE используются перечисленные ниже флаги.

Флаг Описание
MCI_NOTIFY Если установлен этот флаг, после завершения команды функции окна, адрес которой передан через поле dwCallback, будет послано сообщение MM_MCINOTIFY
MCI_WAIT Функция mciSendCommand вернет управление только после завершения процесса
MCI_FROM Поле dwFrom содержит начальную позицию для удаления
MCI_TO Поле dwTo содержит конечную позицию для удаления

MCI_LOAD

Команда MCI_LOAD предназначена для загрузки файла. Она использует блок параметров в формате структуры MCI_LOAD_PARMS :

typedef struct tagMCI_LOAD_PARMS {
    DWORD   dwCallback;
    LPCSTR  lpfilename;
} MCI_LOAD_PARMS;
typedef MCI_LOAD_PARMS FAR * LPMCI_LOAD_PARMS;

Через поле lpfilename передается указатель на буфер, содержащий путь к файлу.

Вместе с командой MCI_LOAD можно использовать следующие флаги:

Флаг Описание
MCI_NOTIFY Если установлен этот флаг, после завершения команды функции окна, адрес которой передан через поле dwCallback, будет послано сообщение MM_MCINOTIFY
MCI_WAIT Функция mciSendCommand вернет управление только после завершения процесса
MCI_LOAD_FILE Поле lpfilename содержит указатель на строку пути к файлу

Приложение MCIWAVER

В качестве примера использования интерфейса сообщений MCI приведем исходные тексты несложного приложения MCIWAVER, с помощью которого можно записывать и воспроизводить wav-файлы (рис. 2.2).

Рис. 2.2. Главное окно приложения MCIWAVER

Если выбрать из главного меню приложения строку "Record!", включится запись. Вы сможете записать звуковой фрагмент длительностью до 60 секунд (максимальное время записи определяется константой MAXRECORDTIME, вы можете изменить значение этой константы в исходном тексте приложения). Для прерывания процесса записи в любой момент времени можно выбрать из меню строки "Stop!" или "Pause!". Результат записи всегда сохраняется в файле с именем recorded.wav, который создается в текущем каталоге.

С помощью строки "Open..." меню "File" можно выбрать wav-файл для воспроизведения. Путь к выбранному файлу отобразится в заголовке окна. Для прослушивания загруженного wav-файла воспользуйтесь строкой "Play!". Прослушивание можно прекратить (строка "Stop!") или временно приостановить (строка "Pause!"). Для продолжения прослушивания после временного останова выберите строку "Resume!".

Полоса просмотра служит для отображения текущей позиции при записи и воспроизведении. Над полосой просмотра выводится текущий режим работы приложения.

Основной файл приложения MCIWAWER приведен в листинге 2.7.


Листинг 2.7. Файл mciwaver\mciwaver.cpp


// ------------------------------------------------
// Приложение MCIWAVE
// Проигрывание и запись wav-файлов
// с помощью интерфейса сообщений MCI
// ------------------------------------------------

#define STRICT
#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <mem.h>
#pragma hdrstop

#include "mciwave.hpp"
#include "mciwavio.hpp"

// Идентификатор таймера
#define BEEP_TIMER 1

// Идентификатор полосы просмотра
#define ID_SCROLL 10

// Длина полосы просмотра
#define SCROLL_SIZE 400

// Длительность записи в миллисекундах
#define MAXRECORDTIME 60000L

// Прототипы функций
BOOL    InitApp(HINSTANCE);
LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM);

// Глобальные переменные
int      nMode = MODE_STOP;
MMTIME   mmtimeIn, mmtimeOut;
BOOL     fFileLoaded = FALSE;
int      nPosition;
HWND     hScroll;
UINT     wOutDeviceID;
UINT     wInDeviceID;
BYTE     szFileName[128];
DWORD    dwFileSize;

char const szClassName[]   = "MCIWaveClass";
char const szWindowTitle[] = "MCIWaver";
HINSTANCE  hInst;

// =====================================
// Функция WinMain
// =====================================
#pragma argsused

int PASCAL
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
        LPSTR lpszCmdLine, int nCmdShow)
{
  MSG  msg;   // структура для работы с сообщениями
  HWND hwnd;  // идентификатор главного окна приложения

  if(hPrevInstance)
    return FALSE;

  if(!InitApp(hInstance))
    return FALSE;

  hInst = hInstance;

  hwnd = CreateWindow(
    szClassName,         // имя класса окна
    szWindowTitle,       // заголовок окна
    WS_OVERLAPPEDWINDOW, // стиль окна
    CW_USEDEFAULT,       // размеры и расположение окна
    CW_USEDEFAULT,       
    450, 120, 0, 0, hInstance, NULL);
                       
  if(!hwnd)
    return FALSE;

  ShowWindow(hwnd, nCmdShow);
  UpdateWindow(hwnd);

  while(GetMessage(&msg, 0, 0, 0))
  {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
  return msg.wParam;
}

// =====================================
// Функция InitApp
// Выполняет регистрацию класса окна
// =====================================

BOOL
InitApp(HINSTANCE hInstance)
{
  ATOM aWndClass; // атом для кода возврата
  WNDCLASS wc;    // структура для регистрации

  memset(&wc, 0, sizeof(wc));
  wc.lpszMenuName  = "APP_MENU";
  wc.style         = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc   = (WNDPROC) WndProc;
  wc.cbClsExtra    = 0;
  wc.cbWndExtra    = 0;
  wc.hInstance     = hInstance;
  wc.hIcon         = LoadIcon(hInstance, "APPICON");
  wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
  wc.lpszClassName = (LPSTR)szClassName;

  aWndClass = RegisterClass(&wc);
  return (aWndClass != 0);
}

// =====================================
// Функция WndProc
// =====================================

LRESULT CALLBACK _export
WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  HDC hdc;
  PAINTSTRUCT ps;
  int rc;

  switch (msg)
  {
// ------------------------------------------------------------
// WM_CREATE
// Создание главного окна приложения
// ------------------------------------------------------------
    case WM_CREATE:
    {
       nMode        = MODE_STOP;
       fFileLoaded  = FALSE;
       wOutDeviceID = 0;
       wInDeviceID  = 0;

       // Создаем таймер
       SetTimer(hwnd, BEEP_TIMER, 100, NULL);

       // Создаем полосу просмотра
       hScroll = CreateWindow("scrollbar", NULL,
         WS_CHILD | WS_VISIBLE | SBS_HORZ,
         10, 40, SCROLL_SIZE, 15, hwnd,
         (HMENU) ID_SCROLL, hInst, NULL);

       // Устанавливаем текущую позицию
       nPosition = 0;

       // Устанавливаем минимальное и максимальное
       // значения для полосы просмотра
       SetScrollRange(hScroll, SB_CTL, 1, SCROLL_SIZE, TRUE);

       // Устанавливаем ползунок
       SetScrollPos(hScroll, SB_CTL, nPosition, TRUE);
       return 0;
    }

// ------------------------------------------------------------
// WM_PAINT
// Рисование в окне
// ------------------------------------------------------------
    case WM_PAINT:
    {
      // Получаем контекст отображения для
      // рисования во внутренней области окна 
      hdc = BeginPaint(hwnd, &ps);

      // Отображаем текущий режим работы
      if(nMode == MODE_STOP)
        TextOut(hdc, 10, 10, "Остановлено", 11);
      else if(nMode == MODE_RECORDING)
        TextOut(hdc, 10, 10, "Идет запись...", 14);
      else if(nMode == MODE_PLAYING)
        TextOut(hdc, 10, 10, "Идет проигрывание...", 20);
      else if(nMode == MODE_RECORDINGPAUSED)
        TextOut(hdc, 10, 10, "Запись остановлена", 18);
      else if(nMode == MODE_PLAYINGPAUSED)
        TextOut(hdc, 10, 10, "Проигрывание остановлено", 24);
      else
        TextOut(hdc, 10, 10, "Неправильный режим!", 19);

      // Освобождаем контекст отображения
      EndPaint(hwnd, &ps);
      return 0;
    }

// ------------------------------------------------------------
// WM_COMMAND
// Обработка сообщений от меню
// ------------------------------------------------------------
    case WM_COMMAND:
    {
      switch (wParam)
      {
        // -------------------------------------------------
        // Строка "About" меню "Help"
        // -------------------------------------------------
        case CM_HELPABOUT:
        {
          MessageBox(hwnd,
            "MCIWaver, v.1.0\n"
            "(C) Frolov A.V., 1994",
            "About MCIWaver", MB_OK | MB_ICONINFORMATION);
          return 0;
        }

        // -------------------------------------------------
        // Строка "Open" меню "File"
        // -------------------------------------------------
        case CM_FILEOPEN:
        {
          char szTitle[256];

          // Загружаем новый файл
          if(!mciwioSelectFile(szFileName))
            return 0;

          // Отображаем в заголовке окна путь к файлу
          lstrcpy(szTitle, szWindowTitle);
          lstrcat(szTitle, " - ");
          lstrcat(szTitle, szFileName);
          SetWindowText(hwnd, szTitle);

          // Если было запущено воспроизведение,
          // останавливаем его и закрываем устройство вывода
          if(wOutDeviceID)
          {
            mciwioStop(wOutDeviceID);
            mciwioClose(wOutDeviceID);
            wOutDeviceID = 0;

            // Новый режим
            nMode = MODE_STOP;
          }

          // Устанавливаем движок в начало полосы просмотра
          nPosition = 0;
          SetScrollPos(hScroll, SB_CTL, nPosition, TRUE);

          // Устанавливаем флаг загрузки файла
          fFileLoaded = TRUE;
          return 0;
        }

        // -------------------------------------------------
        // Строка "Play!"
        // Проигрывание загруженного wav-файла
        // -------------------------------------------------
        case CM_CTLPLAY:
        {
          // Если файл загружен и не проигрывается,
          // запускаем проигрывание файла
          if((fFileLoaded == TRUE) && (nMode == MODE_STOP))
          {
            // Новый режим
            nMode = MODE_PLAYING;

            // Перерисовываем окно для отображения строки,
            // соответствующей новому режиму
            InvalidateRect(hwnd, NULL, TRUE);

            // Открываем устройство
            wOutDeviceID = mciwioOpen((LPSTR)szFileName);

            // Проигрываем файл
            mciwioPlay(hwnd, wOutDeviceID);
          }
          return 0;
        }

        // -------------------------------------------------
        // Строка "Record!"
        // Запись wav-файла
        // -------------------------------------------------
        case CM_CTLRECORD:
        {
          // Запись возможна только из состояния останова
          if(nMode == MODE_STOP)
          {
            nMode = MODE_RECORDING;
            InvalidateRect(hwnd, NULL, TRUE);

            // Запись файла
            wInDeviceID = mciwioRecord(hwnd, MAXRECORDTIME);
          }
          return 0;
        }

        // -------------------------------------------------
        // Строка "Stop!"
        // Останов проигрывания или записи wav-файла
        // -------------------------------------------------
        case CM_CTLSTOP:
        {
          if(nMode == MODE_RECORDING 
             || nMode == MODE_RECORDINGPAUSED)
          {
            // Останавливаем запись
            mciwioStop(wInDeviceID);
          }

          else if(nMode == MODE_PLAYING 
             || nMode == MODE_PLAYINGPAUSED)
          {
            // Останавливаем проигрывание
            mciwioStop(wOutDeviceID);
          }

          // Устанавливаем движок в начало полосы просмотра
          nPosition = 0;
          SetScrollPos(hScroll, SB_CTL, nPosition, TRUE);

          // Новый режим
          nMode = MODE_STOP;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }

        // -------------------------------------------------
        // Строка "Pause!"
        // Временный останов проигрывания или
        // полный останов записи wav-файла
        // -------------------------------------------------
        case CM_CTLPAUSE:
        {
          if(nMode == MODE_RECORDING)
          {
            // Останов записи
            mciwioStop(wInDeviceID);
          }

          else if(nMode == MODE_PLAYING)
          {
            // Временный останов проигрывания
            mciwioPause(wOutDeviceID);
            nMode = MODE_PLAYINGPAUSED;
          }

          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }

        // -------------------------------------------------
        // Строка "Resume!"
        // Продолжение проигрывания после останова
        // -------------------------------------------------
        case CM_CTLRESUME:
        {
          if(nMode == MODE_PLAYINGPAUSED)
          {
            // Продолжаем проигрывание
            mciwioResume(wOutDeviceID);
            nMode = MODE_PLAYING;
            InvalidateRect(hwnd, NULL, TRUE);
          }
          return 0;
        }

        // -------------------------------------------------
        // Строка "Exit" меню "File"
        // Завершение работы приложения
        // -------------------------------------------------
        case CM_FILEEXIT:
        {
          DestroyWindow(hwnd);
          return 0;
        }
        default:
          return 0;
      }
    }

// ------------------------------------------------------------
// MM_MCINOTIFY
// ------------------------------------------------------------
    case MM_MCINOTIFY:
    {
      // Если находились в режиме записи, сохраняем файл
      if(wInDeviceID)
      {
        MCI_SAVE_PARMS mciSave;
        MCI_GENERIC_PARMS mcigen;
        DWORD dwrc;

        // Имя файла, в котором будет сохранен звуковой фрагмент
        mciSave.lpfilename = "recorded.wav";

        dwrc=mciSendCommand(wInDeviceID, MCI_SAVE,
           MCI_SAVE_FILE | MCI_WAIT, (DWORD)(LPVOID)&mciSave);
        if(dwrc)
        {
          mciwioError(dwrc);
        }

        // Закрываем устройство записи
        dwrc = mciSendCommand(wInDeviceID, MCI_CLOSE, MCI_WAIT,
          (DWORD)(LPMCI_GENERIC_PARMS)&mcigen);
        if(dwrc)
        {
          mciwioError(dwrc);
        }
        wInDeviceID = 0;
      }

      // Если находились в режиме воспроизведения, останавливаем
      // и закрываем устройство вывода
      else if(wOutDeviceID)
      {
        mciwioStop(wOutDeviceID);
        mciwioClose(wOutDeviceID);
        wOutDeviceID=0;
      }

      nMode = MODE_STOP;
      InvalidateRect(hwnd, NULL, TRUE);
      return 0;
    }

// ------------------------------------------------------------
// WM_TIMER
// Сообщение от таймера
// ------------------------------------------------------------
    case WM_TIMER:
    {
      MCI_STATUS_PARMS mciStatus;
      DWORD dwPos;

      // Режим записи
      if(nMode == MODE_RECORDING)
      {
        // Определяем текущую позицию внутри  блока
        mciStatus.dwItem = MCI_STATUS_POSITION;
        mciSendCommand(wInDeviceID, MCI_STATUS,
          MCI_STATUS_ITEM, (DWORD)(LPVOID)&mciStatus);
        dwPos = mciStatus.dwReturn;

        // Вычисляем новое положение движка полосы просмотра
        nPosition = ((DWORD)SCROLL_SIZE * dwPos) / MAXRECORDTIME;

        // Ограничиваем пределы изменения текущей
        // позиции значениями от 1 до SCROLL_SIZE
        if(nPosition > SCROLL_SIZE) nPosition = SCROLL_SIZE;
        if(nPosition < 1) nPosition = 1;

        // Устанавливаем движок полосы просмотра
        // в соответствии с новым значением текущей позиции
        SetScrollPos(hScroll, SB_CTL, nPosition, TRUE);
      }

      // Режим воспроизведения
      else if(nMode == MODE_PLAYING)
      {
        // Определяем текущую позицию внутри блока
        mciStatus.dwItem = MCI_STATUS_POSITION;
        mciSendCommand(wOutDeviceID, MCI_STATUS,
          MCI_STATUS_ITEM, (DWORD)(LPVOID)&mciStatus);
        dwPos = mciStatus.dwReturn;

        // Вычисляем новое положение движка полосы просмотра
        nPosition = ((DWORD)SCROLL_SIZE * dwPos) / dwFileSize;

        // Ограничиваем пределы изменения текущей
        // позиции значениями от 1 до SCROLL_SIZE
        if(nPosition > SCROLL_SIZE) nPosition = SCROLL_SIZE;
        if(nPosition < 1) nPosition = 1;

        // Устанавливаем ползунок полосы просмотра
        // в соответствии с новым значением текущей позиции
        SetScrollPos(hScroll, SB_CTL, nPosition, TRUE);
      }
      return 0;
    }

// ------------------------------------------------------------
// WM_DESTROY
// Уничтожение главного окна приложения
// ------------------------------------------------------------
    case WM_DESTROY:
    {
      // Удаляем таймер и полосу просмотра
      KillTimer(hwnd, BEEP_TIMER);
      DestroyWindow(hScroll);

      // Если находимся в режиме записи, останавливаем
      // запись и закрываем устройство ввода
      if(nMode == MODE_RECORDING || nMode == MODE_RECORDINGPAUSED)
      {
        mciwioStop(wInDeviceID);
        mciwioClose(wInDeviceID);
      }

      else if(fFileLoaded)
      {
      // Если находимся в режиме проигрывания, останавливаем
      // запись и закрываем устройство вывода
        if(nMode == MODE_PLAYING || nMode == MODE_PLAYINGPAUSED)
        {
          mciwioStop(wOutDeviceID);
          mciwioClose(wOutDeviceID);
        }
        nMode = MODE_STOP;
      }
      PostQuitMessage(0);
      return 0;
    }
    default:
      break;
  }
  return DefWindowProc(hwnd, msg, wParam, lParam);
}

При создании главного окна приложения обработчиком сообщения WM_CREATE выполняется инициализация глобальных переменных. Устанавливается текущий режим работы nMode (останов), флаг загрузки файла для проигрывания fFileLoaded, в переменные, соответствующие идентификаторам устройств ввода и вывода (wOutDeviceID и wInDeviceID) записываются нулевые значения.

Положение движка на полосе просмотра, отражающее текущую позицию при записи и воспроизведении, определяется по сообщениям таймера. На этапе инициализации создается таймер, который посылает сообщения каждую десятую долю секунды. Кроме того, создается полоса просмотра, устанавливается текущая позиция, диапазон изменений значений и начальное положение движка.

Во время обработки сообщения WM_PAINT в верхней части окна отображается текущий режим работы, для чего используется функция TextOut.

Когда вы выбираете wav-файл для воспроизведения, функция окна получает сообщение WM_COMMAND с параметром wParam, равным значению CM_FILEOPEN. Соответствующий обработчик загружает файл, вызывая функцию mciwioSelectFile. Эта функция определена в нашем приложении, ее исходный текст находится в файле mciwaveio.cpp (листинг 2.9). С помощью функции SetWindowText путь к файлу отображается в заголовке окна приложения.

Если в момент выбора нового файла приложение находилось в режиме проигрывания, следует остановить и закрыть устройство вывода. Для этого мы используем функции mciwioStop и mciwioClose, соответственно. После того, как устройство вывода закрыто, мы сбрасываем содержимое переменной wOutDeviceID (идентификатор устройства вывода). Кроме того, в переменную nMode записываем код нового состояния (останов).

В завершении выполняется установка движка полосы просмотра в начальное положение. В переменную fFileLoaded записывается значение TRUE (загружен файл для воспроизведения).

После выбора строки "Play!" проверяется текущий режим и флаг загрузки файла. Если файл загружен, и приложение находится в состоянии останова, можно начинать воспроизведение. В переменную nMode записывается константа MODE_PLAYING (воспроизведение), открывается устройство вывода (функция mciwioOpen) и запускается воспроизведение (функция mciwioPlay). Для того чтобы название нового режима было отображено на экране, выполняется перерисовка окна (функция InvalidateRect). Исходные тексты функций mciwioOpen и mciwioPlay находятся в файле mciwaveio.cpp (листинг 2.9).

Запись также можно запустить только из состояния останова. Для записи вызывается функция mciwioRecord (ее исходный текст также находится в листинге 2.9), которой в качестве второго параметра передается максимальная длительность записи в миллисекундах.

При выполнении команды останова (строка "Stop!" в меню приложения) анализируется текущий режим работы. Если приложение находится в режиме записи, вызывается функция mciwioStop (останов устройства), причем в качестве параметра ей передается идентификатор устройства ввода. Если же приложение находится в состоянии воспроизведения, вызывается эта же функция, но в качестве параметра ей передается идентификатор устройства вывода. Далее движок полосы просмотра устанавливается в начальное положение, а переменную nMode записывается код состояния останова.

В ответ на команду временного останова (строка "Pause!") выполняется полный останов записи или временный останов воспроизведения. В последнем случае вызывается функция mciwioPause, которой в качестве параметра передается идентификатор устройства вывода. В переменную nMode записывается значение константы MODE_PLAYINGPAUSED, которое обозначает временный останов воспроизведения.

Для продолжения воспроизведения после временного останова вызывается функция mciwioResume, которой в качестве параметра передается идентификатор устройства вывода.

Функция окна приложения обрабатывает сообщение MM_MCINOTIFY, поступающее после завершения записи или воспроизведения. Обработчик этого сообщения сохраняет записанные данные в том случае, если было открыто устройство ввода. Для этого он вызывает функцию mciSendCommand, передавая с ее помощью устройству ввода команду MCI_SAVE_FILE:

mciSave.lpfilename = "recorded.wav";
dwrc=mciSendCommand(wInDeviceID, MCI_SAVE,
   MCI_SAVE_FILE | MCI_WAIT, (DWORD)(LPVOID)&mciSave);

После сохранения устройство ввода закрывается, в переменную wInDeviceID записывается нулевое значение:

dwrc = mciSendCommand(wInDeviceID, MCI_CLOSE, MCI_WAIT,
  (DWORD)(LPMCI_GENERIC_PARMS)&mcigen);
if(dwrc)
{
  mciwioError(dwrc);
}
wInDeviceID = 0;

Если сообщение MM_MCINOTIFY пришло при воспроизведении, устройство вывода останавливается и закрывается. В переменную wOutDeviceID записывается нулевое значение.

В любом случае обработчик сообщения MM_MCINOTIFY переводит приложение в режим останова.

Обработчик сообщения WM_TIMER предназначен для определения и отображения текущей позиции в режимах записи и воспроизведения.

В режиме записи текущая позиция определяется при помощи сообщения MCI_STATUS:

mciStatus.dwItem = MCI_STATUS_POSITION;
mciSendCommand(wInDeviceID, MCI_STATUS,
  MCI_STATUS_ITEM, (DWORD)(LPVOID)&mciStatus);
dwPos = mciStatus.dwReturn;

По умолчанию для звукового устройства ввода/вывода устанавливается формат времени в миллисекундах. Поэтому в переменную dwPos будет записана текущая позиция в миллисекундах.

Далее обработчик вычисляет положение движка полосы просмотра, исходя из диапазона изменения значений полосы просмотра SCROLL_SIZE, максимального времени записи MAXRECORDTIME и текущей позиции dwPos:

nPosition = ((DWORD)SCROLL_SIZE * dwPos) / MAXRECORDTIME;

Затем движок устанавливается в новое положение при помощи функции SetScrollPos.

В режиме воспроизведения новое положение движка просмотра вычисляется исходя из размера файла dwFileSize:

nPosition = ((DWORD)SCROLL_SIZE * dwPos) / dwFileSize;

Размер файла в миллисекундах записывается в глобальную переменную dwFileSize функцией mciwioOpen при открытии файла.

При завершении работы приложения удаляются таймер и полоса просмотра. Далее, если приложение находилось в режиме записи, устройство ввода останавливается и закрывается. Аналогичные действия выполняются с устройством вывода в режиме воспроизведения.

Константы для работы с меню определены в файле mciwave.hpp (листинг 2.8).


Листинг 2.8. Файл mciwaver\mciwave.hpp


#define CM_HELPABOUT   301
#define CM_FILEEXIT    302
#define CM_FILEOPEN    303
#define CM_FILESAVEAS  304
#define CM_FILENEW     305

#define CM_CTLPLAY     401
#define CM_CTLRECORD   402
#define CM_CTLRESUME   403
#define CM_CTLPAUSE    404
#define CM_CTLSTOP     405

Файл mciwaveio.cpp (листинг 2.9) содержит функции для работы с интерфейсом сообщений MCI.


Листинг 2.9. Файл mciwaver\mciwavio.cpp


#define STRICT
#include <windows.h>
#include <windowsx.h>
#include <commdlg.h>
#include <mmsystem.h>
#include <mem.h>
#pragma hdrstop

#include "mciwavio.hpp"

// Глобальные переменные
extern int  nMode;
extern int  nPosition;
extern DWORD dwFileSize;

//-----------------------------------------------------
// mciwioOpen
// Открытие устройства вывода
//-----------------------------------------------------

UINT mciwioOpen(LPSTR szFileName)
{
  MCI_OPEN_PARMS mciOpen;
  MCI_STATUS_PARMS mciStatus;
  DWORD dwrc;
  DWORD dwFlags;

  // Готовим блок параметров
  mciOpen.lpstrDeviceType= (LPSTR)"waveaudio";
  mciOpen.lpstrElementName = (LPSTR)szFileName;
  mciOpen.dwCallback = 0;
  mciOpen.wDeviceID = 0;
  mciOpen.wReserved0 = 0;
  mciOpen.lpstrAlias = NULL;

  // Устанавливаем флаги
  dwFlags = MCI_OPEN_TYPE | 
    MCI_OPEN_ELEMENT | MCI_WAIT;

  // Открываем устройство
  dwrc = mciSendCommand(0, MCI_OPEN,
    dwFlags, (DWORD)(LPVOID)&mciOpen);
  if(dwrc)
  {
    mciwioError(dwrc);
    return 0;
  }

  // Если устройство открыто успешно, определяем
  // длительность звучания в миллисекундах 
  else
  {
    mciStatus.dwItem = MCI_STATUS_LENGTH;
    dwrc = mciSendCommand(mciOpen.wDeviceID, MCI_STATUS,
      MCI_STATUS_ITEM | MCI_WAIT,
      (DWORD)(LPVOID)&mciStatus);
    if(dwrc)
    {
      mciwioError(dwrc);
      return 0;
    }

    // Сохраняем длительность звучания в глобальной
    // переменной и возвращаем идентификатор устройства вывода
    dwFileSize = mciStatus.dwReturn;
    return mciOpen.wDeviceID;
  }
}

//-----------------------------------------------------
// mciwioPlay
// Проигрывание загруженного wav-файла
//-----------------------------------------------------
DWORD mciwioPlay(HWND hwnd, UINT wDeviceID)
{
  MCI_PLAY_PARMS mciPlayParms;
  DWORD dwrc;

  // Позиционирование на начало фрагмента
  dwrc = mciSendCommand(wDeviceID, MCI_SEEK,
    MCI_WAIT | MCI_SEEK_TO_START, NULL);

  // Идентификатор окна, функция которого получит
  // сообщение MM_MCINOTIFY
  mciPlayParms.dwCallback = (DWORD)hwnd;

  // Запускаем проигрывание
  dwrc=mciSendCommand(wDeviceID, MCI_PLAY, MCI_NOTIFY,
    (DWORD)(LPVOID)&mciPlayParms);

  return dwrc;
}

//-----------------------------------------------------
// mciwioStop
// Останов проигрывания загруженного wav-файла
//-----------------------------------------------------
DWORD mciwioStop(UINT wDeviceID)
{
  MCI_GENERIC_PARMS mcigen;
  DWORD dwrc;

  dwrc = mciSendCommand(wDeviceID, MCI_STOP, MCI_WAIT,
    (DWORD)(LPMCI_GENERIC_PARMS)&mcigen);
  if(dwrc)
  {
    mciwioError(dwrc);
  }

  return dwrc;
}

//-----------------------------------------------------
// mciwioResume
// Проигрывание после временного останова
//-----------------------------------------------------
DWORD mciwioResume(UINT wDeviceID)
{
  MCI_GENERIC_PARMS mcigen;
  DWORD dwrc;

  dwrc = mciSendCommand(wDeviceID, MCI_RESUME, MCI_WAIT,
    (DWORD)(LPMCI_GENERIC_PARMS)&mcigen);
  if(dwrc)
  {
    mciwioError(dwrc);
  }

  return dwrc;
}

//-----------------------------------------------------
// mciwioPause
// Временный останов проигрывания загруженного wav-файла
//-----------------------------------------------------
DWORD mciwioPause(UINT wDeviceID)
{
  MCI_GENERIC_PARMS mcigen;
  DWORD dwrc;

  dwrc = mciSendCommand(wDeviceID, MCI_PAUSE, MCI_WAIT,
    (DWORD)(LPMCI_GENERIC_PARMS)&mcigen);
  if(dwrc)
  {
    mciwioError(dwrc);
  }

  return dwrc;
}

//-----------------------------------------------------
// mciwioSelectFile
// Выбор wav-файла
//-----------------------------------------------------
BOOL mciwioSelectFile(LPSTR lpszFileName)
{
  OPENFILENAME ofn;

  char szFile[256];
  char szFileTitle[256];
  char szFilter[256] =
         "Wave Files\0*.wav\0Any Files\0*.*\0";
  szFile[0] = '\0';
  memset(&ofn, 0, sizeof(OPENFILENAME));

  // Инициализируем нужные нам поля
  ofn.lStructSize       = sizeof(OPENFILENAME);
  ofn.hwndOwner         = NULL;
  ofn.lpstrFilter       = szFilter;
  ofn.nFilterIndex      = 1;
  ofn.lpstrFile         = szFile;
  ofn.nMaxFile          = sizeof(szFile);
  ofn.lpstrFileTitle    = szFileTitle;
  ofn.nMaxFileTitle     = sizeof(szFileTitle);
  ofn.lpstrInitialDir   = NULL;
  ofn.Flags =   OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST
               | OFN_HIDEREADONLY;
  // Выбираем входной файл
  if (GetOpenFileName(&ofn))
  {
    // Копируем путь к выбранному файлу
    lstrcpy(lpszFileName, (LPSTR)szFile);
    return TRUE;
  }
  else
    return FALSE;
}

//-----------------------------------------------------
// mciwioClose
// Закрытие устройства вывода
//-----------------------------------------------------
void mciwioClose(UINT wDeviceID)
{
  MCI_GENERIC_PARMS mcigen;
  DWORD dwrc;

  dwrc = mciSendCommand(wDeviceID, MCI_CLOSE, MCI_WAIT,
    (DWORD)(LPMCI_GENERIC_PARMS)&mcigen);
  if(dwrc)
  {
    mciwioError(dwrc);
    return;
  }
}

//-----------------------------------------------------
// mciwioError
// Обработка ошибок
//-----------------------------------------------------
void mciwioError(DWORD dwrc)
{
  BYTE szBuf[MAXERRORLENGTH];

  if(mciGetErrorString(dwrc, (LPSTR)szBuf, MAXERRORLENGTH))
    MessageBox(NULL, szBuf,
      "MCIWAVER Error", MB_ICONEXCLAMATION);
  else
    MessageBox(NULL, "Неизвестная ошибка",
      "MCIWAVER Error", MB_ICONEXCLAMATION);
}

//-----------------------------------------------------
// mciwioRecord
// Запись wav-файла
//-----------------------------------------------------
WORD mciwioRecord(HWND hwnd, DWORD dwMSec)
{
  MCI_RECORD_PARMS mciRecordParms;
  MCI_OPEN_PARMS mciOpen;
  DWORD dwrc;
  DWORD dwFlags;
  WORD wInDeviceID;

  // Готовим блок параметров
  // для команды открытия устройства
  mciOpen.lpstrDeviceType  = (LPSTR)"waveaudio";
  mciOpen.lpstrElementName = (LPSTR)"";
  mciOpen.dwCallback = 0;
  mciOpen.wDeviceID = 0;
  mciOpen.wReserved0 = 0;
  mciOpen.lpstrAlias = NULL;

  // Устанавливаем флаги
  dwFlags = MCI_OPEN_TYPE| 
    MCI_OPEN_ELEMENT | MCI_WAIT;

  // Открываем устройство ввода
  dwrc = mciSendCommand(0, MCI_OPEN, dwFlags,
    (DWORD)(LPVOID)&mciOpen);
  if(dwrc)
  {
    mciwioError(dwrc);
    return 0;
  }
  else
  {
    // В случае успеха сохраняем идентификатор
    // устройства ввода в глобальной переменной
    wInDeviceID = mciOpen.wDeviceID;
  }

  // Готовим блок параметров для команды записи
  mciRecordParms.dwTo       = dwMSec;
  mciRecordParms.dwCallback = (DWORD)hwnd;

  // Запускаем запись
  dwrc=mciSendCommand(wInDeviceID,
     MCI_RECORD, MCI_NOTIFY | MCI_TO,
    (DWORD)(LPVOID)&mciRecordParms);
  if(dwrc)
  {
    mciwioError(dwrc);
    return 0;
  }
  return wInDeviceID;
}

Функция mciwioOpen открывает устройство вывода, посылая ему сообщение MCI_OPEN. В блоке параметров мы указываем тип устройства ("waveaudio") и путь к wav-файлу szFileName. Так как тип устройства указан в виде текстовой строки, мы используем флаг MCI_OPEN_TYPE. Необходимо также указать флаг MCI_OPEN_ELEMENT, так как устройство будет работать с файлом. Для того чтобы функция вернула управление только после открытия устройства, используется флаг MCI_WAIT.

Если при открытии устройства произошла ошибка, функция mciSendCommand вернет ненулевой код ошибки. Мы передаем этот код функции mciwioError, которая выводит текстовое описание ошибки на экран.

После успешного открытия устройства вывода определяется размер файла (длительность звучания файла в миллисекундах). Для этого используется сообщение с кодом MCI_STATUS. Полученный размер сохраняется в глобальной переменной dwFileSize. Он будет использован для вычисления положения движка полосы просмотра, соответствующего текущей позиции при воспроизведении.

Функция mciwioPlay предназначена для проигрывания загруженного файла с самого начала. Перед запуском воспроизведения текущая позиция устанавливается на начало, для чего используется сообщение MCI_SEEK с флагом MCI_SEEK_TO_START:

dwrc = mciSendCommand(wDeviceID, MCI_SEEK,
  MCI_WAIT | MCI_SEEK_TO_START, NULL);

Далее готовится блок параметров для сообщения MCI_PLAY. В поле dwCallback записывается идентификатор главного окна приложения (из глобальной переменной hwnd). Это окно получит извещение о завершении проигрывания в виде сообщения MM_MCINOTIFY.

Функция mciwioStop посылает устройству, идентификатор которого передается ей через параметр wDeviceID, сообщение MCI_STOP.

Функция mciwioPause предназначена для временного останова проигрывания wav-файла. Она посылает устройству, идентификатор которого передается ей через параметр wDeviceID, сообщение MCI_PAUSE.

С помощью функции mciwioResume можно возобновить прерванный функцией mciwioPause процесс записи или воспроизведения. Эта функция посылает устройству сообщение MCI_RESUME.

Функция mciwioSelectFile предназначена для выбора wav-файла. Она пользуется стандартной диалоговой панелью выбора файла и функцией GetOpenFileName, определенной в DLL-библиотеке commdlg.dll. Мы уже пользовались этой функцией в предыдущих томах "Библиотеки системного программиста". Путь к выбранному файлу копируется в буфер, адрес которого передается функции mciwioSelectFile в качестве единственного параметра.

Функция mciwioClose закрывает устройство ввода или вывода, посылая ему сообщение MCI_CLOSE.

Запись файла инициируется функцией mciwioRecord. В качестве первого параметра этой функции передается идентификатор окна, которое получит сообщение MM_MCINOTIFY после завершения процесса записи. Второй параметр определяет максимальную длительность записи в миллисекундах.

Перед началом записи открывается устройство ввода "waveaudio", причем в качестве имени файла используется пустая строка:

mciOpen.lpstrDeviceType  = (LPSTR)"waveaudio";
mciOpen.lpstrElementName = (LPSTR)"";
mciOpen.dwCallback = 0;
mciOpen.wDeviceID = 0;
mciOpen.wReserved0 = 0;
mciOpen.lpstrAlias = NULL;

dwFlags = MCI_OPEN_TYPE | 
  MCI_OPEN_ELEMENT | MCI_WAIT;

dwrc = mciSendCommand(0, MCI_OPEN, dwFlags,
  (DWORD)(LPVOID)&mciOpen);
if(dwrc)
{
  mciwioError(dwrc);
  return 0;
}
else
{
  wInDeviceID = mciOpen.wDeviceID;
}

Далее готовится блок параметров для записи и посылается сообщение MCI_RECORD:

mciRecordParms.dwTo       = dwMSec;
mciRecordParms.dwCallback = (DWORD)hwnd;
dwrc=mciSendCommand(wInDeviceID,
   MCI_RECORD, MCI_NOTIFY | MCI_TO,
  (DWORD)(LPVOID)&mciRecordParms);

При этом указывается конечная позиция для записи dwTo и идентификатор окна, которое получит извещение о завершении процесса записи dwCallback. Для того чтобы перечисленные параметры были приняты во внимание, устанавливаются флаги MCI_TO и MCI_NOTIFY.

Константы и прототипы функций для файла mciwavio.cpp находятся в файле mciwaveio.hpp (листинг 2.10).


Листинг 2.10. Файл mciwaver\mciwavio.hpp


#include <windows.h>
#include <mmsystem.h>

#define MODE_STOP            0
#define MODE_PLAYING         1
#define MODE_RECORDING       2
#define MODE_PLAYINGPAUSED   3
#define MODE_RECORDINGPAUSED 4

UINT  mciwioOpen(LPSTR szFileName);
BOOL  mciwioSelectFile(LPSTR lpszFileName);
void  mciwioClose(UINT wDeviceID);
DWORD mciwioPlay(HWND hwnd, UINT wDeviceID);
void  mciwioError(DWORD dwrc);
DWORD mciwioStop(UINT wDeviceID);
DWORD mciwioPause(UINT wDeviceID);
DWORD mciwioResume(UINT wDeviceID);
WORD  mciwioRecord(HWND hwnd, DWORD dwMSec);

Файл описания ресурсов (листинг 2.11) содержит определение пиктограммы и шаблон меню.


Листинг 2.11. Файл mciwaver\mciwaver.rc


#include "mciwave.hpp"
APPICON ICON "mciwaver.ico"
APP_MENU MENU 
BEGIN
  POPUP "&File"
    BEGIN
      MENUITEM "&Open...", CM_FILEOPEN
      MENUITEM SEPARATOR
      MENUITEM "E&xit",    CM_FILEEXIT
    END

  MENUITEM "&Play!",     CM_CTLPLAY
  MENUITEM "&Stop!",     CM_CTLSTOP
  MENUITEM "Resu&me!",   CM_CTLRESUME
  MENUITEM "P&ause!",    CM_CTLPAUSE
  MENUITEM "&Record!",   CM_CTLRECORD

  POPUP "&Help"
    BEGIN
      MENUITEM "&About...", CM_HELPABOUT
    END
END

Файл определения модуля для приложения MCIWAVER приведен в листинге 2.12.


Листинг 2.12. Файл mciwaver\mciwaver.def


NAME        MCIWAVER
DESCRIPTION 'Приложение MCIWAVER, (C) 1994, Frolov A.V.'
EXETYPE     windows
STUB        'winstub.exe'
STACKSIZE   10240
HEAPSIZE    1024
CODE        preload moveable discardable
DATA        preload moveable multiple

[Назад] [Содеожание] [Дальше]