Как стать автором
Обновить

Программирование под Windows CE на C++ с помощью Embedded Visual C++, часть 3 (наверное последняя).

Время на прочтение5 мин
Количество просмотров4.4K
Программирование под Windows CE на C++ с помощью Embedded Visual C++, часть 3 (наверное последняя).

Продолжение 1-й и 2-й части.


Сейчас мы в деталях обсудим различия между смартфонами и покетПиСи. Готовы? Итак: в PocketPC можно тыкнуть пальцем, а в Smartphone нельзя. Вот и все!

Большая проблема с КПК в том, что на них не так много памяти. Неплохо бы вообще понять где мы запустились и чего есть. Это можно сделать так:

MEMORYSTATUS ms;
ZeroMemory(&ms, sizeof(ms));
ms.dwLength = sizeof(MEMORYSTATUS);
GlobalMemoryStatus(&ms);

ULARGE_INTEGER free = {0}, avail = {0}, total = {0};
GetDiskFreeSpaceEx(0, &free, &avail, &total);

// нам нужно тут слово PocketPC если пишем под КПК
TCHAR platform[1000] = {0};
SystemParametersInfo(SPI_GETPLATFORMTYPE, 1000, platform, 0);

TCHAR OEM[1000] = {0};
SystemParametersInfo(SPI_GETOEMINFO, 1000, OEM, 0);

printf (_T("Производитель: %s."), OEM);
printf (_T("Платформа: %s."), platform);
printf (_T("Память, доступно %d из %d Мб."), ms.dwAvailVirtual >> 20, ms.dwTotalVirtual >> 20);
printf (_T("Диск, доступно %d Мб."), free.QuadPart >> 20);


Иногда на КПК можно повернуть экран в альбомную и портретную ориентацию. Вот необходимые функции:

// можно нам повернуть экран?
bool CanRotateScreen()
{
#ifdef UNDER_CE
DEVMODE dm;
memset(&dm, 0, sizeof(dm));
dm.dmSize = sizeof(DEVMODE);
dm.dmFields = DM_DISPLAYQUERYORIENTATION;
return DISP_CHANGE_SUCCESSFUL == ChangeDisplaySettingsEx(NULL, &dm, NULL, CDS_TEST, NULL);
#else
return false;
#endif
}

// как он повернут сейчас?
int ScreenRotationAngle()
{
#ifdef UNDER_CE
DEVMODE dm;
memset(&dm, 0, sizeof(dm));
dm.dmSize = sizeof(DEVMODE);
dm.dmFields = DM_DISPLAYORIENTATION;
ChangeDisplaySettingsEx(NULL, &dm, NULL, CDS_TEST, NULL);
switch (dm.dmDisplayOrientation)
{
case DMDO_0: return 0;
case DMDO_90: return 90;
case DMDO_180: return 180;
case DMDO_270: return 270;
}
#endif
return -1;
}

// поворачиваем!
void RotateScreen(int angle)
{
#ifdef UNDER_CE
DEVMODE dm;
memset(&dm, 0, sizeof(dm));
dm.dmSize = sizeof(DEVMODE);
dm.dmFields = DM_DISPLAYORIENTATION;
switch (angle)
{
default:
case 0: dm.dmDisplayOrientation = DMDO_0;
case 90: dm.dmDisplayOrientation = DMDO_90;
case 180: dm.dmDisplayOrientation = DMDO_180;
case 270: dm.dmDisplayOrientation = DMDO_270;
}
ChangeDisplaySettingsEx(NULL, &dm, NULL, CDS_RESET, NULL);
#endif

}


Не забудьте отреагировать на сообщение WM_SETTINGCHANGE! Возможно Вы захотите там понять как теперь выглядит экран:

...
Screen.right = GetSystemMetrics(SM_CXSCREEN) - 1;
Screen.bottom = GetSystemMetrics(SM_CYSCREEN) - 1;
...


Поскольку нельзя объять необъятное, то я тут закругляюсь, но все-таки расскажу под конец как сделать инсталляцию Вашего приложения под КПК. Вы же хотите создать нормальный человеческий инсталлятор из-под Win32, а не убожество по умолчанию, верно?

Вам нужна RAPI.DLL. Если порыться в сети, то можно найти RAPI.H, который описывает неимоверное кол-во структур и функций в RAPI.DLL, некоторые из которых Вам нужны. С помощью RAPI.DLL можно установить факт присоединения КПК к настольному ПК, порыться в его файлах, скопировать файлы с настольного на КПК и обратно, создать ярлыки и т.д.

Это делается примерно так (код на Delphi, не пугайтесь!):

type

TRapiInit = record
cbSize:DWORD;
heRapiInit:THandle;
hrRapiInit:HResult;
end;

function CeCloseHandle(hObject: THandle): bool; stdcall external 'rapi.dll';
function CeCreateFile(lpFileName: LPCWSTR; dwDesiredAccess: dword; dwShareMode: dword; lpSecurityAttributes: PSecurityAttributes; dwCreationDistribution: dword; dwFlagsAndAttributes: dword; hTemplateFile: THandle): THandle; stdcall external 'rapi.dll';
function CeGetFileSize(hFile: THandle; lpFileSizeHigh: PDWORD): dword; stdcall external 'rapi.dll';
function CeGetLastError: dword; stdcall external 'rapi.dll';
function CeRapiInitEx(var RapiInit: TRapiInit): longint; stdcall external 'rapi.dll';
function CeRapiUninit: longint; external 'rapi.dll';
function CeReadFile(hFile: THandle; const lpBuffer; nNumberOfBytesToRead: dword; var NumberOfBytesRead :dword; Overlapped: POVERLAPPED): bool; stdcall external 'rapi.dll';
function CeWriteFile(hFile: THandle; const lpBuffer; NumberOfBytesToWrite: dword; var NumberOfBytesWritten :dword; Overlapped: POVERLAPPED): bool; stdcall external 'rapi.dll';
function CeCreateDirectory(lpPathName:LPCWSTR; lpSecurityAttributes:PSecurityAttributes):BOOL; stdcall external 'rapi.dll';
function CeRemoveDirectory(PathName:LPCWSTR):BOOL; stdcall external 'rapi.dll';
function GetRapiError: integer; stdcall external 'rapi.dll';

procedure InitRAPI(wait_ms: cardinal);
var
ri: TRapiInit;
h: HRESULT;
when: cardinal;
begin
ZeroMemory(@ri, sizeof(ri));
ri.cbSize := sizeof(ri);
h := CeRapiInitEx(ri);
if FAILED(h) then raise Exception.Create('Не удалось инициализировать систему связи с КПК.');
when := GetTickCount + wait_ms;
while GetTickCount < when do
case MsgWaitForMultipleObjects(1, ri.heRapiInit, FALSE, when - GetTickCount,QS_ALLINPUT) of
WAIT_OBJECT_0: if SUCCEEDED(ri.hrRapiInit) then exit else raise Exception.Create('Не удалось установить соединение с PDA.');
WAIT_OBJECT_0 + 1: Application.ProcessMessages;
end;
raise Exception.Create('Таймаут связи с КПК.');
end;

procedure CopyFileToPDA(src_filename, dst_filename: string; ignore_errors: boolean );
var
buffer: array [0..16384] of char;
BufferCount, ReadCount, WriteCount: cardinal;
dst, src: THandle;
filename: pWideChar;
code: longbool;
begin
GetMem(filename, sizeof(WideChar) * Succ(Length(dst_filename)));
StringToWideChar(dst_filename, filename, Succ(Length(dst_filename)));
try
src := CreateFile(PChar(src_filename), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
if GetLastError = INVALID_HANDLE_VALUE then raise Exception.CreateFmt('Не удалось открыть файл "%s".', [src_filename]);
dst := CeCreateFile(filename, GENERIC_READ or GENERIC_WRITE,0,nil,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
if (CeGetLastError = INVALID_HANDLE_VALUE) then raise Exception.CreateFmt('Не удалось создать файл "%s" на КПК.', [dst_filename]);
BufferCount := 16384; ReadCount := 16384;
while ReadFile(src,Buffer,BufferCount,ReadCount,nil) and (ReadCount <> 0) do begin
code := CeWriteFile(dst,buffer,ReadCount,WriteCount, nil);
if not code and not ignore_errors then
raise Exception.Create('Ошибка при копировании файла "' + src_filename + '" на КПК ("' + dst_filename + '").');
Application.ProcessMessages;
end;
CloseHandle(src);
CeCloseHandle(dst);
finally
FreeMem(filename);
end;
end;



Может быть Вы захотите записать приложение сразу на карту памяти? Тогда попробуйте найти ее вот так:

function StorageCardPath: string;
var
h: THandle;
data: CE_FIND_DATA;
name: string;
const
a = FILE_ATTRIBUTE_TEMPORARY or FILE_ATTRIBUTE_DIRECTORY;
begin
h := CeFindFirstFile('\*.*', @data);
while h <> INVALID_HANDLE_VALUE do begin
if (data.dwFileAttributes and a) = a then begin
name := WideCharToString(data.cFileName);
if Pos('NETWORK', UpperCase(name)) = 0 then begin
result := '\' + name;
break;
end;
end;
if not CeFindNextFile(h, @data) then break;
end;
CeFindClose(h);

end;


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

Удачи!

Теги:
Хабы:
Всего голосов 13: ↑8 и ↓5+3
Комментарии9

Публикации

Истории

Работа

Swift разработчик
32 вакансии
iOS разработчик
24 вакансии

Ближайшие события