Difference between revisions of "WinCE Programming Tips"

From Lazarus wiki
Jump to navigationJump to search
Line 244: Line 244:
 
=== Making a Fullscreen Application ===
 
=== Making a Fullscreen Application ===
  
Make sure that in you have included the windows unit to your program (uses windows;) In the INTERFACE section of your program paste the following code:
+
Make sure that you have included the windows unit to your program (uses windows;) In the INTERFACE section of your program paste the following code:
 
<delphi>
 
<delphi>
 
const
 
const

Revision as of 09:00, 17 August 2009

WinCE Logo.png

This article applies to WinCE only.

See also: Multiplatform Programming Guide

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

This page is a under construction reference to help in the development for the Windows CE platform, covering common programming topics specific to it.

Other Interfaces

Platform specific Tips

Interface Development Articles

TIPS / FAQ

Application runs on Windows Device Emulator, but not on physical device

When running a compiled application on the Windows Device emulator, it works fine, but running it on the physical device you get the error:

Cannot find 'project1' (or one of its components).

This is usually indicative of missing DLLs on the target device, especially if you have a very simple "Hello World" type of application. In many instances, it is related to the aygshell.dll file, which is not present on many industrial-type devices running a bare Windows CE version - normally devices running "Windows Mobile" versions of Windows CE will not have this problem.

This problem has been reported on Motorolla/Symbol MC9000 and MC1000 barcode scanners running both Windows CE 4.2 and 5.

To resolve, do a search for "aygshells.zip" in a search engine - there are some "Dummy" aygshell.dll files available that can be copied to the device to overcome this problem.

Get Device ID

Get and ID of your device useful for protect your application. This work only on Windows Mobile 5.0 and Windows CE 5.1 <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');//any string you like
 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> Reference pages: 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

Get Device Name

Easy to get it from registry

<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>

Show/Hide SIP Panel

SIP: Software Input Panel button, it is a keyboard come with WinCE for touch screen devices.

<delphi> const

 //some of consts already found in Windows
 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 documentation for the SipShowIM routine: [1]

Wakeup Device/ Power On

If you like to make alarm application this function make your device power on, you need also make some sounds with it.

<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>

LED / Vibrator

You can turn on/off then LED/vibrator in, your device, it worked for me but not as like as i want, may be it need some improvements.

<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 = off, 1 = on, 2 = blink
   TotalCycleTime: DWORD;         // total cycle time of a blink in microseconds
   OnTime: DWORD;                 // on time of a cycle in microseconds
   OffTime: DWORD;                // off time of a cycle in microseconds
   MetaCycleOn: Integer;          // number of on blink cycles
   MetaCycleOff: Integer;         // number of off blink cycles
  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>

Examples

<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>


Vibrator it is the last LED in your device, if you can write some music you can now make your phone dance. <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>

Getting Battery Status

For more information : 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>

Making a Fullscreen Application

Make sure that you have included the windows unit to your program (uses windows;) In the INTERFACE section of your program paste the following code: <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> Then in your Forms, OnCreate or OnShow (better on the OnShow) event add the following code: <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>

Installation of an app build with Lazarus on a WinCE device

//Original de Hinnack (from Lazarus forum) Hi,

it took me a long time to figure out, how to install my app on a wince device (yes, I know I can do copy and paste...), so I thought I should share it here: 1) one needs a inf file (maybe Lazarus could generate one on his own some time...). A good brief on how to create one can be found here: http://web.archive.org/web/20080205125046/http://www.sundialsoft.freeserve.co.uk/cabinfo.htm (original website is dead) I used the following (only for ARM prozessors):

<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>

2) now create a cab file out of your files using this inf file by using cabwiz.exe from the platform SDK of MS 3) generate a install.ini - my looks like this (icon-section is nor really needed...): <delphi> [CEAppManager] Version = 1.0 Component = Ticket Validator

[Ticket Validator] Description = bilettiX Ticket Validator Uninstall = bilettiXscan DeviceFile = bilettiXscan.exe IconFile = bilettix.ico IconIndex = 0 CabFiles = bilettiXscan.ARM.CAB </delphi> 4) download EzSetup for free from here: http://www.spbsoftwarehouse.com/products/ezsetup/index.html

5) generate the installer using the ini-file, a readme and a eula file you generated as txt files

6) done :-)

be sure to have ActiveSync installed. double-click the installer and have fun :-)

--Blueicaro 21:49, 29 April 2009 (CEST)

Links

Here are some links that might be useful for creating Windows CE interfaces.

Windows CE Development Notes

WinCE port of KOL GUI library