Опубликован: 24.04.2009 | Доступ: свободный | Студентов: 1180 / 358 | Оценка: 4.39 / 4.28 | Длительность: 18:45:00
Специальности: Программист
Лекция 8:

Программирование приложений в CE

Пример программы AC97, использующей функции аудио API CE

Следующий пример программы звонит семь раз в колокольчик на устройстве аудио-выхода AC97. Стандартный динамик ПК или стерео-наушники можно соединить с разъемом аудио выхода на передней панели eBox, чтобы слышать вывод (разъем с символом наушников). Ядро CE также должно быть собрано с выбранным драйвером аудио устройства BSP. Вызов API PlaySound проигрывает за раз только один звуковой файл. С помощью функции Sleep добавляется задержка, чтобы разделить звуки и создать паузу перед выходом программы и закрытием консольного окна. Этот пример использует встроенный звуковой файл Windows "EXCLAM". С небольшими изменениями вы сможете воспроизвести любой wav-файл пользователя.

Для более сложных звуков и микширования используйте вызовы API waveout. Вызовы API wavein можно использовать для записи звуков с помощью микрофона ПК. Аудио звуки будут немного искажены, когда вы соединяетесь с отладчиком, так как он все замедляет, особенно, когда выводятся отладочные сообщения или один из удаленных инструментов соединяется с устройством. Примеры исходного кода, использующего функции API wavein и waveout можно найти в подкаталоге \SDK\SAMPLES\AUDIO.

// Playsound.cpp : Определяет точку входа для консольного приложения.
//

#include "stdafx.h"

int _tmain(int argc, TCHAR *argv[], TCHAR *envp[])
{
	int i;
    _tprintf(_T("Hello Audio World!\n"));
	Sleep(1000);
	// Воспроизводит файл WAV семь раз на аудио-устройстве 
	for (i=0; i<7; i++)
	{
	// Использует запись в реестре для звукового файла EXCLAM
	// Можно заменить путем доступа к своему файлу wav
	// если добавить | SND_FILENAME в третий аргумент 
		PlaySound (TEXT("EXCLAM"), NULL, SND_SYNC);
		Sleep(500);
	}
	Sleep(1500);
    return 0;
}

Базовое приложение Windows, пример Hello World

В этом примере программы создается приложение Windows (на основе GUI), а не простое текстовое консольное приложение. Важно понимать, что обычная программа Windows отличается от других программных моделей тем, что прикладная программа запрашивает ввод из операционной системы с помощью явных вызовов API, таких как getc и putc. В прикладной программе Windows операционная система уведомляет приложение, что доступен ввод клавиатуры и мыши, посылая приложению сообщения. Сообщения автоматически генерируются операционной системой, когда возникает активность мыши или клавиатуры, связанная с этим окном. Щелчок на кнопке или выбор пункта меню с помощью мыши генерирует сообщение. Приложения Windows написаны для ответа на эти последовательности сообщений от операционной системы. Сообщения распознаются прикладной программой с помощью последовательностей предопределенных констант, таких как WM_CREATE и WM_DESTROY. Этот процесс одинаков как в настольных операционных системах Windows, так и в Windows Embedded CE.

Стиль программирования, традиционно используемый в программах Windows и в этом примере программы, состоит в использовании префикса для имени каждой переменной из символов нижнего регистра, который указывает тип переменной. Это улучшает удобочитаемость кода, когда вы понимаете значение префиксов, так как не нужно рыться в множестве файлов в поисках объявления переменной, чтобы определить ее тип. Наиболее часто используемые префиксы венгерской нотации показаны в таблице 8.3. Префиксы можно объединять. Например, lpsz является длинным указателем на строку. Чтобы облегчить идентификацию префикса в нижнем регистре, первый символ имени переменной обычно записывается в верхнем регистре. В качестве примера, szTitle, одна из первых переменных в примере программы является строкой, которая содержит заголовок.

Таблица 8.3. Обычные префиксы венгерской нотации, используемые для переменных в программах Windows
Тип переменной Венгерский префикс
Integer i или n
Word (16-bit) w или s
Double Word (32-bit) dw
Long (32-bit signed) l
Char c
String (с нулем на конце) sz
Pointer p
Long Pointer lp
Handle h
Window Handle hwnd
Размер структуры cb

Приложение Windows в следующем примере кода основывается на коде, автоматически генерируемом CE, когда создается простое приложение Windows "Hello World". При рассмотрении примера кода обратите внимание, что все программы Windows имеют точку входа программы WinMain. При входе приложение должно зарегистрировать свой основной класс окна. В примере кода это делается в MyRegisterClass. Определяются различные параметры стиля окна. Все окна являются экземплярами класса окна.

Затем приложение должно создать, вывести и обновить новое окно. В примере программы эта операция выполняется в InitInstance.

После того как процедура WinMain регистрирует, создает, выводит, и обновляет основное окно, она входит в цикл сообщений окон. В примере программы найдите цикл while в конце WinMain. Это критическая часть любого приложения Windows. Она остается в цикле сообщений While, пока выполняется приложение. Функция GetMessage блокируется, пока не будет доступно новое сообщение из операционной системы. TranslateMessage транслирует соответствующие клавиатурные сообщения в символьное сообщение. Функция DispatchMessage уведомляет операционную систему о передаче нового сообщения в соответствующее окно в приложении. Приложение остается в цикле while, пока не будет получено сообщение WM_QUIT. Это специальное сообщение заставляет GetMessage вернуть значение ноль и завершить цикл while, и приложение завершается.

Когда посылается каждое новое сообщение, операционная система автоматически активирует процедуру обратного вызова, WndProc. ОС передает в нее новое сообщение. Найдите эту функцию в конце кода программы примера. Функция обратного вызова приложения Windows (т.е., WndProc ) обрабатывает каждое сообщение, декодируя его в операторе switch. Операции, требуемые для каждого сообщения, кодируются в каждом случае. После обработки сообщения функция обратного вызова возвращает управление.

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

Большая часть усилий при разработке новой прикладной программы Windows тратится на кодирование процедуры обратного вызова Windows приложения, и код, требуемый для обработки каждого сообщения. Можно использовать графические инструменты для проектирования GUI и автоматической генерации шаблонов кода Windows для программ C/C++ и C#. Разработчику по прежнему необходимо вручную ввести код для реализации действий, требуемых для реакции на каждое сообщение окна.

// WinAPP.cpp : Определяет точку входа для приложения.
//
#include "stdafx.h"
#include "resource.h"

#define MAX_LOADSTRING 100

// Глобальные переменные:
HINSTANCE hInst;                      // current instance
TCHAR szTitle[MAX_LOADSTRING];        // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING];  // The title bar text

// Предварительные объявления функций, включенных в этот модуль кода:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR     lpCmdLine,
                     int       nCmdShow)
{
    // Что делать: Поместите здесь код.
    MSG msg;
    HACCEL hAccelTable;

    // Инициализация глобальных строк 
    LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadString(hInstance, IDC_WinAPP, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // Выполнить инициализацию приложения:
    if (!InitInstance (hInstance, nCmdShow)) 
    {
        return FALSE;
    }

    hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_WinAPP);

    // Основной цикл сообщений:
    while (GetMessage(&msg, NULL, 0, 0)) 
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return msg.wParam;
}
//
//  FUNCTION: MyRegisterClass()
//
//  Назначение: Регистрирует класс окна.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASS wc;

    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = (WNDPROC) WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = 0;
    wc.hCursor = 0;
    wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName = 0;
    wc.lpszClassName = szWindowClass;

    return RegisterClass(&wc);
}
//
//   FUNCTION: InitInstance(HANDLE, int)
//
//   Назначение: Сохраняет handle экземпляра и создает основное окно 
//
//   COMMENTS:
//
//        В этой функции мы сохраняем handle экземпляра в глобальной 
//        переменной и создаем и выводим основное окно программы.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; // Store instance handle in our global variable

   hWnd = CreateWindow(szWindowClass, szTitle, WS_VISIBLE,
      0, 0, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}
//
//  FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
//
//  Назначение:  Обрабатывает сообщения для основного окна.
//
//  WM_COMMAND  - обработка меню приложения 
//  WM_PAINT    - отрисовка основного окна 
//  WM_DESTROY  - отправка сообщения о завершении и возврат управления 
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;
    TCHAR szHello[MAX_LOADSTRING];
    LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);

    switch (message) 
    {
        case WM_PAINT:
            hdc = BeginPaint(hWnd, &ps);
// Сделать: Добавить здесь какой-нибудь дополнительный код
// для рисования...
            RECT rt;
            GetClientRect(hWnd, &rt);
            DrawText(hdc, szHello, _tcslen(szHello), &rt, DT_CENTER);
            EndPaint(hWnd, &ps);
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
   }
   return 0;
}