Pull to refresh

Программирование под Windows CE с помощью Embedded Visual C++, часть 1

Reading time 4 min
Views 21K
Этот пост для настоящих программистов, которые вместо букваря учили алфавит по третьему изданию справочника по C++. Программировать под Windows CE будем на C++ с помощью Embedded Visual C++.

Итак, нам понадобятся:


1. eMbedded Visual C++ 4.0 (TRT7H-KD36T-FRH8D-6QH8P-VFJHQ)
2. eMbedded Visual C++ 4.0 service pack 4
3. ritti.exe
4. Microsoft Pocket PC 2003 SDK.msi
5. Microsoft ActiveSync
6. StandAlone Emulator

Данный комплект позволяет разрабатывать программы, которые запускаются на всех Windows Mobile, начиная с 2003. Забудьте про нововведения в Windows Mobile 5 и 6 (если только они вам не нужны :). Все эти продукты находятся через Гугл, но установить их немного тягомотно. Особенно надоедает Emulator, который требует установки следующих вещей в следующем порядке:

1. netsvwrap.msi
2. standalone_emulator_V1.exe
3. efp.msi
4. emulator_2_0.msi

Если Вы все еще здесь – продолжаем!

Вкратце отличия WinCE API от Win32 API таковы: только Unicode, отсутствие текущего каталога (только абсолютные пути), урезаны громоздкие вещи, наличие особенностей со вводом.

Я создавал кросс-платформенный продукт (под WinCE и Win32). Вот как это делается в двух словах. С помощью UNDER_CE различить платформу:

#ifdef UNDER_CE
// здесь код для только для Windows CE
#else
// здесь код для только для Windows 32
#endif


WinMain немного различается:

#ifdef UNDER_CE
int WINAPI WinMain(HINSTANCE h, HINSTANCE prev, LPTSTR line, int cmd)
#else
int WINAPI WinMain(HINSTANCE h, HINSTANCE prev, LPSTR line, int cmd)
#endif

Проще всего делать оба проекта UNICODE. Это упростит код. В STL для работы с UNICODE-строкой есть замечательный класс wstring. Литералы строковые выглядеть должны так:

_T(«Goodbye, world!»)

_T() есть макрос, которые превратит строковый литерал в UNICODE или ASCII по надобности. Вместо char используем TCHAR.

Чтобы сделать проект UNICODE в Win32 задайте два preprocessor definitions: _UNICODE и UNICODE. В Embedded C++ это будет сделано по умолчанию.

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

wstring ApplicationPath()
{
TCHAR Path[MAX_PATH + 1] = {0};
int n = GetModuleFileName(0, Path, MAX_PATH);
while (--n > 0 && Path[n] != _T('\\') && Path[n] != _T('/'))
Path[n] = 0;
return Path;
}

Вот так вот извращаемся, если нужно что-то только под Windows 32:

typedef DWORD (WINAPI *FUNC_GetGuiResources)(HANDLE, DWORD);
FUNC_GetGuiResources f_GetGuiResources = 0;

struct Win2000_Linkage { Win2000_Linkage() {
#ifndef UNDER_CE
f_GetGuiResources = (FUNC_GetGuiResources) GetProcAddress(GetModuleHandle(_T(«user32.dll»)), «GetGuiResources»);
#endif
} } Win2000_linkage;

int GetGuiResource(DWORD which)
{
#ifndef UNDER_CE
if (f_GetGuiResources == 0) return 0;
HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, false, GetCurrentProcessId());
int n = f_GetGuiResources (h, which);
CloseHandle(h);
return n;
#else
return 0;
#endif
}

Вот еще странный кусок кода, который видимо появился из-за отсутствия прерывистой линии типа, составленной из точек на Win CE:

#ifdef UNDER_CE
#define DASH_STYLE PS_DASH
#else
#define DASH_STYLE PS_DOT
#endif

Под Win CE у нас как бы нету текущей позиции курсора, потому как сами понимаете. Следовательно, если она нужна, то запоминайте сами последнее событие от мыши и считайте эту позицию позицией курсора. Типа:

#ifdef UNDER_CE
POINT mouse = mouse_at;
#else
POINT mouse = WhereIsCursor();
#endif

Под Win CE отсутствует примитив Arc() (см. GDI).

Зато! Зато под Win CE есть все-таки что-то хорошее. Это хорошее – это встроенный в ОС браузер Chro..., то есть Oper.., то есть Inernet Explorer! Фуу, вспомнил название-таки! Он конечно немного попроще своего старшего брата, но ведь нам много и не нужно – просто красиво нам текст HTML нарисуй и все!

Вначале делаем:

BOOL InitHTMLControl(
HINSTANCE hinst );

Теперича на окно можно добавить контрол с классом WC_HTML.
И заслать в него какой-нибудь HTML для отображения:
SendMessage(hwndHTML, WM_SETTEXT, 0, (LPARAM)"");
SendMessage(hwndHTML, DTM_ADDTEXTW, FALSE, (LPARAM)TEXT("Hello"));
SendMessage(hwndHTML, DTM_ADDTEXTW, FALSE, (LPARAM)TEXT("World!"));
SendMessage(hwndHTML, DTM_ENDOFSOURCE, 0, (LPARAM)NULL);

Под Win 32 для схожих целей можно использовать контрол richedit.

Под Win CE нету GetPrivateProfileString, так что чтение и разбор INI-файлов ваша прерогатива.

При загрузке DLL под Win32 имя функции должно быть в ANSI. Хотя проект и под UNICODE. Почему? Потому что!

#ifndef UNDER_CE
string f_name = ANSI(func_name);
FARPROC f = GetProcAddress(h, f_name.data());
#else
FARPROC f = GetProcAddress(h, func_name);
#endif

Заодно держите и вот эти функции:

string ANSI(wstring w)
{
int l = WideCharToMultiByte(CP_ACP, 0, w.data(), w.size(), NULL, 0, NULL, NULL);
if (l)
{
char* buffer = new char[l + 1];
l = WideCharToMultiByte(CP_ACP, 0, w.data(), w.size(), buffer, l, NULL, NULL);
buffer[l] = 0;
string s(buffer);
delete[] buffer;
return s;
}
return "";
}

wstring UniCODE(string w)
{
int l = MultiByteToWideChar(CP_ACP, 0, w.data(), w.size(), NULL, 0);
if (l)
{
TCHAR* buffer = new TCHAR[l + 1];
l = MultiByteToWideChar(CP_ACP, 0, w.data(), w.size(), buffer, l);
buffer[l] = 0;
wstring s(buffer);
delete[] buffer;
return s;
}
return _T("");
}

Вот как у меня выглядит начало h-файла, который включается в каждый компилируемый файл первым:

#pragma warning(disable: 4786)
#pragma once

#ifndef UNICODE
#error You must define UNICODE
#endif

#ifndef _UNICODE
#error You must define _UNICODE
#endif

#ifndef WINVER
#define _WIN32_WINNT 0x0400
#define WINVER 0x0400
#endif

#ifndef UNDER_CE
#include <tchar.h>
#include <crtdbg.h>
#define ASSERT(expr) _ASSERT(expr)
#define IDC_HAND MAKEINTRESOURCE(32649)
#define GR_GDIOBJECTS 0 /* Count of GDI objects */
#define GR_USEROBJECTS 1 /* Count of USER objects */
#define WS_NONAVDONEBUTTON 0
#include <math.h>
#endif
#include «windows.h»
#include #include #include #include #include #include using namespace std;

Как видите я плотно использую STL и поэтому подгружаю ее классы в пространство имен по умолчанию.

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

Tags:
Hubs:
+12
Comments 28
Comments Comments 28

Articles