WinCE Programming Tips/ru
Эта статья относится только к WinCE.
См. также: Multiplatform Programming Guide
│
English (en) │
русский (ru) │
На этой странице описано несколько приёмов работы с платформой WinCE.
Other Interfaces
- Lazarus known issues (things that will never be fixed) - A list of interface compatibility issues
- Win32/64 Interface - The Windows API (formerly Win32 API) interface for Windows 95/98/Me/2000/XP/Vista/10, but not CE
- Windows CE Interface - For Pocket PC and Smartphones
- Carbon Interface - The Carbon 32 bit interface for macOS (deprecated; removed from macOS 10.15)
- Cocoa Interface - The Cocoa 64 bit interface for macOS
- Qt Interface - The Qt4 interface for Unixes, macOS, Windows, and Linux-based PDAs
- Qt5 Interface - The Qt5 interface for Unixes, macOS, Windows, and Linux-based PDAs
- GTK1 Interface - The gtk1 interface for Unixes, macOS (X11), Windows
- GTK2 Interface - The gtk2 interface for Unixes, macOS (X11), Windows
- GTK3 Interface - The gtk3 interface for Unixes, macOS (X11), Windows
- fpGUI Interface - Based on the fpGUI library, which is a cross-platform toolkit completely written in Object Pascal
- Custom Drawn Interface - A cross-platform LCL backend written completely in Object Pascal inside Lazarus. The Lazarus interface to Android.
Platform specific Tips
- Android Programming - For Android smartphones and tablets
- iPhone/iPod development - About using Objective Pascal to develop iOS applications
- FreeBSD Programming Tips - FreeBSD programming tips
- Linux Programming Tips - How to execute particular programming tasks in Linux
- macOS Programming Tips - Lazarus tips, useful tools, Unix commands, and more...
- WinCE Programming Tips - Using the telephone API, sending SMSes, and more...
- Windows Programming Tips - Desktop Windows programming tips
Interface Development Articles
- Carbon interface internals - If you want to help improving the Carbon interface
- Windows CE Development Notes - For Pocket PC and Smartphones
- Adding a new interface - How to add a new widget set interface
- LCL Defines - Choosing the right options to recompile LCL
- LCL Internals - Some info about the inner workings of the LCL
- Cocoa Internals - Some info about the inner workings of the Cocoa widgetset
Советы / ЧаВо
Приложение работает на эмуляторе, но не работает на устройстве
Когда приложение запущено на эмуляторе, всё нормально, однако на устройстве возникает ошибка типа:
Cannot find 'project1' (or one of its components).
'project1' (или один из компонентов) не найден.
Возможно, ошибка возникает, потому что:
Отсуствует aygshell.dll
Эта ошибка обычно указывает на отсутствие библиотеки на целевом устройстве, особенно если у вас приложение типа "Hello World". Часто это связано с библиотекой aygshell.dll, которая отсуствует на многих устройствах под управлением "голых" Windows CE - как правило, на устройствах под управлением Windows Mobile этой проблемы не возникает.
Эта проблема наблюдалась на считывателях штрих-кодов motorolla, работавших под WinCE 4.2 и 5.
Проблема решается распространением aygshell.dll вместе с программой(кажется, так делает gps-программа navitel).
Вот пара ссылок на темы форума freepascal.org, где обсуждаются проблемы с aygshell.dll(на английском):
- http://forum.lazarus.freepascal.org/index.php/topic,7161.0.html
- http://forum.lazarus.freepascal.org/index.php/topic,5524.0.html
А здесь(тоже на английском) изменения в версиях библиотеки aygshell.dll:
Не тот процессор
Возможно, на устройстве установлен не ARM, наиболее распространённый, а x86 или MIPS. Тут уж ничего не поделаешь.
Отсутствие функций из-за версии операционной системы
Возможно, операционная система очень старая, и в ней просто нет функций, используемых Lazarus'ом.
Получить ID устройства
Идентификация устройства полезна для защиты вашей программы. Работает только на windows mobile 5.1 и 5.2 <delphi>
function GetDeviceUniqueID(AppData:LPCWSTR; cbApplictionData:Integer; dwDeviceIDVersion:Integer;
var deviceIDOuput; var pcbDeviceIDOutput:DWORD):Integer; external 'coredll.dll' name 'GetDeviceUniqueID';
function GetDeviceID: string; var
AppData: array[0..19] of WideChar; DeviceID : array[0..19] of Byte; Count: DWORD; s: string; Res, i:Integer;
begin
//not sure about Unicode AppData := Utf8Decode('MY_SIG'); Count := SizeOf(DeviceID); FillChar(DeviceID, Count, #0); Res := GetDeviceUniqueID(AppData, SizeOF(AppData), 1, DeviceID, Count); if Res = 0 then begin Result := ; for i := 0 to Count -1 do begin if (i > 0) and ((i mod 2) = 0) then Result := Result + '-'; //add space make the string wrap in label Result := Result + IntToHex(DeviceID[i], 2); end; end else Result := ;//error accord
// you can MD5 it with your string // Result := MD5Print(MD5Buffer(DeviceID, Count)); end; </delphi>
Ссылки: http://msdn2.microsoft.com/en-us/library/ms893522.aspx http://peterfoot.net/RetrieveIMEIThroughTAPI.aspx http://blogs.msdn.com/jehance/archive/2004/07/12/181067.aspx
Получить имя устройтсва
Это легко стелать через реестр:
<delphi> function GetDeviceName: string; var
aReg:TRegistry;
begin
aReg := TRegistry.Create(KEY_READ); try aReg.RootKey := HKEY_LOCAL_MACHINE; aReg.OpenKey('Ident', False); if aReg.ValueExists('Name') then Result := aReg.ReadString('Name') else Result := 'GUEST'; finally aReg.Free; end;
end; </delphi>
Показать/спрятать SIP Panel
Виртуальная клавиатура для сенсорных экранов(SIP: Software Input Panel button).
<delphi> const
//Некоторые константы SIPF_OFF = $00000000; SIPF_ON = $00000001; SIPF_DOCKED = $00000002; SIPF_LOCKED = $00000004;
function SipShowIM(IPStatus:DWORD):Integer; stdcall; external 'coredll.dll' name 'SipShowIM';
begin
SipShowIM(SIPF_ON)
end;
</delphi>
Документация microsoft об этом: [1]
Включить/разбудить устройство
Понадобится любителям будильников.
<delphi> function SetSystemPowerState(psState: PWideChar; StateFlags: DWORD; Options : DWORD):DWORD;
stdcall; external 'coredll.dll' name 'SetSystemPowerState';
SetSystemPowerState(nil, POWER_STATE_ON, POWER_FORCE); Application.BringToFront; ShowWindow(Handle, SW_SHOW);
</delphi>
Подсветка/вибрация
Вы можете включать/выключать подсветку и вибратор. У меня работало нормально (а вот автор статьи говорит, что работает, но не так, как хотелось бы, и что, видимо будут доработки).
<delphi> const
NLED_COUNT_INFO_ID = 0; NLED_SUPPORTS_INFO_ID = 1; NLED_SETTINGS_INFO_ID = 2;
type
TNLED_COUNT_INFO = record cLeds: DWORD; end; TNLED_SETTINGS_INFO = record LedNum: DWORD; // LED number, 0 is first LED OffOnBlink: Integer; // 0 = выкл, 1 = вкл, 2 = мигание TotalCycleTime: DWORD; // Общее время мигания в микросекундах. OnTime: DWORD; // Время вкл. в цикле в микросекундах. OffTime: DWORD; // Время выкл. в цикле в микросекундах. MetaCycleOn: Integer; // Число вкл. циклов миганий MetaCycleOff: Integer; // Число выкл. циклов миганий end;
function NLedGetDeviceInfo(nID:Integer; var pOutput): WordBool; stdcall; external 'coredll.dll' name 'NLedGetDeviceInfo'; function NLedSetDevice(nID: Integer; var pOutput): WordBool; stdcall; external 'coredll.dll' name 'NLedSetDevice';
</delphi>
Примеры: <delphi> function TForm1.MakeLEDOn; var
Countnfo: TNLED_COUNT_INFO; Info:TNLED_SETTINGS_INFO;
begin
NLedGetDeviceInfo(NLED_COUNT_INFO_ID, Countnfo); //with Countnfo.cLeds you can check if your device support LEDs; Info.LedNum := 0; //<--- First LED Info.OffOnBlink := 1; Info.OffTime := 0; Info.MetaCycleOff:= 50; Info.MetaCycleOn:= 50; Info.TotalCycleTime := 100; NLedSetDevice(NLED_SETTINGS_INFO_ID, Info);
end;
procedure TForm1.MakeLedOff; var
Info:TNLED_SETTINGS_INFO;
begin
Info.LedNum := 0; Info.OffOnBlink := 0; NLedSetDevice(NLED_SETTINGS_INFO_ID, Info);
end;
</delphi>
Вибратор - это последний индикатор устройства.
<delphi> function TForm1.MakeVibratorOn; var
Countnfo: TNLED_COUNT_INFO; Info:TNLED_SETTINGS_INFO;
begin
NLedGetDeviceInfo(NLED_COUNT_INFO_ID, Countnfo); Info.LedNum := Countnfo.cLeds -1; Info.OffOnBlink := 1; NLedSetDevice(NLED_SETTINGS_INFO_ID, Info);
end;
function TForm1.MakeVibratorOff; var
Countnfo: TNLED_COUNT_INFO; Info:TNLED_SETTINGS_INFO;
begin
NLedGetDeviceInfo(NLED_COUNT_INFO_ID, Countnfo); Info.LedNum := Countnfo.cLeds -1; Info.OffOnBlink := 0; NLedSetDevice(NLED_SETTINGS_INFO_ID, Info);
end; </delphi>
Получение состояния батареи
Больше об этом(опять-таки на английском) : MSDN GetSystemPowerStatusEx
<delphi> //by Philip Heinisch
type TBAT_INFO = record ACLineStatus:byte; //0=Offline, 1=Online, 2=Backup Power,3= Unknown status BatteryFlag:byte; //0=High, 1=Low, 2=Critical, 3=Charging, 4=No Battery, 5=Unknown BatteryLifePercent:byte; //0..100 Battery Life in Percent Reserved1:byte; //always 0 BatteryLifeTime: DWORD; //remaining time in seconds BatteryFullLifeTime: DWORD; //max usage time in seconds Reserved2:byte; //always 0 BackupBatteryFlag:byte; //0=High, 1=Low, 2=Critical, 3=Charging, 4=No Battery, 5=Unknown BackupBatteryLifePercent:byte; //0..100 Backup Battery Life in Percent Reserved3:byte; //always 0 BackupBatteryLifeTime: DWORD; //remaining time in seconds BackupBatteryFullLifeTime: DWORD; //max usage time in seconds end; function GetSystemPowerStatusEx(var pOutput;fUpdate:boolean ): WordBool; stdcall; external 'coredll.dll' name 'GetSystemPowerStatusEx';
//Usage Example:
function getbat : byte; var
batinfo: TBAT_INFO;
begin if GetSystemPowerStatusEx(batinfo,True) then getbat:=batinfo.BatteryLifePercent else getbat:=255; //255=Function Call Failed end; </delphi>
Создание полноэкранного приложения
Понадобится модуль windows(uses windows). Вставьте следующий код в раздел INTERFACE вашей программы:
<delphi> const
//ShFullScreen SHFS_SHOWTASKBAR = $01; SHFS_HIDETASKBAR = $02; SHFS_SHOWSIPBUTTON = $04; SHFS_HIDESIPBUTTON = $08; SHFS_SHOWSTARTICON = $10; SHFS_HIDESTARTICON = $20;
function SHFullScreen(hwndRequester: hWnd; dwState: DWord): WINBOOL; stdcall; external 'aygshell.dll' name 'SHFullScreen';
</delphi> Затем вставьте в события OnCreate и OnShow ваших форм(лучше OnShow) сл <delphi> procedure TForm1.FormCreate(Sender: TObject); var
Rect:TRect; hTaskBar:THandle; menuh:Integer;
begin
hTaskBar := FindWindow('HHTaskBar',); GetWindowRect(hTaskBar,rect); menuh:=Rect.Bottom-Rect.Top; GetWindowRect(Form1.Handle,Rect); SHFullScreen(Form1.Handle,SHFS_HIDETASKBAR or SHFS_HIDESTARTICON or SHFS_HIDESIPBUTTON); movewindow(Form1.Handle,Rect.Left,Rect.Top-menuh,Rect.Right,Rect.Bottom+menuh,True);
end; </delphi>
Препятствие входу в режим ожидания
Добавьте на форму таймер, в событии OnTimer пропишите следующую строку:
<delphi> keybd_event(VK_F24, 0, KEYEVENTF_KEYUP or KEYEVENTF_SILENT, 0); </delphi>
Установка приложения на WinCe через app build(cab файл)
//Original de Hinnack (from Lazarus forum)
У меня ушло много времени на то, что-бы выяснить, как установить моё приложение на WinCE-устройство(Да, я знаю, что можно скопировать и вставить), поэтому я решил поделиться этим здесь 1) Во-первых, нужен ini-файл (может, когда-нибудь, Лазарус сможет генерировать их сам...). Хороший рассказ о том, как это можно сделать, есть здесь(на англ.): http://web.archive.org/web/20080205125046/http://www.sundialsoft.freeserve.co.uk/cabinfo.htm (Оригинальный сайт мёртв) Я использовал следующее (только для ARM процессоров):
<delphi> [Version] ; Required section Signature = "$Windows NT$" Provider = "bilettiX" CESignature = "$Windows CE$"
[CEDevice.ARM] ProcessorType = 2577 ; processor value for ARM
[DefaultInstall.ARM] CopyFiles = Files.ARM
[Files.ARM] bilettixscan.exe,,,0 sqlite3.dll,,,0
[DefaultInstall] ; Required section CEShortcuts = Shortcuts.All AddReg = RegData
[SourceDisksNames] ; Required section 1 = ,"common files",,C:\Dokumente und Einstellungen\xyz\Dev;A existing folder on your HD, where the common files to be copied are found (not processor specific)
[SourceDisksNames.ARM] 2 = ,"ARM files",,arm;folder below the common files folder above for ARM specific files
[SourceDisksFiles] ; Required section, application binary, files to copy bilettixscan.EXE = 2 sqlite3.DLL = 2 bilettix.db = 2
[DestinationDirs] ; Required section Shortcuts.All = 0,%CE11% DefaultDestDir = 0,%InstallDir%
[CEStrings] ; Required section AppName = Ticket Validator InstallDir = %CE1%\%AppName%
[Shortcuts.All] %AppName%,0,bilettixscan.exe
[RegData] HKLM,Software\bilettix\%AppName%,MajorVersion,0x00010001,1 HKLM,Software\bilettix\%AppName%,MinorVersion,0x00010001,0 HKLM,Software\bilettix\%AppName%,Installpath,0x00000000,%InstallDir% </delphi>