Мультимедиа для Windows© Александр Фролов, Григорий ФроловТом 15, М.: Диалог-МИФИ, 1994, 284 стр. 3.2. Интерфейс управляющих сообщений MCIКак правило, большинство приложений, составленных на языках программирования C и C++, управляют устройством чтения CD ROM с помощью интерфейса управляющих сообщений MCI. Напомним, что приложения, использующие этот интерфейс, посылают устройствам мультимедиа управляющие сообщения с помощью функции mciSendCommand . Рассмотрим особенности команд MCI, предназначенных для устройства чтения компакт-дисков. MCI_OPENКоманда MCI_OPEN не имеет никаких дополнительных возможностей и используется как обычно. Приложение должно подготовить структуру MCI_OPEN_PARMS и передать ее адрес через четвертый параметр функции mciSendCommand. Поле lpstrDeviceType структуры MCI_OPEN_PARMS содержит указатель на строку имени устройства, или константный идентификатор устройства. Для устройства чтения CD ROM вы можете указать имя "cdaudio " или константу MCI_DEVTYPE_CD_AUDIO . Параметр lpstrElementName не используется, так как устройство чтения компакт-дисков не работает с файлами. Приведенный ниже фрагмент кода открывает устройство чтения компакт-дисков: MCIOpen.lpstrDeviceType = (LPSTR)MCI_DEVTYPE_CD_AUDIO; dwrc = mciSendCommand(NULL, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID, (DWORD)(LPVOID)&MCIOpen); После выполнения этого фрагмента в переменную dwrc будет записан код результата завершения. При успешном завершении в поле wDeviceID структуры mciOpen будет находиться идентификатор открытого устройства. MCI_CLOSEЭта команда закрывает устройство. Она также не имеет никаких особенностей. MCI_PLAYКоманда MCI_PLAY не имеет расширений для устройства чтения CD ROM. MCI_PAUSEКоманда MCI_PAUSE останавливает выполнение операции проигрывания звукового компакт-диска и действует точно так же, как и команда MCI_STOP. MCI_STOPКоманда MCI_STOP останавливает выполнение проигрывания компакт-диска. MCI_SEEKКоманда MCI_SEEK позволяет выполнять позиционирование. Она не имеет расширений, специально предназначенных для устройства чтения CD ROM. MCI_BREAKС помощью команды MCI_BREAK указывается виртуальный код клавиши, с помощью которой можно прервать выполнение операции. По умолчанию используется комбинация клавиш <Control+Break>. 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:
MCI_INFOС помощью этой команды можно получить информацию об устройстве чтения CD ROM в виде текстовой строки. Используется блок параметров в формате структуры 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_SYSINFOС помощью этой команды можно получить системную информацию об устройстве в виде текстовой строки. Команда MCI_SYSINFO не имеет расширений для устройства чтения компакт-дисков. 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:
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 определяет выходной канал. Приведем список флагов, которые используются вместе с командой MCI_SET:
При использовании формата времени MCI_FORMAT_MSF старший байт старшего слова поля dwTimeFormat не используется, младший содержит номер фрейма. Старший байт младшего слова содержит секунды, младший - минуты. Формат времени MCI_FORMAT_TMSF аналогичный, за исключением того, что старший байт старшего слова содержит номер дорожки. Приложение MCICDPLЕсли вы будете разрабатывать проигрыватель звуковых компакт-дисков, то можете взять за основу приложение MCICDPL (рис. 3.1), которое работает с устройством чтения CD-ROM при помощи управляющих сообщений MCI.
Рис. 3.1. Главное окно приложения MCICDPL Исходный текст приложения представлен в листинге 3.1. Листинг 3.1. Файл mcicdpl/mcicdpl.cpp
// ----------------------------------------
// Проигрыватель звуковых компакт-дисков
// ----------------------------------------
#define STRICT
#include <windows.h>
#include <mmsystem.h>
#include <mem.h>
#include <stdlib.h>
#include "mcicdpl.hpp"
#define CD_EMPTY 0
#define CD_READY 1
#define CD_PLAYING 2
#define CD_PAUSED 3
// Прототипы функций
BOOL InitApp(HINSTANCE);
LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM);
void mciwioError(DWORD dwrc);
void Play(HWND hwnd, UINT nTrack);
// Имя класса окна
char const szClassName[] = "MCICDP";
// Заголовок окна
char const szWindowTitle[] = "MCI CD Player";
HINSTANCE hInst;
DWORD dwrc;
UINT nTimerID;
MCI_OPEN_PARMS MCIOpen;
MCI_SET_PARMS MCISet;
MCI_STATUS_PARMS MCIStatus;
MCI_PLAY_PARMS MCIPlay;
BOOL bMediaPresent = FALSE;
BOOL bPaused = FALSE;
UINT nMode = 0;
UINT nCurTrack = 0;
UINT nTrackCnt = 0;
HWND hwndCurTrack = NULL;
// =====================================
// Функция 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;
// Открываем устройство чтения компакт-дисков
MCIOpen.lpstrDeviceType = (LPSTR)MCI_DEVTYPE_CD_AUDIO;
dwrc = mciSendCommand(NULL, MCI_OPEN,
MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID,
(DWORD)(LPVOID)&MCIOpen);
if(dwrc)
{
mciwioError(dwrc);
return -1;
}
// Устанавливаем формат времени
MCISet.dwTimeFormat = MCI_FORMAT_TMSF;
dwrc = mciSendCommand(MCIOpen.wDeviceID, MCI_SET,
MCI_SET_TIME_FORMAT,
(DWORD)(LPVOID)&MCISet);
if(dwrc)
{
mciwioError(dwrc);
return -1;
}
// Создаем диалоговую панель вместо главного окна
hwnd = CreateDialog(hInstance, szClassName, 0, NULL);
// Если создать окно не удалось, завершаем приложение
if(!hwnd)
return FALSE;
// Определяем идентификатор поля, которое используется
// для отображения номера текущей дорожки
hwndCurTrack = GetDlgItem(hwnd, IDT_CURTRACK);
// Рисуем главное окно
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// Запускаем цикл обработки сообщений
while(GetMessage(&msg, NULL, 0, 0))
{
if((hwnd == 0) || (!IsDialogMessage(hwnd, &msg)))
DispatchMessage(&msg);
}
return msg.wParam;
}
// =====================================
// Функция InitApp
// Выполняет регистрацию класса окна
// =====================================
BOOL InitApp(HINSTANCE hInstance)
{
ATOM aWndClass; // атом для кода возврата
WNDCLASS wc; // структура для регистрации
// класса окна
memset(&wc, 0, sizeof(wc));
wc.style = 0;
wc.lpfnWndProc = (WNDPROC) WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = DLGWINDOWEXTRA;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(hInstance, "APPICON");
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = (LPSTR)NULL;
wc.lpszClassName = (LPSTR)szClassName;
// Регистрация класса
aWndClass = RegisterClass(&wc);
return (aWndClass != 0);
}
// =====================================
// Функция WndProc
// =====================================
LRESULT CALLBACK _export
WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
// ---------------------------------------
// Обработчик сообщения WM_CREATE
// ---------------------------------------
case WM_CREATE:
{
// Создаем таймер, который нужен для периодического
// определения состояния устройства чтения CD
nTimerID = SetTimer(hwnd, 1, 1000, NULL);
return 0;
}
// ---------------------------------------
// Обработчик сообщения WM_COMMAND
// ---------------------------------------
case WM_COMMAND:
{
switch(wParam)
{
// Запуск режима проигрывания
case IDB_PLAY:
{
// Если в проигрывателе есть компакт-диск,
// запускаем проигрывание
if(bMediaPresent)
Play(hwnd, 1);
return 0;
}
// Останов проигрывания
case IDB_STOP:
{
if(bMediaPresent)
{
bPaused = FALSE;
nCurTrack = 0;
mciSendCommand(MCIOpen.wDeviceID, MCI_STOP,
NULL, NULL);
}
return 0;
}
// Временный останов проигрывания
case IDB_PAUSE:
{
if(bMediaPresent)
{
if(!bPaused)
{
bPaused = TRUE;
mciSendCommand(MCIOpen.wDeviceID, MCI_PAUSE,
NULL, NULL);
}
}
return 0;
}
// Продолжение проигрывания после
// временного останова
case IDB_RESUME:
{
if(bMediaPresent)
{
if(bPaused)
{
bPaused = FALSE;
MCIPlay.dwCallback = (DWORD)hwnd;
mciSendCommand(MCIOpen.wDeviceID, MCI_PLAY,
MCI_NOTIFY, (DWORD)(LPVOID)&MCIPlay);
}
}
return 0;
}
// Позиционирование на следующую дорожку
case IDB_NEXT:
{
if(bMediaPresent)
{
UINT nNewTrack;
// Если текущая дорожка - последняя,
// начинаем проигрывание с первой дорожки.
// Если нет - проигрываем следующую дорожку
if(nCurTrack == nTrackCnt)
nNewTrack = 1;
else
nNewTrack = nCurTrack + 1;
Play(hwnd, nNewTrack);
}
return 0;
}
// Позиционирование на предыдущую дорожку
case IDB_PREV:
{
if(bMediaPresent)
{
UINT nNewTrack;
// Если текущая дорожка - первая,
// проигрываем последнюю дорожку
if(nCurTrack <= 1)
nNewTrack = nTrackCnt;
else
nNewTrack = nCurTrack - 1;
Play(hwnd, nNewTrack);
}
return 0;
}
// Завершаем работу приложения
case IDOK:
case IDCANCEL:
{
SendMessage(hwnd, WM_CLOSE, 0, 0L);
return 0;
}
// Выполняем команду извлечения диска из
// устройства чтения
case IDB_EJECT:
{
mciSendCommand(MCIOpen.wDeviceID, MCI_SET,
MCI_SET_DOOR_OPEN, NULL);
return 0;
}
}
}
// ---------------------------------------
// Обработчик сообщения WM_TIMER
// ---------------------------------------
case WM_TIMER:
{
UINT nCurMode;
// Если окно свернуто в пиктограмму, ничего не делаем,
// чтобы не снижать производительность системы
if(IsIconic(hwnd))
return 0;
// Определяем текущее состояние проигрывателя CD
MCIStatus.dwItem = MCI_STATUS_MODE;
mciSendCommand(MCIOpen.wDeviceID, MCI_STATUS,
MCI_STATUS_ITEM | MCI_WAIT,
(DWORD)(LPVOID)&MCIStatus);
// Проверяем, готово ли устройство чтения к работе
if((MCIStatus.dwReturn == MCI_MODE_NOT_READY) ||
(MCIStatus.dwReturn == MCI_MODE_OPEN))
{
// Устройство не готово
nCurMode = CD_EMPTY;
}
else if((MCIStatus.dwReturn == MCI_MODE_STOP) &&
bPaused)
{
// Устройство остановлено
nCurMode = CD_PAUSED;
}
else if(MCIStatus.dwReturn == MCI_MODE_PLAY)
{
// Устройство находится в режиме проигрывания
nCurMode = CD_PLAYING;
}
else
{
// Устройство готово
nCurMode = CD_READY;
}
// Если с момента последней проверки произошло
// изменение режима, записываем код нового режима
if(nMode != nCurMode)
{
nMode = nCurMode;
}
// Проверяем, вставлен ли компакт-диск
MCIStatus.dwItem = MCI_STATUS_MEDIA_PRESENT;
mciSendCommand(MCIOpen.wDeviceID, MCI_STATUS,
MCI_STATUS_ITEM | MCI_WAIT,
(DWORD)(LPVOID)&MCIStatus);
// Если компакт-диск вставлен, определяем
// количество звуковых дорожек
if((!bMediaPresent) && MCIStatus.dwReturn)
{
bMediaPresent = TRUE;
bPaused = FALSE;
nCurTrack = 0;
MCIStatus.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
mciSendCommand(MCIOpen.wDeviceID, MCI_STATUS,
MCI_STATUS_ITEM | MCI_WAIT,
(DWORD)(LPVOID)&MCIStatus);
nTrackCnt = MCIStatus.dwReturn;
}
// Если компакт-диск не вставлен, сбрасываем
// номер текущей дорожке в поле диалоговой панели
else if((bMediaPresent) && !MCIStatus.dwReturn)
{
bMediaPresent = FALSE;
bPaused = FALSE;
SetWindowText(hwndCurTrack, (LPSTR)"");
}
// Если приложение находится в режиме проигрывания,
// определяем номер текущей дорожки
if(nCurMode == CD_PLAYING)
{
// Определяем текущую позицию
MCIStatus.dwItem = MCI_STATUS_POSITION;
mciSendCommand(MCIOpen.wDeviceID, MCI_STATUS,
MCI_STATUS_ITEM | MCI_WAIT,
(DWORD)(LPVOID)&MCIStatus);
// Если номер дорожки изменился, отображаем новое
// значение в соответствующем поле диалоговой панели
if(nCurTrack != (UINT)MCI_TMSF_TRACK(MCIStatus.dwReturn))
{
BYTE szBuf[20];
nCurTrack = (UINT)MCI_TMSF_TRACK(MCIStatus.dwReturn);
SetWindowText(hwndCurTrack, itoa(nCurTrack, szBuf, 10));
}
}
return 0;
}
// ---------------------------------------
// Обработчик сообщения MM_MCINOTIFY
// ---------------------------------------
case MM_MCINOTIFY:
{
if(wParam == MCI_NOTIFY_SUCCESSFUL)
{
if(bMediaPresent)
Play(hwnd, 1);
}
return 0;
}
// ---------------------------------------
// Обработчик сообщения WM_CLOSE
// ---------------------------------------
case WM_CLOSE:
{
DestroyWindow(hwnd);
return 0;
}
// ---------------------------------------
// Обработчик сообщения WM_DESTROY
// ---------------------------------------
case WM_DESTROY:
{
// Закрываем устройство чтения компакт-дисков
dwrc = mciSendCommand(MCIOpen.wDeviceID, MCI_CLOSE,
NULL, NULL);
if(dwrc)
mciwioError(dwrc);
// Уничтожаем таймер
KillTimer(hwnd, nTimerID);
PostQuitMessage(0);
return 0;
}
}
return DefDlgProc(hwnd, msg, wParam, lParam);
}
//-----------------------------------------------------
// mciwioError
// Обработка ошибок
//-----------------------------------------------------
void mciwioError(DWORD dwrc)
{
BYTE szBuf[MAXERRORLENGTH];
if(mciGetErrorString(dwrc, (LPSTR)szBuf, MAXERRORLENGTH))
MessageBox(NULL, szBuf,
"MCIWAVE Error", MB_ICONEXCLAMATION);
else
MessageBox(NULL, "Неизвестная ошибка",
"MCIWAVE Error", MB_ICONEXCLAMATION);
}
//-----------------------------------------------------
// Play
// Запуск проигрывания дорожки
//-----------------------------------------------------
void Play(HWND hwnd, UINT nTrack)
{
bPaused = FALSE;
MCIPlay.dwCallback = (DWORD)hwnd;
MCIPlay.dwFrom = MCI_MAKE_TMSF(nTrack, 0, 0, 0);
dwrc = mciSendCommand(MCIOpen.wDeviceID, MCI_PLAY,
MCI_FROM | MCI_NOTIFY, (DWORD)(LPVOID)&MCIPlay);
if(dwrc)
{
mciwioError(dwrc);
return;
}
}
Особенностью данного приложения является отсутствие главного окна - его роль выполняет диалоговая панель. Сразу после запуска приложение пытается открыть устройство чтения компакт-дисков, и если в системе нет соответствующего драйвера, приложение завершает свою работу с сообщением об ошибке. Далее устанавливается формат времени MCI_FORMAT_TMSF, так как приложение будет выполнять позиционирование по дорожкам компакт-диска. Далее с помощью функции CreateDialog создается диалоговая панель, при этом указывается зарегистрированный приложением класс окна szClassName (строка "MCICDP"): hwnd = CreateDialog(hInstance, szClassName, 0, NULL); Для того чтобы функция окна могла получать сообщения от диалоговой панели, в описании шаблона диалоговой панели используется оператор CLASS : CLASS "MCICDP" В шаблоне предусмотрен статический орган управления, который имеет идентификатор IDT_CURTRACK и используется для отображения номера текущего трека. Перед запуском цикла обработки сообщений приложение определяет его идентификатор и сохраняет в переменной hwndCurTrack: hwndCurTrack = GetDlgItem(hwnd, IDT_CURTRACK); Затем диалоговая панель отображается на экране и запускается цикл обработки сообщений, в котором вызывается функция IsDialogMessage:
while(GetMessage(&msg, NULL, 0, 0))
{
if((hwnd == 0) || (!IsDialogMessage(hwnd, &msg)))
DispatchMessage(&msg);
}
Во время обработки сообщения WM_CREATE создается таймер с периодом 1 секунда. Этот таймер будет использоваться для определения текущего состояния устройства чтения компакт-дисков. Если нажать на кнопку "Play", функция окна получит сообщение WM_COMMAND с параметром IDB_PLAY. При этом приложение проверит состояние флага bMediaPresent (наличие компакт-диска в устройстве) и, если этот флаг установлен, запустит проигрывание первой дорожки. Содержимое флага bMediaPresent периодически обновляется в соответствии с действительным состоянием устройства обработчиком сообщений таймера. Кнопка "Stop" позволяет остановить процесс проигрывания. При этом устройству посылается команда MCI_STOP. Алогично, кнопка "Pause" выполняет временный останов, соответствующий обработчик посылает управляющее сообщение с кодом MCI_PAUSE. Для продолжения проигрывания после временного останова используется команда MCI_PLAY, для которой не задается начальная позиция (команда MCI_RESUME не поддерживается драйвером устройства чтения CD ROM). В этом случае проигрывание возобновляется с текущей позиции, то есть с прерванного места. Для выполнения операции позиционирования на следующую или предыдущую дорожку вычисляется номер следующей дорожки исходя из номера текущей дорожки. Если новый номер дорожки меньше 1 или больше максимального, выполняется переход, соответственно, на последнюю или первую дорожку компакт-диска. Обработчик сообщения таймера проверяет, не находится ли окно приложения (диалоговая панель) в свернутом виде. Если пользователь свернул окно в пиктограмму, нет смысла определять текущее состояние устройства, поэтому для увеличения общей производительности системы обработчик сообщения таймера в этом случае просто возвращает управление. Код текущего состояния устройства записывается в переменную nMode. Далее обработчик сообщения WM_TIMER с помощью команды MCI_STATUS проверяет, вставлен ли в устройство компакт-диск. Если диск вставлен, определяется количество дорожек. определенное значение сохраняется в переменной nTrackCnt. Номер текущей дорожки также определяется каждый раз при обработке сообщения таймера (при условии, что компакт-диск вставлен в устройство и устройство находится в режиме проигрывания). Если этот номер изменился, новое значение отображается в статическом органе управления диалоговой панели с идентификатором hwndCurTrack:
if(nCurTrack != (UINT)MCI_TMSF_TRACK(MCIStatus.dwReturn))
{
BYTE szBuf[20];
nCurTrack = (UINT)MCI_TMSF_TRACK(MCIStatus.dwReturn);
SetWindowText(hwndCurTrack, itoa(nCurTrack, szBuf, 10));
}
Макрокоманда MCI_TMSF_TRACK извлекает номер дорожки из значения, возвращенного командой MCI_STATUS с параметром MCI_STATUS_POSITION. В файле mmsystem.h определены и другие макрокоманды, которые используются аналогичным образом для получения других полей: MCI_TMSF_FRAME , MCI_TMSF_MINUTE , MCI_TMSF_SECOND , MCI_MSF_FRAME , MCI_MSF_MINUTE , MCI_MSF_SECOND . Можно сделать и обратные преобразования. Например, можно использовать макрокоманду MCI_MAKE_TMSF для упаковки в двойное слово номера дорожки, минут, секунд и номера фрейма: dwFormat = MCI_MAKE_TMSF(track, min, sec, frame); В нашем приложении предусмотрена обработка сообщения MM_MCINOTIFY . Это сообщение используется для того чтобы "зациклить" проигрывание компакт-диска. После того как команда проигрывания будет выполнена до конца (то есть после того как будет завершено проигрывание последней дорожки компакт-диска), функция окна приложения получит сообщение MM_MCINOTIFY с параметром MCI_NOTIFY_SUCCESSFUL. Обработчик этого сообщения выглядит очень просто - он запускает проигрывание заново с первой дорожки:
case MM_MCINOTIFY:
{
if(wParam == MCI_NOTIFY_SUCCESSFUL)
{
if(bMediaPresent)
Play(hwnd, 1);
}
return 0;
}
При завершении работы приложения обработчик сообщения WM_DESTROY закрывает устройство чтения компакт-дисков и уничтожает таймер. Функция Play, определенная в нашем приложении, запускает проигрывание компакт-диска начиная с заданной дорожки. В ней для формирования позиции используется макрокоманда MCI_MAKE_TMSF : MCIPlay.dwFrom = MCI_MAKE_TMSF(nTrack, 0, 0, 0); Все параметры, кроме первого, содержат нулевые значения, поэтому проигрывание будет запущено с самого начала дорожки, имеющей номер nTrack. Файл mcicdpl.hpp (листинг 3.2) содержит определения констант, используемых в приложении. Листинг 3.2. Файл mcicdpl/mcicdpl.hpp #define IDT_CURTRACK 200 #define IDB_STOP 101 #define IDB_PAUSE 102 #define IDB_RESUME 103 #define IDB_NEXT 104 #define IDB_PREV 105 #define IDB_EJECT 106 #define IDB_PLAY 100 Файл описания ресурсов приложения представлен в листинге 3.3. Он содержит определение пиктограммы и диалоговой панели, выступающей в роли главного окна приложения. Листинг 3.3. Файл mcicdpl/mcicdpl.rc
#include "g:\tcwin\include\windows.h"
#include "mcicdpl.hpp"
APPICON ICON "mcicdpl.ico"
MCICDP DIALOG 45, 20, 153, 57
STYLE WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX
CLASS "MCICDP"
CAPTION "Compact Disk Player"
BEGIN
PUSHBUTTON "Play", IDB_PLAY, 84, 11, 31, 11,
WS_CHILD | WS_VISIBLE | WS_TABSTOP
PUSHBUTTON "Stop", IDB_STOP, 118, 11, 31, 11,
WS_CHILD | WS_VISIBLE | WS_TABSTOP
PUSHBUTTON "Pause", IDB_PAUSE, 84, 26, 31, 11,
WS_CHILD | WS_VISIBLE | WS_TABSTOP
PUSHBUTTON "Resume", IDB_RESUME, 118, 26, 31, 11,
WS_CHILD | WS_VISIBLE | WS_TABSTOP
PUSHBUTTON ">>I", IDB_NEXT, 6, 26, 31, 11,
WS_CHILD | WS_VISIBLE | WS_TABSTOP
PUSHBUTTON "I<<", IDB_PREV, 40, 26, 31, 11,
WS_CHILD | WS_VISIBLE | WS_TABSTOP
PUSHBUTTON "Eject", IDB_EJECT, 6, 41, 65, 11,
WS_CHILD | WS_VISIBLE | WS_TABSTOP
DEFPUSHBUTTON "Exit", IDOK, 84, 41, 65, 11,
WS_CHILD | WS_VISIBLE | WS_TABSTOP
LTEXT "Track:", -1, 12, 7, 35, 8,
WS_CHILD | WS_VISIBLE | WS_GROUP
LTEXT "00", IDT_CURTRACK, 35, 7, 16, 8,
WS_CHILD | WS_VISIBLE | WS_GROUP
CONTROL "", -1, "static",
SS_BLACKFRAME | WS_CHILD | WS_VISIBLE, 6, 4, 65, 15
END
Файл определения модуля приложения MCICDPL представлен в листинге 3.4. Листинг 3.4. Файл mcicdpl/mcicdpl.def NAME MCICDPL DESCRIPTION 'Приложение MCICDPL, (C) 1994, Frolov A.V.' EXETYPE windows STUB 'winstub.exe' STACKSIZE 8194 HEAPSIZE 1024 CODE preload moveable discardable DATA preload moveable multiple |

