Глава 7. Разработка программ для Windows СЕ

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

В целом можно отметить, что компания Microsoft как всегда оказалась на высоте. Как показала практика, все что угодно можно довести до приемлемого уровня, если вложить в это соответствующие деньги. Это относится и к Windows СЕ — при наличии необходимых средств не составило труда нанять нужное количество квалифицированных разработчиков и создать для Windows СЕ качественное программное обеспечение — нормальную среду разработки, нормальную документацию и т. д. Нельзя не учитывать также и немалый опыт разработки операционных систем, накопленный компанией Microsoft. Поэтому можно отметить, что система Windows СЕ получилась весьма удачной и разрабатывать для нее программы — одно удовольствие. К чему мы сейчас и приступим.
Так же как и в начале предыдущей главы, нужно отметить, что эта глава книги не создана для замены "классических" книг по программированию. Серьезное описание программирования под Windows займет не один том, и физически нельзя уложить такое количество информации в одну главу. Да это и не нужно. Задача этой книги — дать читателю возможность быстрого и относительно легкого старта. С помощью информации из данной главы читатель сможет легко создать работающую программу для Windows СЕ, попробовать различные методы и технологии. Это может быть полезно как новичку в программировании, так и человеку, который уже программировал для Windows, но хочет узнать больше о специфике разработки программ для карманных устройств. А тем, кто пожелает знать еще больше, можно предложить специальную литературу, которой сейчас очень много.
Из имеющейся сейчас литературы можно порекомендовать следующие книги.

Так же как и в программировании для Palm OS, можно с сожалением отметить, что книг, специально описывающих разработку программ для Windows СЕ, на русский язык не переведено. Список англоязычной литературы приведен в табл. 7.1.

Таблица 7.1. Англоязычные книги по программированию для Windows СЕ

Название Стоимость Описание
Douglas Boling $41,99 Объем: 998 страниц.
Programming Microsoft Windows CE    Издательство: Microsoft Press, ISBN: 073561 4431
Nick Grattan, Marshall Brain, Nick Gratten $34,99 Объем: 512 страниц.
Windows CE 3.0 Application Programming    Издательство: Prentice Hall PTR, ISBN: 01 30255920.
     В книгу включен CD-ROM
Robert Burdick Нет данных Объем: 460 страниц.
Essential Windows CE Application Programming    Издательство: John Wiley & Sons, ISBN: 0471 327476
Chris Muench, Randolph Kath $34,97 Объем: 624 страницы.
The Windows CE Technology Tutorial: Windows Powered Solutions for the Developer    Издательство: Addison-Wesley Pub Co, ISBN: 0201 61 6424
John Murray $20,99 Объем: 291 страница.
Inside Microsoft Windows CE    Издательство: Microsoft Press, ISBN: 1572318546
Microsoft Windows Ce Developer's Kit (Microsoft Professional Editions) $69,99 Объем: 1440 страниц.

Издательство: Microsoft Press, ISBN: 07356061 96

Опять-таки, можно с сожалением отметить высокий уровень цен на эту литературу и отсутствие перевода хотя бы одной из этих книг на русский язык.

7.1. Среда разработки для Windows CE
Как уже упоминалось выше, для разработки программ под Windows CE используется среда разработки eMbedded Visual Studio, которая является модификацией Visual Studio, используемой для разработки под "обычную" систему Windows.
Среди отличительных особенностей eMbedded Visual Studio можно отметить два основных момента.

К сожалению, найти eMbedded Visual Studio на компакт-дисках практически невозможно. Единственный способ — переписать EVS с сайта Microsoft, тем более, что среда разработки — бесплатная. Для разработки программ, работающих под распространенной сейчас системой Windows СЕ 3.0, подойдет eMbedded Visual Tools 3.0, взять которую можно бесплатно с сайта Microsoft по следующему адресу: http://download.microsoft.com/download/wince/lnstall/ 3.0/W9X2K/EN-US/EN_WINCE_EMBDVTOOLS30.exe. Размер дистрибутива, к сожалению, не маленький — 304 Мбайт. Во время установки программа запросит ключ, который можно бесплатно взять на странице http://www.microsoft.com/mobile/downloads/emvt30.asp.
Те, кто захотят разрабатывать программы для более новой версии PocketPC 2002, должны будут скачать последний SDK по следующему адресу: http://download.microsoft.com/download/pocketpc/Install/2002/NT5XP/ EN-US/PPC2002_SDK.exe. Размер этого файла составляет 67 Мбайт.

7.1.1. Сторонние дополнительные модули
Существует много дополнительных модулей для Visual Studio, три из которых значительно облегчают работу и достойны отдельного упоминания.

WndTabs
Удобный модуль, отображающей в нижней части окна Visual Studio список открытых файлов.

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

Visual Assist
Самый удобный и эффективный из различных плагинов. Возможности Visual Assist весьма велики, некоторые из них стоит рассмотреть отдельно.

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

MessageBox creator
Гораздо более простой, но в то же время иногда полезный плагин. Как известно, в Windows для вывода сообщений используется функция MessageBox, которая может принимать большое количество параметров: количество кнопок, текст сообщения, текст заголовка, варианты ответа и т. д.
Запомнить все это сложно, и для облегчения создания нужного MessageBox был создан плагин, который позволяет пользователю задать все возможные варианты параметров функции MessageBox и тут же проверить их в действии.
К примеру, можно создать MessageBox с вопросом "Нравится ли Вам Windows", вопросительным знаком и вариантами ответа "да" и "нет". Заодно можно сразу задать создание кода для проверки условия выбора. Задание параметров происходит в течение нескольких секунд, после чего при нажатии кнопки Copy to Clipboard and Close был сгенерирован следующий код.

if ( : :MessageBox (NULL, _T ( "Нравится ли Вам Windows"), _Т ("Вопрос: ") , MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON1) == IDYES)
{
}

Только набор этого кода вручную с клавиатуры потребовал бы гораздо больше времени, чем интерактивное задание нескольких параметров в окне этого весьма удобного плагина.
Стоит отметить использование макросов _то для описания текстовых констант, обеспечивающих переносимость Unicode- и He-Unicode-версий программ, что также актуально для Windows СЕ. Подробнее об этом будет рассказано ниже.

7.2. Написание простейшей программы для СЕ
Рассмотрим по шагам процесс создания простейшей программы для Windows СЕ. Будем считать, что среда разработки eMbedded Visual Studio уже установлена, и к ней поставлен соответствующий SDK.

7.2.1. Создание новой программы
Процесс создания программы весьма прост.
Выбираем в меню File пункт New. Появляется окно, подобное показанному на.

Возможные варианты создаваемых программ здесь следующие.

Собственно говоря, среда разработки eMbedded Visual Studio позволяет создавать собственные мастера, которые могут быть использованы вместе со стандартными. Их можно создавать самостоятельно или найти уже готовые в Интернете. Например, разработчик игр может создать свой мастер, который по ряду параметров создает базовый каркас программы, уже охватывающий базовые игровые ситуации (так, что останется только вписать имя разработчика, и можно сразу продавать уже готовую игру (шутка)). Поэтому количество доступных вариантов в окне создания проекта может быть несколько больше.
Естественно, что, помимо этих пунктов, в окне создания проекта нужно задать путь в каталог, где он будет размещен, и наименование проекта. Стоит отметить, что к выбору названия проекта следует подходить обдуманно, т. к. потом поменять его будет уже почти невозможно — многие созданные классы и ресурсы будут содержать в своем названии это имя.

7.2.2. Исследование простейшей программы, написанной на WinAPI
Как уже упоминалось, написание программ с использованием только средств WinAPI здесь рассматриваться не будет. Но одну программу рассмотреть все же стоит, чтобы иметь хотя бы некоторое представление о том, как работает программа, созданная для Windows.
Кроме этого раздела, разработка программ только с использованием WinAPI в этой книге больше нигде рассматриваться не будет. Здесь это приведено лишь "для общего развития", чтобы смысл работы программы под Windows был более понятен. Те, кто хочет сразу приступить к созданию программ, могут совершенно безболезненно пропустить этот раздел и вернуться к нему при необходимости позже. А те, кому эта теория интересна, могут читать дальше.
Создадим новый проект, выбрав вариант WCE Application — A typical "Hello world application". В качестве имени проекта выберем API_test. Рассмотрим проект, который сгенерировал Visual Studio.
Рассмотрим последовательно основные файлы и созданные в них функции.

API_test.cpp
Этот файл содержит все функции, отвечающие за работу программы. Рассмотрим основные функции и разберем их назначение более подробно.

Функция WinMain
Вид этой функции показан в листинге 7.1. После листинга мы рассмотрим этот код более подробно.

Листинг 7.1. Функция WinMain

int WINAPI WinMain(HINSTANCE hlnstance, HINSTANCE hPrevInstance,
LPTSTR IpCmdLine, int nCmdShow)
{
MSG msg;
HACCEL hAccelTable;
// Первоначальная инициализация программы:
if (!Initlnstance (hlnstance, nCmdShow))
{
// Загрузка акселераторов:
hAccelTable = LoadAccelerators (hlnstance, (LPCTSTR) IDC_API_TEST)
// Основной цикл обработки сообщений:
while (GetMessage(&msg, NULL, 0, 0))
{
if ( ITranslateAccelerator (msg.hwnd, hAccelTable, &msg) )
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
}
return msg.wParam;
}

Функция winMain является основной функцией, работающей с программой. С этой функцией программа начинает и завершает свою работу, и в ней же "крутится" цикл обработки сообщений, приходящих к программе.
Во время запуска Windows передает этой функции следующие параметры.

Функция Initlnstance
Функция init'ihstance отвечает за создание программы, ее вид показан в листинге 7.2. После листинга мы рассмотрим этот код более подробно.

Листинг 7.2. Функция Initlnstance

BOOL Initlnstance(HINSTANCE hlnstance, int nCmdShow)
{
HWND hWnd;
// Название заголовка программы
TCHAR szTitle[MAX_LOADSTRING];
// Название класса окна:
TCHAR szWindowClass[MAX_LOADSTRING];
// Сохранить указатель в глобальной переменной
hlnst = hlnstance;
// Загрузка из ресурса строки с названием класса
LoadString(hlnstance, IDC_API__TEST, szWindowClass, MAX_LOADSTRING)
MyRegisterClass(hlnstance, szWindowClass);
// Загрузка из ресурса строки с заголовком программы
LoadString(hlnstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
// Создание окна
hWnd = CreateWindowfszWindowClass, szTitle, WSJVISIBLE,
CWJJSEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, NULL, NULL, hlnstance, NULL);
if (IhWnd) // не удалось создать окно
{
return FALSE; // аварийное завершение программы
}
// Показать окно
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
// Показать тулбар
if (hwndCB)
CoirniandBar_Show(hwndCB, TRUE);
return TRUE;
}

Основными действиями, выполняющимися в этой функции, являются следующие.

Интересно также отметить использование функции Loadstring. Эта функция загружает строку из соответствующего ресурса. В Windows все объекты программы (формы, элементы управления, строки, списки акселераторов и т. д.) могут храниться в специальном разделе ресурсов. Для просмотра ресурсов программы необходимо в Visual Studio выбрать вкладку ResourceView в левом окне рабочего пространства. Там видны уже созданные ресурсы различных видов — диалоговое окно, таблица строк и т. д.
Естественно, что можно использовать строки и непосредственно в программе, но признаком "хорошего тона" является вынесение всех строк в ресурс, и загрузка их оттуда. Это позволит быстро изменять в будущем необходимые строки и, в частности, легко производить локализацию программы на другой язык.

Функция MyRegisterClass
Эта функция отвечает за регистрацию программы для обеспечения корректной работы в Windows, ее вид показан в листинге 7.3. После листинга мы рассмотрим этот код более подробно.

Листинг 7.3. Функция MyRegisterClass

ATOM MyRegisterClass (HINSTANCE hlnstance, LPTSTR szWindowClass)
{
WNDCLASS we;
we. style = CS_HREDRAW | CSJ/REDRAW;
we. IpfnWndProc = (WNDPROC) WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hlnstance = hlnstance;
wc.hlcon = Loadlcon (hlnstance, MAKEINTRESOURCE (IDI_API_TEST) ) ;
wc.hCursor = 0;
wc.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
we . Ips zMenuName = 0;
wc.lpszClassName = szWindowdass;
return RegisterClass (iwc) ;
}

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

Функция WndProc
Эта функция, в принципе, является главной для нас, поскольку именно в ней выполняется основной цикл обработки сообщений во время работы программы. Укороченный вид этой функции показан в листинге 7.4.

Листинг 7.4. Функция WndProc

LRESULT CALLBACK WndProc (HWND hWnd, UINT message,
WPARAM wParam, LPARAM IParam)
{
....
switch (message)
{
case WM_COMMAND:
// Обработка сообщений от меню
wmld = LOWORD (wParam) ;
wmEvent = HIWORD (wParam) ;
switch (wmld)
{
case IDM_HELP_ABOUT:
// Обработка выбора меню About
...
break;
case IDM_FILE_EXIT:
// Обработка выбора меню
Exit DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message,
wParam, IParam) ;
}
break; case WM_CREATE:
// Создание окна, выполнение различных действий
hwndCB = CommandBar_Create(hlnst, hWnd, 1) ;
...
break;
case WM_PAINT:
// Перерисовка окна
...
break;
case WM_DESTROY:
// Уничтожение окна, выполнение различных действий
CoramandBar_Destroy(hwndCB)
...

break;
default:
return DefWindowProc(hWnd, message, wParam, IParam};
}
return 0;
}

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

API_test.h
Этот файл содержит всего лишь одну строчку, подключающую идентификаторы из файла ресурсов:
#include "resource.h"
Как уже было показано, ресурсы широко используются в программе — в них хранятся многие важные элементы (строки, значки программы и т. д.).

Описание ресурсов
Файл ресурсов хранится в файле API_test.rc. Вид некоторых фрагментов этого файла приведен в листинге 7.5.

Листинг 7.5. Описания ресурсов в файле API_test.rc

#include "resource.h"
// Описания значков
IDI API TEST ICON DISCARDABLE "API test.ICO"
// Описания меню
//
IDM_MENU MENU DISCARDABLE BEGIN
POPUP "SFile"
BEGIN
MENUITEM "E&xit", IDM_FILE_EXIT
END
POPUP "SHelp"
BEGIN
MENUITEM "SAbout", IDM_HELP_ABOUT
END
END
// Описания диалоговых окон
//
IDD_ABOUTBOX DIALOGEX 0, 0, 125, 55
STYLE DS_MODALFRAME | WS_POPUP I WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_CAPTIONOKBTN
CAPTION "About API_test"
FONT 8, "System"
BEGIN
ICON IDI_API_TEST,IDC_STATIC,11,17,20,20
LTEXT "API_test Version 1.0",IDC_STATIC,38,10,70,8, SS_NOPREFIX
LTEXT "Copyright (C) 2002",IDC_STATIC,38,25,70,8
END
// Таблица строк
//
STRINGTABLE DISCARDABLE
BEGIN
IDC_API_TEST "APIJIEST"
IDS_APP_TITLE "API_test"
IDS_HELLO "Hello World!"
END

Видно, что все ресурсы хранятся в обыкновенном текстовом файле, структура которого является довольно простой. К счастью, редактирование ресурсов "вручную" вовсе не обязательно — eMbedded Visual Studio имеет полнофункциональный редактор ресурсов, который делает все это самостоятельно.
Также интересно отметить описания констант в файле resource.h:

#define IDS_APP_TITLE 1
tdefine IDS_HELLO 2
#define IDC_API_TEST 3
fdefine IDI_API_TEST 101
#define IDM_MENU 102
#define IDD_ABOUTBOX 103
#define IDM_FILE_EXIT 40002
#define IDM_HELP_ABOUT 40003

Все эти строки добавляются средой разработки Visual Studio самостоятельно.
На этом мы заканчиваем рассмотрение программ, создаваемых только при использовании WinAPI. Те, кто интересуется этим вопросом, могут обратиться к уже упомянутой книге Ч. Петзолда. Вся эта книга посвящена именно программированию с использованием WinAPI.
Особо интересующиеся могут еще сравнить текст вышеприведенной программы с текстом программы для Palm OS и найти там немало схожих моментов. Самые "продвинутые" читатели могут даже попытаться портировать библиотеку MFC на Palm OS (можно сказать однозначно — тому, кто это сделает, безбедное существование на всю жизнь обеспечено, но пока еще никто этого не делал).

7.2.3. Создание простейшей программы, использующей MFC
Рассмотрим теперь процесс создания программ при помощи MFC. Благодаря возможностям MFC и возможностям Visual Studio этот процесс гораздо более легкий и приятный, чем разработка программы предыдущим методом. Дальше мы будем рассматривать именно программы, использующие MFC.

Зачем нужна MFC
Библиотека классов MFC (Microsoft Foundation Classes) была создана компанией Microsoft именно в целях облегчения процесса разработки программного обеспечения. Библиотека MFC представляет собой наборы классов и функций, являющихся "надстройкой" над стандартными средствами WinAPI. Сама структура MFC довольно сложна, ряд статей об этом (на русском языке) можно найти на замечательном сайте для разработчиков www.rsdn.ru.
Из преимуществ MFC можно выделить как минимум следующие:

Конечно, у MFC есть и недостаток — получаемые программы имеют несколько больший размер, но чаще всего это не столь критично. Современные параметры компьютеров (и карманных, в том числе) таковы, что разница, например, между 20 и 40 Кбайт размера программы уже не ощущается.
Нужно отметить, что в настоящее время существует очень удобная библиотека WTL (Windows Template Library), основанная на использовании шаблонов. WTL аналогична MFC, но получаемый код оказывается гораздо компактнее и эффективнее. К сожалению, официальной версии WTL для Windows СЕ пока не существует, хотя в Интернете можно найти портированную на Windows СЕ версию. Впрочем, учитывая растущую популярность Windows СЕ, можно предположить, что со временем WTL для Windows СЕ все-таки будет создана.
Следует учитывать, что работать с MFC не просто, а очень просто. Писать программы таким способом немногим сложнее, чем с помощью Visual Basic. А что касается того, "как это работает", то в большинстве случаев об этом можно даже не задумываться. Но, тем не менее, если потребуется более глубоко (и эффективно) использовать MFC, то придется слегка разобраться с особенностью ее построения. При этом необходимо знать язык C++ и хотя бы основные моменты объектно-ориентированного программирования. Дело в том, что вся библиотека MFC построена на основе объектно-ориентированного подхода, и для понимания многих моментов необходимо иметь об этом хотя бы базовые представления. Например, не должно вызывать сложностей использование хотя бы таких терминов, как наследование, конструктор и деструктор. Например, не зная ООП, трудно понять, почему в классе cstdioFile описаны только три функции и не описаны многие другие, например, функция открытия файла. А на самом деле, класс cstdioFile наследуется от класса cFiie, так что все остальные функции следует искать там. Так что, базовые знания ООП все-таки будут нужны.
А тем кто захочет серьезно изучить объектно-ориентированный подход в программировании, можно посоветовать книгу Г. Буча "Объектно-ориентированный анализ и проектирование" (эту книгу тоже можно бесплатно найти в Интернете).

Создание программы
Приступим, наконец, к созданию программы. Для начала рассмотрим создание программ более простого типа — программ, основанных на базе диалоговых окон (dialog-based). Этот тип программ является более простым в создании и модификации.
Для создания программы создадим новый проект и выберем тип приложения WCE MFC AppWizard (exe). Выберем необходимый каталог (обычно удобно создать в корне диска что-то типа каталога с названием My Projects) и введем название программы AppMFCTest. В следующем появившемся окне зададим тип программы Dialog based и выберем из раскрывающегося списка используемый язык "Английский" (русского в списке, к сожалению, нет). В следующем окне предлагается ввести название программы, отображаемое на окне (title for dialog). Можно ввести что угодно, например, My First mfc Арр. Теперь можно нажать кнопку Finish, оставив все остальные параметры по умолчанию.
Рассмотрим теперь очень кратко файлы, созданные для нас средой Visual Studio.

Теперь можно запустить программу на компиляцию. Для этого нужно выбрать активную платформу PocketPC (в меню Build выбрать Set Active Platform — Pocket PC). В этом же разделе меню можно выбрать различные конфигурации, например, задать создание программы для процессоров ARM, MIPS или SH3. Помимо этого, нужно отметить еще один вариант — Win32 Emulation. Дело в том, что в состав среды разработки входит эмулятор, отлаживать программы с помощью которого гораздо быстрее и удобнее. К тому же, использовать эмулятор можно даже в том случае, если карманный компьютер отсутствует вообще — в 90% случаев программа отображается на эмуляторе вполне корректно. Так что можно создать и отладить программу, даже не имея вообще карманного устройства, что в ряде случаев весьма удобно.
Когда все приготовления (длящиеся 5—10 секунд) закончены, можно нажимать клавишу <F7> и запускать процесс компиляции. После окончания программа автоматически записывается в Start-меню выбранного устройства, так что запустить ее на устройстве совсем не сложно.
Кстати говоря, размер получившейся программы довольно мал. Версии для ARM, MIPS и SH3 занимают 8,1, 8,7 и 8,1 Кбайт соответственно.

7.3. Развитие созданной программы
Естественно, что останавливаться только на изучении программы, созданной автоматически с помощью Visual Studio, было бы неразумно. Да и останавливаться, по большому счету, пока почти не на чем — программа, создаваемая за 20 секунд, не делает ничего особо полезного. Поэтому пойдем дальше и наполним программу действительно полезным содержанием.

7.3.1. Некоторые особенности Windows СЕ
Перед тем как осваивать дальнейшие аспекты программирования для Windows СЕ, нужно остановиться на ряде особенностей, которые являются весьма актуальными, и без понимания которых обойтись довольно сложно.

Использование Unicode
Символы Unicode представляют собой относительно новый стандарт описания наборов символов. Раньше, во времена DOS и Windows 3.1x/9x, использовались однобайтовые символы типа char, в которых коды символов ограничивались значениями от 0 до 255. Понятно, что такой объем не мог вместить всего разнообразия различных алфавитов (хотя американцы наверное были бы счастливы, если бы во всем мире говорили только на английском, тогда бы и Unicode не понадобился). При кодировании символов по стандарту Unicode используются двухбайтовые значения, и количество символов ограничено уже 65 535. Этого хватит для хранения символов любого языка, что весьма удобно. Новые операционные системы, например. Windows 2000, поддерживают Unicode, но позволяют использовать и прежнее кодирование ANSI. Операционная система Windows СЕ поддерживает только Unicode, что необходимо учитывать при написании программ.
Использование только Unicode накладывает на программу некоторые ограничения. В частности, уже невозможна работа со строками, использующими тип char. Вместо этого в Unicode введен тип wchar_t. Однако, как говорится в рекламе, "есть способ лучше", при разработке программ следует придерживаться следующих методов.

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

Листинг 7.6. Использование строк и строковых констант

// Этот код нельзя использовать в Windows CE
char c_sym; // описание одного символа
char s_str[6] = "abed"; // описание строки
MessageBox(s_str) ; // вывод строки
MessageBox( "Message output"); // вывод константной строки
// Этот код можно использовать в Windows СЕ,
//Но этот код не является переносимым
wchar t с sym; // описание одного символа
wchar_t s_str[6] = __T("abcd") ; / / описание строки
MessageBox(s str); // вывод строки
MessageBox( Т ("Message output")); // вывод константной строки
// Этот код является переносимым  
TCHAR с sym; // описание одного символа
TCHAR s_str[6] = _T("abcd"); // описание строки
MessageBox(s str); // вывод строки
MessageBox (_T ("Message output") ) ; // вывод константной строки
// Этот код также является переносимым
CString s_str = _T("abcd"); // описание строки
MessageBox (s str) ; // вывод строки

Естественно, нужно учитывать, что использование tchar возможно лишь при внутреннем применении данных в программе. Если стоит вопрос о сохранении данных, например, в файле, то лучше выбрать какой-либо конкретный формат. В противном случае может получиться так, что версия для Windows СЕ пытается сохранить файл в двухбайтовой кодировке Unicode, a версия для обычной Windows пытается прочесть этот же файл, используя однобайтные char-строки. Естественно, что при чтении файла ничего хорошего не получится.
Более подробно использование строк будет рассмотрено ниже.

Файловая система
Как и "большая" операционная система, Windows СЕ имеет полноценную файловую систему, поддерживающую длинные имена файлов и наличие каталогов и подкаталогов. Собственно говоря, это уже неплохо, поскольку другие карманные компьютеры, например, Palm или Pocket Viewer, полноценной файловой системы не имеют вообще.
Тем не менее, файловая система Windows СЕ имеет ряд особенностей. Основная из них — отсутствие в системе логических дисков, все пути начинаются сразу из корневого каталога, как показано на рис. 7.1.


Рис. 7.1. Структура файловой системы Windows CE

Вторая особенность состоит в том, что внутри папки My Documents нельзя создавать папок другого уровня вложенности.
Интересно отметить, что для хранения программ и оперативной памяти физически используется одна и та же память. В настройках Windows СЕ имеется регулятор, с помощью которого в любое время можно изменить соотношение этих значений (понятно, что больше объема доступной физической памяти этот указатель выставить нельзя). Интересно еще и то, что сама операционная система Windows СЕ "зашита" в ПЗУ карманного компьютера, поэтому оперативной памяти не занимает.

Реестр
Как и на настольном компьютере, Windows СЕ хранит многие данные в реестре (registry). Структура аналогична структуре реестра "настольных" версий Windows, с тем лишь исключением, что количество имеющихся веток несколько меньше. Да и объем хранящейся в реестре информации гораздо меньше. Собственно говоря, это и неудивительно. Например, на домашнем компьютере автора этой книги суммарный объем файлов реестра операционной системы Windows 98 составляет 8 Мбайт. Очевидно, что для карманного компьютера такой объем явно является излишним. Например, можно отметить, что в операционной системе Windows СЕ 3.0 отсутствует ветвь реестра hkey_users, т. к. система является однопользовательской.
Для редактирования реестра на карманном компьютере существуют различные утилиты, но разработчикам в этом плане несколько проще — в состав eMbedded Visual Studio входит утилита Remote Registry Editor, которая позволяет просматривать и редактировать как реестр локального компьютера, так и реестр эмулятора или реального КПК.

7.3.2. Использование различных элементов управления

Элементы Edit Box и Static Text
Настала пора дальнейшего совершенствования нашей программы. Рассмотрим для начала простейшие операции — создание обработчиков для кнопок и ввод/вывод текстовой информации.
Перед добавлением элементов на форму диалогового окна нужно учесть еще одну особенность. Дело в том, что в Windows СЕ диалоговые окна по умолчанию запускаются в полноэкранном режиме. Поэтому какой бы не был размер диалогового окна, все равно оно будет увеличено до стандартного разрешения 240x320 пикселов по вертикали. В созданном автоматически проекте диалоговое окно довольно маленькое, поэтому растянем его мышкой так, чтобы его размер примерно соответствовал экрану КПК. Конкретный размер указать сложно, т. к. показываемые eMbedded Visual Studio размеры не соответствуют реальным пикселам на экране КПК.
Создадим несложную программу, выполняющую простую операцию — преобразование валюты из рублей в доллары. Рассмотрим все операции по шагам.

  1. Создание необходимых ресурсов.
  2. Создание обработчика для кнопки. Для этого достаточно дважды нажать на кнопку, и в появившемся окне с названием будущей функции просто нажать ОК. В обработчике CAppMFCTestoig будет создана и автоматически открыта в редакторе функция onButtonCount. Когда пользователь нажмет на кнопку, эта функция будет вызвана.
  3. Обработка результатов.
    Здесь мы займемся написанием кода, который и выполняет основную функцию программы — получение данных из двух полей ввода и вывод результата в третье поле для вывода.
    Рассмотрим процесс создания обработчиков по шагам.

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

Листинг 7.7. Вычисление курса валюты с использованием MFC

// Занести значения из полей ввода в соответствующие переменные
UpdateData();
// Вычислить результат
m_Result = m_SumSrc / m_Rate;
// Занести значения обратно
UpdateData(FALSE);

Функция UpdateData нужна для чтения/записи используемых нами переменных. Дело в том, что созданные в Class Wizard переменные вначале не содержат каких-либо осмысленных значений. Для занесения этих значений как раз и используется функция UpdateData. При вызове без параметров она заносит значения из элементов управления в переменные, а при вызове с параметром false происходит обратный процесс — занесение значений из переменных в соответствующие поля на экране. Стоит отметить, что все необходимые преобразования (например, из текста поля ввода в вещественное значение типа double) MFC выполняет автоматически, совершенно "прозрачно" для пользователя.

Закончив программу, уже можно сделать некоторые выводы. Видно, что процесс создания законченной программы занимает гораздо меньше времени, чем при написании такой же программы для Palm. Если рассмотреть весь процесс создания этой программы по шагам, то он будет следующий:

  1. Создать новый проект, ввести тип и имя проекта.
  2. Разместить (мышкой) в редакторе соответствующие кнопки и поля, задать идентификаторы.
  3. Запустить Class Wizard, ввести соответствующие переменные.
  4. Создать обработчик кнопки (двойным нажатием на нее) и ввести код из шести строк.

Даже у самого медлительного человека создание такой программы займет (при достаточном опыте) не больше 5 минут. Ни на одном из карманных компьютеров другого типа создание программы за такой короткий срок принципиально невозможно. Можно сравнить листинг 7.6 с листингом 6.12, в котором похожая операция производилась для Palm OS.
Стоит также отметить, что получившийся код является переносимым с версией для Windows.
Полученный проект находится на прилагаемом к книге компакт-диске в подкаталоге AppMFCTestl.

Более сложные элементы управления
Будем модифицировать далее нашу программу. При детальном рассмотрении видно, что полученная программа имеет как минимум два недостатка.

Вначале исправим первый недостаток. При хранении результата в формате double вывод какого-либо иного значения невозможен, поэтому воспользуемся возможностями работы со строками. Запустим Class Wizard, в нем удалим переменную m_Resuit и создадим вместо нее переменную m_Resuitstr типа cstring. Используемый код чуть усложнится, зато подобный способ вывода результата является гораздо более гибким.
Измененный код обработчика показан в листинге 7.8.

Листинг 7.8. Вычисление курса валют

// Занести значения в соответствующие переменные
UpdateData();
// Сформировать результат
m_ResultStr.Format( Т("Sum of dollars: %.2f USD"), m SumSrc / m Rate);
// Занести значения обратно
UpdateData(FALSE);

Основным в этом коде является использование функции Format, которая позволяет сформировать любую строку необходимым образом. Параметры этой функции соответствуют аналогичным параметрам функции sprintf, входящей в стандарт C++, более подробно о функции Format можно прочитать в MSDN или в прилагаемом к eMbedded Visual Studio SDK.
Теперь выдаваемый результат гораздо более приятен на вид: профамма формирует ответ в виде "Sum of dollars: 3.17 usd", что уже вполне неплохо.

Раскрывающиеся списки (Combo Box)
Теперь займемся устранением второго недостатка — поддержка только одной валюты. Для выбора валюты добавим в программу раскрывающийся список с различными вариантами. Пусть для начала будут доступны три варианта — доллар, евро и немецкая марка.
Рассмотрим создание профаммы по шагам.

  1. Добавляем на форму раскрывающийся список (combo box) и задаем ему идентификатор idc_combo_ctype. В свойствах списка снимаем флажок Sort и задаем тип Drop List. Значение Drop List указывает на то, что текст в раскрывающемся списке нельзя редактировать, а можно только выбирать предлагаемые значения.
  2. Добавляем в профамму три переменные для хранения курсов валют с названиями m_TaxUSD, mjraxEUR, mjraxDM. Для добавления переменных необходимо во вкладке ClassView Visual Studio нажать правой кнопкой мыши на наименование класса CAppMFCTestoig и в контекстном меню выбрать Add Member Variable. Нужно ввести тип значений double. Собственно говоря, эти значения можно добавить и самостоятельно, для чего нужно открыть в Visual Studio файл AppMFCTestDlg.h двойным щелчком на названии класса CAppMFCTestoig в той же вкладке ClassView.
  3. Инициализируем переменные в конструкторе класса CAppMFCTestoig. Для примера были заданы следующие значения:

    m_TaxUSD = 31.2; mJTaxEUR = 30.90; mjraxDM = 15.0;
  4. Создаем переменную для работы с сотЬоВох. Для этого запускаем ClassWizard и уже известным способом добавляем переменную с названием m_comboCurType, но тип переменной задаем не Value, a control. При этом в класс cAppMFCTestoig должна добавиться переменная типа ccomboBox, связанная с нашим раскрывающимся списком.
  5. Инициализируем раскрывающийся список. Для этого воспользуемся функцией OninitDialog, которая уже создавалась при автоматической генерации текста программы. Код инициализации будет показан ниже.
  6. Модифицируем обработчик соответствующим образом.

Листинг 7.9. Доработанная программа вычисления курса валют

// Конструктор класса CAppMFCTestDlg
CAppMFCTestDlg::CAppMFCTestDlg(CWhd* pParent /*=NULLV)
: CDialog(CAppMFCTestDlg::IDD, pParent)
{
...
// Начальная инициализация значений
mJTaxUSD = 31.20;
m_TaxEUR = 30.90;
m_TaxDM = 15.00;
}
// Функция инициализации диалогового окна

BOOL CAppMFCTestDlg::OninitDialog()
{
CDialog::OninitDialog();
...
// Занесение значений в ComboBox
const int ind_USD = m_ComboCurType.AddString(_T("USD")),
ind_EUR = m_ComboCurType.AddString(_T("Euro"),
ind_DM = m_ComboCurType.AddString(_T("DM"));
// Занесение типов соответствующих значений
m_ComboCurType.SetltemData(ind_USD, TYPE_USD);
m_ComboCurType.SetltemData(ind_EUR, TYPE_EOR);
m_ComboCurType.SetltemData(ind_DM, TYPE_DM);
// Сделать первый элемент текущим
m_ComboCurType.SetCurSel(0);
return TRUE;
}
// Вычислить значение
void CAppMFCTestDlg: :OnButtonCount ()
{
// Занести значения в соответствующие переменные
UpdateData ( ) ;
// Получить индекс текущего выделенного элемента в списке
const int index = m_ComboCurType.GetCurSel ( ) ;
// Получить тип выделенного элемента
const DWORD type = m_ComboCurType. GetltemData (index) ;
// Сформировать результат
switch (type)
{
case TYPE_USD:
m_ResultStr. Format (__T("Sum of dollars: %.2f USD"),
m_SumSrc / mJTaxUSD) ;
break; case TYPE_EUR:
m_ResultStr.Format (_T ("Sum of euro: %.2f EUR"),
m_SumSrc / m_TaxEUR) ;
break; case TYPE_DM:
m_ResultStr. Format (_T ( "Sum of DM: %.2f"),
m_SumSrc / m_TaxDM) ;
break;
default: // ошибка в программе
ASSERT (1) ;
// Занести значения обратно
UpdateData (FALSE) ;
}

На некоторых фрагментах кода стоит остановиться более подробно.

Таблицы
Рассмотрим теперь использование более сложного элемента List control. Этот элемент имеет довольно большие возможности. Он позволяет выводить элементы в виде таблицы, в виде списка текстовых записей или в виде списка значков. Рассмотрим здесь использование этого элемента в виде таблицы.
Как и в предыдущем случае, рассмотрим создание программы по шагам.

  1. Создаем программу с названием ListCtrlTest, аналогично предыдущему методу. В созданное диалоговое окно помещаем элемент List Control, задаем ему идентификатор idc_test_list и с помощью ClassWizard создаем переменную m_Listctri типа CListctri. Как это делать, уже описывалось выше, так что подробно останавливаться на этом не будем.
  2. Для формирования таблицы добавим код инициализации в функцию OninitDiaiog. В качестве примера использования таблицы сформируем таблицу умножения. А поскольку мы все-таки занимаемся программированием, то выведем таблицу умножения в шестнадцатеричном виде. Необходимый для занесения значений код показан в листинге 7.10.

Листинг 7.10. Инициализация элемента List Control

// Инициализация таблицы
const int ELEMS_NMB =15; // размерность таблицы
// Добавляем колонки
int p;
for(p=0; p<ELEMS_NMB; p++)
{
CString str;
str. Format (_T ( "%X" ), p+1);
m_ListCtrl.InsertColumn(p, str, LVCFMT_CENTER, 28);
}
// Добавление значений
for(p=0; p<ELEMS_NMB;p++)
{
// Сформировать добавляемый текст
CString str;
str. Format (_T ("%X") , p+1);
// Сформировать первый элемент строки
LVTTEM item_info;
item info.iltem = p;
item_info. iSubltem = 0;
item_info.mask = LVIF__TEXT;
item_info.pszText = str.GetBuffer (str.GetLength ())
m_ListCtrl. Insertltem(&item_info) ;
// Добавить остальные элементы строки
for(int j=l; j<ELEMS_NMB;
// Сформировать добавляемый текст
str. Format (_T( "IX") , (p+1) * (j+1) ) ;
item_info.iSubItem = j;
item_info.pszText = str.GetBuffer (str.GetLength ());
m_ListCtrl. Setitem (&item_inf о ) ;
}
}

Рассмотрим некоторые части кода более подробно.
Для инициализации таблицы необходимо выполнить два основных действия.

  1. Добавить необходимое количество колонок. Добавление колонки происходит с помощью функции insertcoiumn. В качестве параметров нужно указать индекс колонки, ее текст, выравнивание текста в колонке и ее ширину. Для формирования нужного текста используется уже знакомая функция Format класса CString.
  2. Занесение значений производится с помощью двух функций insertitem и setitem класса CListctri. При занесении первого элемента в строке, он добавляется с помощью функции insertitem, а остальные элементы строки вставляются с помощью функции Setitem. При использовании этих функций необходимо заполнить основные поля структуры lvitem — индексы строки и подстроки, указатель на текстовую строку и тип элемента lvif_text, указывающий на то, что это поле является текстовым.

На этом рассмотрение использования элемента List control завершается.
Созданная программа представлена на прилагаемом к книге компакт-диске в каталоге dev_CE \ListCtrlTest.

7.3.3. Работа с элементами управления без использования MFC
К сожалению, рассмотреть все особенности использования различных элементов управления в этой книге не представляется возможным — для этого необходим гораздо больший объем, и в пределах одной главы просто невозможно рассмотреть все тонкости и особенности программирования для Windows. Но все-таки стоит еще раз коснуться разработки программ без использования MFC. Для примера рассмотрим формирование шестнадцатеричной таблицы умножения из предыдущего примера в случае написания этой программы только с использованием WinAPI.
Соответствующий код приведен в листинге 7.11.

Листинг 7.11. Инициализация элемента List iContrl седствами WinAPI

HWND list Ctrl = : :GetDlgItem(GetSafeHwnd () , IDC_TEST_LIST) ;
int p;
// Добавление колонок
for(p=0; p<ELEMS_NMB;
{
/ / Сформировать текст
TCHAR str [10] ;
swprintf (str, _T("%X"), p+1);
LV_COLUMN column;
column. mask = LVCFJTEXT | LVCF_FMT ;
column. pszText = (LPTSTR) str;
column. fmt = LVCFMT_CENTER;
column. mask |= LVCF_WIDTH;
column. ex = 28;
: :SendMessage(list_ctrl, LVM_INSERTCOLUMN, p, (LPARAM) icolumn) ;
// Добавление значений
for(p=0; p<ELEMS_NMB;
{
// Сформировать добавляемый текст
TCHAR str [10] ;
swprintf (str, _T("%X"), p+1);
// Сформировать первый элемент строки
LVITEM item_info;
item_info. iltem = p;
item_info. iSubltem = 0;
item_info.mask = LVIFJTEXT;
item_info.pszText = str;
: :SendMessage(list_ctrl, LVM_INSERTITEM, 0, (LPARAM) &item_info)
// Добавить остальные элементы строки
for(int j=l; j<ELEMS_NMB;
{
// Сформировать добавляемый текст swprintf
(str, _T("%X"), (p+1) * (j+1)
itera_info. iSubltem = j;
item_info.pszText = str;
::SendMessage(list_ctrl, LVM SETITEM, 0, (LPARAM)sitem info);
}
}

При использовании WinAPI нужно учитывать несколько основных моментов.

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

7.4. Работа с файлами
Для демонстрации приложения, работающего с файлами, напишем несложную программу, построенную на основе диалогового окна. Создадим в ней три элемента: текстовое поле (Edit box) для заметок с идентификатором IDC_EDIT_NOTE, ТСКСТОВОС ПОЛС ДЛЯ ИМ6НИ ЗВТОра С
идентификатором idc_edit_author и две кнопки: Load и Save.
Код, необходимый для чтения и записи, показан в листинге 7.12.

Лстинг 7.12. Чтение и запись файла

// Буфер для хранения данных
#define BUF_LEN 255
static WCHAR str_buf[BUF_LEN];
// Сохранение данных
void CFilesTestDlg::OnButtonSave()
{
// Создать файл
CFile file;
file.Open(_T("My Documents\\Personal\\MyNote.txt"),
CFile::modeWrite|CFile::modeCreate);
// Получить текст из 1-го поля ввода
CEdit *pEdit = (CEdit*)GetDlgItem(IDC_EDIT_AUTHOR);
pEdit->GetWindowText(str buf, 255);
// Записать 1-ю строку в файл
file.Write(str buf, BUF LEN*sizeof(WCHAR));
// Получить текст из 2-го поля ввода
pEdit = (CEdit*)GetDlgItem(IDC_EDIT_NOTE) ;
pEdit->GetWindowText (str_buf, 255) ;
// Записать 2-ю строку в файл
file. Write (str_buf, BUF_LEN*sizeof (WCHAR) ) ;
// Закрыть файл file. Closed ;
}
// Чтение данных
void CFilesTestDlg: : OnButtonLoad ( )
{
CFile file;
// Открыть файл
file.Open(_T ("My Documents\\Personal\\MyNote.txt") ,
CFile: :modeRead)
// Прочитать 1-ю строку из файла
file. Read (strjsuf, BUF_LEN*sizeof (WCHAR) ) ;
// Занести текст в 1-е поле ввода
CEdit *pEdit = (CEdit*)GetDlgItem(IDC_EDIT_AUTHOR) ;
pEdit->SetWindowText (strjouf ) ;
// Прочитать 2-ю строку из файла
file. Read (str__buf , BUF__LEN*sizeof (WCHAR) ) ;
// Занести текст во 2-е поле ввода
pEdit = (CEdit*) GetDlgItem(IDC_EDIT_NOTE) ;
pEdit->SetWindowText (str_buf ) ;
/ / Закрыть файл file.
Close () ;
}

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

  1. Открытие файла функцией open. Функция принимает два параметра, первый из которых — имя файла, а второй — необходимые флаги доступа. Могут использоваться комбинации различных флагов доступа, основные из которых следующие:
  2. Запись (или чтение) в файл.
    Запись в файл производится функцией write, которой передаются два параметра — указатель на объект и размер объекта. Объекты могут быть совершенно произвольными — можно записывать строки, целые и вещественные числа и т. д. Чтение производится похожей функцией Read. Естественно, что при чтении необходимо соблюдать тот же порядок следования элементов, что был при записи.
  3. Закрытие файла функцией close.

Еще раз следует отметить, что файловая система Windows СЕ, в отличие от Palm OS, является полностью функциональной. Единственное ее отличие от файловой системы настольных компьютеров состоит в отсутствии логических дисков.

7.5. Еще об особенностях Windows СЕ
На этом разделе изучение программирования для Windows СЕ заканчивается. Естественно, очень многие вопросы остались неизученными. Не была рассмотрена работа с графикой, не были рассмотрены многие интерфейсные элементы Windows, не была рассмотрена работа с реестром. Естественно, что на все это понадобилась бы еще целая книга, по объему не меньше этой.
При рассмотрении программирования под Windows СЕ уже было замечено, что принципы программирования для карманных компьютеров PocketPC практически не отличаются от программирования для настольных ПК. Единственная разница состоит лишь в том, что Windows СЕ поддерживает меньшее количество разнообразных API-функций, чем имеется на настольной версии.
Собственно говоря, это не является большой проблемой. Даже наоборот, громоздкость Windows давно уже вызывает вполне уместные замечания (например, на компьютере автора Windows 2000 занимает более гигабайта). Поэтому радует то, что из Windows СЕ наконец-то была выкинута куча функций, половина из которых редко используется, и без которых можно обойтись, а другая половина оставлена лишь "для обеспечения совместимости".

7.5.1. Различия в библиотеке ATL
Различия между версиями ATL для Windows и Windows СЕ сведены в табл. 7.2. Из таблицы видно, что подавляющее количество классов ATL все-таки поддерживается Windows СЕ, так что в большинстве случаев можно пользоваться ATL, почти не думая о вопросах переносимости между Windows и Windows СЕ.

Таблица 7.2. Различия версий ATL

Наличие поддержки Список классов
Поддерживаемые классы CaxDialoglmpl, CcomVariant, CaxWindow, CContainedWindow, CcomAggObject, Cdialoglmpl, CcomAutoCriticalSection, CDynamicChain, CComAutoThreadModule, CFirePropNotifyEvent, CComBSTR, CMessageMap, CcomCachedTearOff Object, CRegKey, CcomClassFactory, CSimpleDialog, CcomClassFactory2, CStockPropImpl, CcomClassFactoryAutoThread, Cwindowlmpl, CcomCoClass, CWinTraits, CcomCompositeControl, CWinTraitsOR, CcomContainedObject, CWndClassInfo, CcomControl, I connect ionPointContainerIrn.pl, CcomCriticalSection, IconnectionPointlmpl, CcomDispatchDriver, IDispatchlmpl, CcomDynamicUnkArray, IdispEventlmpl, CcomFakeCriticalSection, lobjectWithSitelmpl, CcomMultiThreadModel, loleControlImpl, CcomMultiThreadModelNoCS, lOlelnPlaceActiveObjectlmpl, CcomObject, lOlelnPlaceObjectWindowlessImpl, CcomObjectGlobal, IPerPropertyBrowsinglmpl, CcomObjectNoLock, IPersistPropertyBaglmpl, CcomObjectRoot, IPersistStoragelmpl, CcomObjectRootEx, IpersistStreamlnitlmpl, CcomObjectStack, IPointerlnactivelmpl, CcomObjectThreadModel, IPropertyNotifySinkCP, CcomPolyObject, IPropertyPage2Impl, CcomPtr, IprovideClassInfo2lmpl, CComQIPtr, IquickActivatelmpl, CcomSimpleThreadAl locator, IrunnableObjectlmpl, CcomSingleThreadModel, I specif у Proper t у Pages Imp 1, CcomTearOff Object, IsupportErrorlnfoImpl, CcomUnkArray, IviewObjectExImpl
Неподдерживаемые классы CBindStatusCallback, CSnapInltemlmpl, С SnapInPropertyPagelmpl, lObjectSafetylmpl, I service Provider Info
Модифицированные классы CcomApartment, CWindow, CcomClassFactorySingleton, IDataObjectlmpl, CcomGlobalsThreadModel, IQleObjectlmpl, CComModule, IpropertyPagelmpl

7.5.2. Различия в библиотеке MFC
Приведем такую же таблицу для классов MFC (табл. 7.3).

Таблица 7.3. Различия версий MFC

Наличие поддержки Список классов
Поддерживаемые классы CArchive, CObList, CArchiveException, ColeControlModule, CArray, COleCurrency, CBitmapButton, COleDispatchDriver, CByteArray, COleDispatchException, CClientDC, COleException, CCmdTarget, COlePropertyPage, CCmdUI, COleSafeArray, CColorDialog, COleStreamFile, CConnectionPoint, COleVariant, CControlBar, CPaintDC, CCreateContext, CPoint, CCriticalSection, CProgressCtrl, CCtrlView, CPropExchange, CDataExchange, CPtrArray, CdateTimeCtrl, CPtrList, CDialogBar, CReBar, CDumpContext, CrecentFileList, CDWordArray, CRect, CException, CresourceException, CFileException, CRuntimeClass, CFindReplaceDialog, CScrollBar, CFormView, CScrollView, CHeaderCtrl, CsingleDocTemplate, CHttpFile, CSingleLock, CInternetException, CSize, CList (template), CSliderCtrl, CListView, CSocket, CLongBinary, CsocketFile, CMap (template), CSplitterWnd, CMapPtrToPtr, CStatusBar, CmapPtrToWord, CStringArray, CMapStringToOb, CStringList, CmapStringToPtr, CTimeSpan, CMapStringToString, CToolBar, CmapWordToOb, CTreeCtrl, CMapWordToPtr, CTreeView, CMemFile, CtypedPtrArray, CMemoryException, CTypedPtrList, CMultiLock, CtypedPtrMap, CMutex, CUIntArray, CNotSupportedException, CuserException, CObArray, CWaitCursor, CObject, CWindowDC, CwordArray
Неподдерживаемые классы Диалоговые окна:
CFontDialog, CpageSetupDialog.

Элементы интерфейса:
CAnimateCtrl, CHotKeyCtrl, CCheckListBox, CminiFrameWnd, CComboBoxEx, CToolTipCtrl, CdragListBox.

Работа с БД:
CDaoDatabase, CDaoRecordset, CDaoException, CDaoRecordView, CDaoFieldExchange, CDaoTableDef, CDaoQueryDef, CDaoWorkspace, CDatabase, CFieldExchange, CDBException, CRecordset, CDBVariant, CRecordView.

Интернет:
CFtpConnection, CHtmlView, CFtpFileFind, CHttpFilter, CGopherConnection, CHttpFilterContext, CGopherFile, CHttpServer, CGopherFileFind, ChttpServerContext, CGopherLocator, CIPAddressCtrl, ChtmlStream.

MDI:
CMDIChildWnd, CMultiDocTemplate, CMDIFrameWnd.

OLE:
CAsyncMonikerFile, COleDialog, CCachedDataPathProperty, COleDocObjectltem, CDataPathProperty, COleDocument, CDocItem, COleDropSource, CDocObjectServer, COleDropTarget, CDocObjectServerltem, COlelnsertDialog, CMonikerFile, COlelPFrameWnd, COleBusyDialog, COleLinkingDoc, COleChangelconDialog, COleLinksDialog,COleChangeSourceDialog, COleMessageFilter, COleClientltem, COlePasteSpecialDialog, COleCmdUI, COlePropertiesDialog, COleConvertDialog, COleResizeBar, COleDataObject, COleServerDoc, COleDataSource, COleServerltem, COleDBRecordView, ColeTemplateServer.

Элемент Rich Edit:
CrichEditCntrlltem, CRichEditDoc, CRichEditCtrl, CrichEditView.

Другие классы:
CDockState, CPictureHolder, CFileFind, CSemaphore, CMemoryState, CSharedFile, CmetaFileDC

Модифицированные классы  CAsyncSocket, CMenu, CBitmap, COleControl, CBrush,  COleDateTime, CButton, COleDateTimeSpan, CComboBox,  COleObjectFactory, CCommandLinelnfo, CPalette, CCommonDialog, CPen, CDC, CPrintDialog, CDialog, CPropertyPage, CDocTemplate, CPropertySheet, CDocument, CReBarCtrl, CEdit, CRectTracker, CEditView, CRgn, CEvent, CSpinButtonCtrl, CFile, CStatic, CFileDialog, CStatusBarCtrl, CFont, CStdioFile, CFontHolder, CString, CFrameWnd, CSyncObject, CGdiObject, CTabCtrl, CHttpConnection, CTime, CImageList, CToolBarCtrl, CInternetConnection, CView, CInternetFile, CWinApp, CInternetSession, CWinThread, CListBox, CWnd, ClistCtrl

 

Из таблицы видно, что поддержка классов MFC сделана в Windows СЕ гораздо более бедно, и отсутствует немало полезных классов. Например, отсутствует диалоговое окно выбора шрифта CFontDialog, отсутствуют многие классы для отображения HTML и работы с Интернетом, например, CHtmiview, отсутствует класс CMetaFiieDC, позволяющий удобно выводить графику в метафайл. Одно из наиболее заметных отличий — отсутствие поддержки многодокументных приложений MDI. При необходимости разработки переносимых программ все это нужно учитывать. Собственно говоря, вряд ли можно было ожидать полной поддержки MFC в Windows СЕ, поскольку одна только библиотека "mfc42.dll" занимает около мегабайта, что для СЕ слишком расточительно. Но в любом случае можно отметить, что Windows СЕ в настоящее время является самой удобной из платформ, имеющихся для карманных компьютеров.
На этом изучение программирования для Windows СЕ подходит к концу. Для более детального освоения этой системы читателям придется обратиться к другой специальной литературе. У программистов, работающих с Windows СЕ, в этом плане есть немалое преимущество — литературы, описывающей программирование для Windows, можно найти очень много. И хоть не все функции полноценно работают под Windows СЕ (см. табл. 7.2 и 7.3), в большинстве случаев очень многое совпадает, а с некоторыми отличиями разобраться не составляет труда. Тем более, вся документация содержится в MSDN.

Hosted by uCoz