Sign in Join
Wiki copytemporary

WinCE Programming Tips/ru: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11На этой странице описано несколько приёмов работы с платформой WinCE.
22
33## Если приложение не запускается?..
44
55Если вы написали и скомпилировали ваше приложение под ОС Windows CE и оно прекрасно запускается на эмуляторе, а на реальном устройстве нет (при попытке запуска возникает системная ошибка), возможны следующие варианты:
66
77#### Настройки компилятора
88
99Убедитесь, что в среде Lazarus установлены правильные настройки компиляции приложения. Они должны быть такими:
1010
11-`"Меню" -> "Проект" -> "Параметры компилятора"`
11+```text
12+"Меню" -> "Проект" -> "Параметры компилятора"
13+```
1214
1315здесь :
1416
1517- на первой владке "Пути", в самом низу в выпадающем меню "Библиотека виджетов LCL" необходимо установить "wince"
1618
1719- на вкладке "Код" в блоке "Целевая платформа", необходимо установить название операционной системы "WinCE" и целевое семейство процессоров "arm" (если вы точно знаете, что на реальном устройстве стоит x86 процессор, соответственно надо выбрать "i386" из предложенного списка). В выпадающем меню "Целевой процессор" оставляем "По умолчанию"
1820
1921#### Не тот целевой процессор
2022
2123Если при попытке запуска программы на целевом устройстве возникает системная ошибка
2224
23-*`'Project1' is not a valid WindowsCE application`*
25+```text
26+ 'Project1' is not a valid WindowsCE application
27+```
2428
2529возможно, на устройстве установлен не ARM, наиболее распространённый, а MIPS-процессор, который, к сожалению, не поддерживается компилятором Lazarus. Тут уж ничего не поделаешь.
2630
2731#### Отсутствие некоторых DLL в целевой ОС
2832
2933Ошибки типа :
3034
31-*`Cannot find 'project1' (or one of its components)`*
35+```text
36+Cannot find 'project1' (or one of its components)
37+```
3238
33-*`'project1' (или один из компонентов) не найден`*
39+```text
40+ 'project1' (или один из компонентов) не найден
41+```
3442
3543а так же, вышеупомянутая
3644
37-*`'Project1' is not a valid WindowsCE application`*
45+```text
46+ 'Project1' is not a valid WindowsCE application
47+```
3848
3949очень часто могут возникать из-за отсутствия системной библиотеки aygshell.dll в составе ОС на целевом устройстве.
4050
4151В 90% случаев такая проблема возникает на устройствах, на которых установлена "голая" версия Windows CE "core" (навигаторы, читалки книг, считыватели штрих-кодов), на устройствах под управлением Windows Mobile эта проблема не возникает.
4252
4353Вот так выглядит ошибка на навигаторе Acer p610 :
4454
4555![](/wiki-images/9/93/Winceerr.gif)
4656
4757Проблема решается распространением aygshell.dll вместе с программой (таким образом поступают разработчики GPS-программы Navitel) или записью этой библиотеки в системную директорию //Windows.
4858
4959Вот здесь можно скачать архив с несколькими версиями aygshell.dll для разных версий ОС WinCE:
5060
5161- <http://hpcmonex.net/izemize.htm>
5262
5363Если "прикручивание" aygshell.dll к программе не дало результатов и ошибка все равно возникает, возможно версия целевой ОС ниже требуемой и она просто не имеет той функциональности, которую требует разработанная программа. Часто такая ситуация провоцируется отсутствием требуемых функций в более ранней версии системной библиотеки coredll.dll.
5464
5565## Советы по программированию / примеры
5666
5767### Получить ID устройства
5868
5969Идентификация устройства полезна для защиты вашей программы. Работает только на windows mobile 5.1 и 5.2
6070
6171``` pascal
6272
6373function GetDeviceUniqueID(AppData:LPCWSTR; cbApplictionData:Integer; dwDeviceIDVersion:Integer;
6474 var deviceIDOuput; var pcbDeviceIDOutput:DWORD):Integer; external 'coredll.dll' name 'GetDeviceUniqueID';
6575
6676function GetDeviceID: string;
6777var
6878 AppData: array[0..19] of WideChar;
6979 DeviceID : array[0..19] of Byte;
7080 Count: DWORD;
7181 s: string;
7282 Res, i:Integer;
7383begin
7484 //not sure about Unicode
7585 AppData := Utf8Decode('MY_SIG');
7686 Count := SizeOf(DeviceID);
7787 FillChar(DeviceID, Count, #0);
7888 Res := GetDeviceUniqueID(AppData, SizeOF(AppData), 1, DeviceID, Count);
7989 if Res = 0 then
8090 begin
8191 Result := '';
8292 for i := 0 to Count -1 do
8393 begin
8494 if (i > 0) and ((i mod 2) = 0) then
8595 Result := Result + '-'; //add space make the string wrap in label
8696 Result := Result + IntToHex(DeviceID[i], 2);
8797 end;
8898 end
8999 else
90100 Result := '';//error accord
91101// you can MD5 it with your string
92102// Result := MD5Print(MD5Buffer(DeviceID, Count));
93103end;
94104```
95105
96106Ссылки: <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>
97107
98108### Получить имя устройства
99109
100110Это легко сделать через реестр:
101111
102112``` pascal
103113function GetDeviceName: string;
104114var
105115 aReg:TRegistry;
106116begin
107117 aReg := TRegistry.Create(KEY_READ);
108118 try
109119 aReg.RootKey := HKEY_LOCAL_MACHINE;
110120 aReg.OpenKey('Ident', False);
111121 if aReg.ValueExists('Name') then
112122 Result := aReg.ReadString('Name')
113123 else
114124 Result := 'GUEST';
115125 finally
116126 aReg.Free;
117127 end;
118128end;
119129```
120130
121131### Показать/спрятать SIP Panel
122132
123133Виртуальная клавиатура для сенсорных экранов(SIP: Software Input Panel button).
124134
125135``` pascal
126136const
127137 //Некоторые константы
128138 SIPF_OFF = $00000000;
129139 SIPF_ON = $00000001;
130140 SIPF_DOCKED = $00000002;
131141 SIPF_LOCKED = $00000004;
132142
133143function SipShowIM(IPStatus:DWORD):Integer; stdcall; external 'coredll.dll' name 'SipShowIM';
134144
135145begin
136146 SipShowIM(SIPF_ON)
137147end;
138148```
139149
140150Документация microsoft об этом: [1](http://msdn.microsoft.com/en-us/library/ms941818.aspx)
141151
142152### Включить/разбудить устройство
143153
144154Понадобится любителям будильников.
145155
146156``` pascal
147157function SetSystemPowerState(psState: PWideChar; StateFlags: DWORD; Options : DWORD):DWORD;
148158 stdcall; external 'coredll.dll' name 'SetSystemPowerState';
149159
150160 SetSystemPowerState(nil, POWER_STATE_ON, POWER_FORCE);
151161 Application.BringToFront;
152162 ShowWindow(Handle, SW_SHOW);
153163```
154164
155165### Подсветка/вибрация
156166
157167Вы можете включать/выключать подсветку и вибратор. У меня работало нормально (а вот автор статьи говорит, что работает, но не так, как хотелось бы, и что, видимо будут доработки).
158168
159169``` pascal
160170const
161171 NLED_COUNT_INFO_ID = 0;
162172 NLED_SUPPORTS_INFO_ID = 1;
163173 NLED_SETTINGS_INFO_ID = 2;
164174
165175type
166176 TNLED_COUNT_INFO = record
167177 cLeds: DWORD;
168178 end;
169179
170180 TNLED_SETTINGS_INFO = record
171181 LedNum: DWORD; // LED number, 0 is first LED
172182 OffOnBlink: Integer; // 0 = выкл, 1 = вкл, 2 = мигание
173183 TotalCycleTime: DWORD; // Общее время мигания в микросекундах.
174184 OnTime: DWORD; // Время вкл. в цикле в микросекундах.
175185 OffTime: DWORD; // Время выкл. в цикле в микросекундах.
176186 MetaCycleOn: Integer; // Число вкл. циклов миганий
177187 MetaCycleOff: Integer; // Число выкл. циклов миганий
178188 end;
179189
180190 function NLedGetDeviceInfo(nID:Integer; var pOutput): WordBool;
181191 stdcall; external 'coredll.dll' name 'NLedGetDeviceInfo';
182192 function NLedSetDevice(nID: Integer; var pOutput): WordBool;
183193 stdcall; external 'coredll.dll' name 'NLedSetDevice';
184194```
185195
186196Примеры:
187197
188198``` pascal
189199function TForm1.MakeLEDOn;
190200var
191201 Countnfo: TNLED_COUNT_INFO;
192202 Info:TNLED_SETTINGS_INFO;
193203begin
194204 NLedGetDeviceInfo(NLED_COUNT_INFO_ID, Countnfo);
195205 //with Countnfo.cLeds you can check if your device support LEDs;
196206 Info.LedNum := 0; //<--- First LED
197207 Info.OffOnBlink := 1;
198208 Info.OffTime := 0;
199209 Info.MetaCycleOff:= 50;
200210 Info.MetaCycleOn:= 50;
201211 Info.TotalCycleTime := 100;
202212 NLedSetDevice(NLED_SETTINGS_INFO_ID, Info);
203213end;
204214
205215procedure TForm1.MakeLedOff;
206216var
207217 Info:TNLED_SETTINGS_INFO;
208218begin
209219 Info.LedNum := 0;
210220 Info.OffOnBlink := 0;
211221 NLedSetDevice(NLED_SETTINGS_INFO_ID, Info);
212222end;
213223```
214224
215225Вибратор - это последний индикатор устройства.
216226
217227``` pascal
218228function TForm1.MakeVibratorOn;
219229var
220230 Countnfo: TNLED_COUNT_INFO;
221231 Info:TNLED_SETTINGS_INFO;
222232begin
223233 NLedGetDeviceInfo(NLED_COUNT_INFO_ID, Countnfo);
224234 Info.LedNum := Countnfo.cLeds -1;
225235 Info.OffOnBlink := 1;
226236 NLedSetDevice(NLED_SETTINGS_INFO_ID, Info);
227237end;
228238
229239function TForm1.MakeVibratorOff;
230240var
231241 Countnfo: TNLED_COUNT_INFO;
232242 Info:TNLED_SETTINGS_INFO;
233243begin
234244 NLedGetDeviceInfo(NLED_COUNT_INFO_ID, Countnfo);
235245 Info.LedNum := Countnfo.cLeds -1;
236246 Info.OffOnBlink := 0;
237247 NLedSetDevice(NLED_SETTINGS_INFO_ID, Info);
238248end;
239249```
240250
241251### Получение состояния батареи
242252
243253#### GetSystemPowerStatusEx
244254
245255Больше об этом(опять-таки на английском) : [MSDN GetSystemPowerStatusEx](http://msdn.microsoft.com/en-us/library/aa453172.aspx)
246256
247257``` pascal
248258//by Philip Heinisch
249259 type
250260 TBAT_INFO = record
251261 ACLineStatus:byte; //0=Offline, 1=Online, 2=Backup Power,3= Unknown status
252262 BatteryFlag:byte; //0=High, 1=Low, 2=Critical, 3=Charging, 4=No Battery, 5=Unknown
253263 BatteryLifePercent:byte; //0..100 Battery Life in Percent
254264 Reserved1:byte; //always 0
255265 BatteryLifeTime: DWORD; //remaining time in seconds
256266 BatteryFullLifeTime: DWORD; //max usage time in seconds
257267 Reserved2:byte; //always 0
258268 BackupBatteryFlag:byte; //0=High, 1=Low, 2=Critical, 3=Charging, 4=No Battery, 5=Unknown
259269 BackupBatteryLifePercent:byte; //0..100 Backup Battery Life in Percent
260270 Reserved3:byte; //always 0
261271 BackupBatteryLifeTime: DWORD; //remaining time in seconds
262272 BackupBatteryFullLifeTime: DWORD; //max usage time in seconds
263273 end;
264274
265275 function GetSystemPowerStatusEx(var pOutput;fUpdate:boolean ): WordBool;
266276 stdcall; external 'coredll.dll' name 'GetSystemPowerStatusEx';
267277
268278//Usage Example:
269279
270280function getbat : byte;
271281var
272282 batinfo: TBAT_INFO;
273283begin
274284if GetSystemPowerStatusEx(batinfo,True) then getbat:=batinfo.BatteryLifePercent
275285else getbat:=255; //255=Function Call Failed
276286end;
277287```
278288
279289#### GetSystemPowerStatusEx2
280290
281291Больше об этом(Угадайте, на каком языке?) : [MSDN GetSystemPowerStatusEx2](http://msdn.microsoft.com/en-us/library/aa931066.aspx)
282292
283293``` pascal
284294//добавил romlo
285295 type
286296 TBAT_INFO2 = record
287297 ACLineStatus: byte; // состояние внешнего питания
288298 BatteryFlag: byte; // состояние основной батареи
289299 BatteryLifePercent: byte; // процент зарядки основной батареи
290300 BatteryLifeTime: DWord; // время, на которое хватит заряда
291301 BatteryFullLifeTime: DWord; // время, на которое хватит полной батареи
292302 BackupBatteryFlag: byte; // состояние резервной батареи
293303 BackupBatteryLifePercent: byte; // процент заряда резервной батареи
294304 BackupBatteryLifeTime: DWord; // время остатка заряда резервной батареи
295305 BackupBatteryFullLifeTime: DWord; // полное время резервной батареи
296306 //Физические характеристики батареи:
297307 BatteryVoltage: Dword; // напряжение батреи (mV)
298308 BatteryCurrent: DWord; // сила тока батареи (mA)
299309 BatteryAverageCurrent: DWord; // средний ток
300310 BatteryAverageInterval: DWord; // интервал изменения тока
301311 BatterymAHourConsumed: DWord; // емкость батареи в mA/h
302312 BatteryTemperature: DWord; // температура батареи
303313 BackupBatteryVoltage: DWord; // емкость резервной батареи
304314 BatteryChemistry: Byte; // тип батареи (LION, NiCD, NIMN… )
305315
306316 function GetSystemPowerStatusEx2(var pOutput; DwLen: DWord; fUpdate: boolean ): WordBool;
307317 stdcall; external 'coredll.dll' name 'GetSystemPowerStatusEx2';
308318
309319//Пример:
310320
311321function getbat2 : byte;
312322var
313323 batinfo: TBAT_INFO2;
314324begin
315325if GetSystemPowerStatusEx2(batinfo,SizeOf(batinfo), True) then getbat:=batinfo.BatteryLifePercent
316326else getbat:=255;
317327end;
318328```
319329
320330### Создание полноэкранного приложения
321331
322332Добавьте в раздел uses модуль windows и добавьте следующий код в раздел **interface** вашей программы:
323333
324334``` pascal
325335const
326336 //ShFullScreen
327337 SHFS_SHOWTASKBAR = $01;
328338 SHFS_HIDETASKBAR = $02;
329339 SHFS_SHOWSIPBUTTON = $04;
330340 SHFS_HIDESIPBUTTON = $08;
331341 SHFS_SHOWSTARTICON = $10;
332342 SHFS_HIDESTARTICON = $20;
333343
334344 function SHFullScreen(hwndRequester: hWnd; dwState: DWord): WINBOOL; stdcall; external 'aygshell.dll' name 'SHFullScreen';
335345```
336346
337347Затем вставьте в события OnCreate и OnShow ваших форм (лучше OnShow) следующее:
338348
339349``` pascal
340350procedure TForm1.FormCreate(Sender: TObject);
341351var
342352 Rect:TRect;
343353 hTaskBar:THandle;
344354 menuh:Integer;
345355begin
346356 hTaskBar := FindWindow('HHTaskBar','');
347357 GetWindowRect(hTaskBar,rect);
348358 menuh:=Rect.Bottom-Rect.Top;
349359 GetWindowRect(Form1.Handle,Rect);
350360 SHFullScreen(Form1.Handle,SHFS_HIDETASKBAR or SHFS_HIDESTARTICON or SHFS_HIDESIPBUTTON);
351361 movewindow(Form1.Handle,Rect.Left,Rect.Top-menuh,Rect.Right,Rect.Bottom+menuh,True);
352362end;
353363```
354364
355365### Препятствие входу в режим ожидания
356366
357367Добавьте на форму таймер, в событии OnTimer пропишите следующую строку:
358368
359369``` pascal
360370keybd_event(VK_F24, 0, KEYEVENTF_KEYUP or KEYEVENTF_SILENT, 0);
361371```
362372
363373### Установка приложения на WinCe через app build(cab файл)
364374
365375//Original de Hinnack (from Lazarus forum)
366376
367377У меня ушло много времени на то, что-бы выяснить, как установить моё приложение на WinCE-устройство(Да, я знаю, что можно скопировать и вставить), поэтому я решил поделиться этим здесь.
368378
3693791\) Во-первых, нужен ini-файл (может, когда-нибудь, Лазарус сможет генерировать их сам...). Хороший рассказ о том, как это можно сделать, есть здесь(на англ.): <http://web.archive.org/web/20080205125046/> <http://www.sundialsoft.freeserve.co.uk/cabinfo.htm> (Оригинальный сайт мёртв) Я использовал следующее (только для ARM процессоров):
370380
371381``` pascal
372382[Version] ; Обязательная секция
373383Signature = "$Windows NT$"
374384Provider = "bilettiX"
375385CESignature = "$Windows CE$"
376386
377387[CEDevice.ARM]
378388ProcessorType = 2577 ; значение для ARM
379389
380390[DefaultInstall.ARM]
381391CopyFiles = Files.ARM
382392
383393[Files.ARM]
384394bilettixscan.exe,,,0
385395sqlite3.dll,,,0
386396
387397[DefaultInstall] ; Обязательная секция
388398CEShortcuts = Shortcuts.All
389399AddReg = RegData
390400
391401[SourceDisksNames] ; Обязательная секция
3924021 = ,"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)
393403
394404[SourceDisksNames.ARM]
3954052 = ,"ARM files",,arm;Папка со специальными ARM файлами
396406[SourceDisksFiles] ; Обязательная секция, бинарник приложения, файлы для копирования
397407bilettixscan.EXE = 2
398408sqlite3.DLL = 2
399409bilettix.db = 2
400410
401411[DestinationDirs] ; Обязательная секция
402412Shortcuts.All = 0,%CE11%
403413DefaultDestDir = 0,%InstallDir%
404414
405415[CEStrings] ; Обязательная секция
406416AppName = Ticket Validator
407417InstallDir = %CE1%\%AppName%
408418
409419[Shortcuts.All]
410420%AppName%,0,bilettixscan.exe
411421
412422[RegData]
413423HKLM,Software\bilettix\%AppName%,MajorVersion,0x00010001,1
414424HKLM,Software\bilettix\%AppName%,MinorVersion,0x00010001,0
415425HKLM,Software\bilettix\%AppName%,Installpath,0x00000000,%InstallDir%
416426```
417427
4184282\) теперь создаём cab файл из наших файлов, используя утилиту cabWiz из SDK от MS и ini-файл. 3) генерируем install.ini - мой выглядел так(на самом деле icon-section не нужна...):
419429
420430``` pascal
421431[CEAppManager]
422432Version = 1.0
423433Component = Ticket Validator
424434
425435[Ticket Validator]
426436Description = bilettiX Ticket Validator
427437Uninstall = bilettiXscan
428438DeviceFile = bilettiXscan.exe
429439IconFile = bilettix.ico
430440IconIndex = 0
431441CabFiles = bilettiXscan.ARM.CAB
432442```
433443
4344444\) Затем берём EzSetup for free отсюда: <http://www.spbsoftwarehouse.com/products/ezsetup/index.html>
435445
4364465\) Генерируем "установщик", используя ini, readme и лицензионное соглашение в txt файлах.
437447
4384486\) Готово! :-)
439449
440450Удостоверьтесь, что у вас стоит ActiveSync. Двойной клик по полученному файлу, и всё, наслаждайтесь :-)
441451
442452--Blueicaro 21:49, 29 April 2009 (CEST)
443453
444454### Debugging with a log file
445455
446456Windows CE doesn't ship with a command line, so people used to command-line log debugging may have trouble. In some versions of Windows CE it is possible to install a command-line, but another solution for this is using the logging routines from the LCLProc unit in Lazarus to write log information to a file in the same directory as the executable and then read it, as in the code bellow.
447457
448458``` pascal
449459uses LCLProc;
450460
451461DbgAppendToFile(ExtractFilePath(ParamStr(0)) + '1.log', 'Some text');
452462```
453463
454464The unit LCLProc also contains other cool routines for debugging, like GetStackTrace, which returns a string with the stack trace.
455465
456466### Current Directory and Placement of DLLs
457467
458468Windows CE does not have the concept of current directory, so there is no point in placing DLLs in the same folder of the executable, as they will not be loaded from there. They need to be on the \Windows directory or another suitable location.
459469
460470## Database Tips
461471
462472### Pre-compiled sqlite dll
463473
464474You can find sqlite3.dll pre-compiled for Windows CE [here](ftp://ftp.freepascal.org/pub/fpc/contrib/arm-wince-sqlite322.zip).
465475
466476## Links
467477
468478Here are some links that might be useful for creating Windows CE interfaces.
469479
470480- [[Windows CE Development Notes]]
471481- [[KOL-CE|WinCE port of KOL GUI library]]
472482
473483---
474484*From the Free Pascal wiki, page "WinCE Programming Tips/ru", as it stood on 2020-03-04 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history