WinCE Programming Tips/ru

From Free Pascal wiki
Revision as of 19:51, 20 August 2010 by Romlo (talk | contribs)
Jump to navigationJump to search
WinCE Logo.png

Эта статья относится только к WinCE.

См. также: Multiplatform Programming Guide

English (en) русский (ru)

На этой странице описано несколько приёмов работы с платформой WinCE.

Other Interfaces

Platform specific Tips

Interface Development Articles

Советы / ЧаВо

Приложение работает на эмуляторе, но не работает на устройстве

Когда приложение запущено на эмуляторе, всё нормально, однако на устройстве возникает ошибка типа:

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(на английском):

А здесь(тоже на английском) изменения в версиях библиотеки 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>