Difference between revisions of "WinCE Programming Tips"

From Free Pascal wiki
Jump to navigationJump to search
m (Re-arrange content)
 
(18 intermediate revisions by 4 users not shown)
Line 1: Line 1:
 
{{WinCE Programming Tips}}
 
{{WinCE Programming Tips}}
 
This page is a under construction reference to help in the development for the Windows CE platform, covering common programming topics specific to it.
 
__TOC__
 
{{Other Interfaces}}
 
  
 
== TIPS / FAQ ==
 
== TIPS / FAQ ==
Line 19: Line 15:
  
 
=== Application runs on Windows Device Emulator, but not on physical device ===
 
=== 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
 
When running a compiled application on the Windows Device emulator, it works fine, but
 
running it on the physical device you get the error:
 
running it on the physical device you get the error:
Line 52: Line 49:
  
 
=== Get Device ID ===
 
=== Get Device ID ===
 +
 
Get and ID of your device useful for protect your application.  
 
Get and ID of your device useful for protect your application.  
 
This work only on Windows Mobile 5.0 and Windows CE 5.1
 
This work only on Windows Mobile 5.0 and Windows CE 5.1
<delphi>
+
 
 +
<syntaxhighlight lang="pascal">
  
 
function GetDeviceUniqueID(AppData:LPCWSTR; cbApplictionData:Integer; dwDeviceIDVersion:Integer;
 
function GetDeviceUniqueID(AppData:LPCWSTR; cbApplictionData:Integer; dwDeviceIDVersion:Integer;
Line 87: Line 86:
 
//  Result := MD5Print(MD5Buffer(DeviceID, Count));
 
//  Result := MD5Print(MD5Buffer(DeviceID, Count));
 
end;
 
end;
</delphi>
+
</syntaxhighlight>
 +
 
 
Reference pages:
 
Reference pages:
 
http://msdn2.microsoft.com/en-us/library/ms893522.aspx
 
http://msdn2.microsoft.com/en-us/library/ms893522.aspx
Line 94: Line 94:
  
 
=== Get Device Name ===
 
=== Get Device Name ===
 +
 
Easy to get it from registry
 
Easy to get it from registry
  
<delphi>
+
<syntaxhighlight lang="pascal">
 
function GetDeviceName: string;
 
function GetDeviceName: string;
 
var
 
var
Line 113: Line 114:
 
   end;
 
   end;
 
end;
 
end;
</delphi>
+
</syntaxhighlight>
  
 
=== Show/Hide SIP Panel ===
 
=== Show/Hide SIP Panel ===
 +
 
SIP: Software Input Panel button, it is a keyboard come with WinCE for touch screen devices.
 
SIP: Software Input Panel button, it is a keyboard come with WinCE for touch screen devices.
  
<delphi>
+
<syntaxhighlight lang="pascal">
 
const
 
const
 
   //some of consts already found in Windows
 
   //some of consts already found in Windows
Line 132: Line 134:
 
end;
 
end;
  
</delphi>
+
</syntaxhighlight>
  
 
Microsoft documentation for the SipShowIM routine: [http://msdn.microsoft.com/en-us/library/ms941818.aspx]
 
Microsoft documentation for the SipShowIM routine: [http://msdn.microsoft.com/en-us/library/ms941818.aspx]
  
 
=== Wakeup Device/ Power On ===
 
=== 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.
 
If you like to make alarm application this function make your device power on, you need also make some sounds with it.
  
<delphi>
+
<syntaxhighlight lang="pascal">
 
function SetSystemPowerState(psState: PWideChar; StateFlags: DWORD; Options : DWORD):DWORD;
 
function SetSystemPowerState(psState: PWideChar; StateFlags: DWORD; Options : DWORD):DWORD;
 
  stdcall; external 'coredll.dll' name 'SetSystemPowerState';
 
  stdcall; external 'coredll.dll' name 'SetSystemPowerState';
Line 147: Line 150:
 
   Application.BringToFront;
 
   Application.BringToFront;
 
   ShowWindow(Handle, SW_SHOW);
 
   ShowWindow(Handle, SW_SHOW);
</delphi>
+
</syntaxhighlight>
  
 
=== LED / Vibrator ===
 
=== 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.
 
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>
+
<syntaxhighlight lang="pascal">
 
const
 
const
 
   NLED_COUNT_INFO_ID = 0;
 
   NLED_COUNT_INFO_ID = 0;
Line 177: Line 181:
 
   function NLedSetDevice(nID: Integer; var pOutput): WordBool;
 
   function NLedSetDevice(nID: Integer; var pOutput): WordBool;
 
   stdcall; external 'coredll.dll' name 'NLedSetDevice';
 
   stdcall; external 'coredll.dll' name 'NLedSetDevice';
</delphi>
+
</syntaxhighlight>
  
 
Examples
 
Examples
  
<delphi>
+
<syntaxhighlight lang="pascal">
 
function TForm1.MakeLEDOn;
 
function TForm1.MakeLEDOn;
 
var
 
var
Line 207: Line 211:
 
end;   
 
end;   
  
</delphi>
+
</syntaxhighlight>
  
 +
Vibrator it is the last LED in your device, if you can write some music you can now make your phone dance.
  
Vibrator it is the last LED in your device, if you can write some music you can now make your phone dance.
+
<syntaxhighlight lang="pascal">
<delphi>
 
 
function TForm1.MakeVibratorOn;
 
function TForm1.MakeVibratorOn;
 
var
 
var
Line 233: Line 237:
 
   NLedSetDevice(NLED_SETTINGS_INFO_ID, Info);
 
   NLedSetDevice(NLED_SETTINGS_INFO_ID, Info);
 
end;   
 
end;   
</delphi>
+
</syntaxhighlight>
  
 
=== Getting Battery Status ===
 
=== Getting Battery Status ===
 +
 
For more information : [http://msdn.microsoft.com/en-us/library/aa453172.aspx MSDN GetSystemPowerStatusEx]
 
For more information : [http://msdn.microsoft.com/en-us/library/aa453172.aspx MSDN GetSystemPowerStatusEx]
  
<delphi>
+
<syntaxhighlight lang="pascal">
 
//by Philip Heinisch
 
//by Philip Heinisch
 
  type
 
  type
Line 268: Line 273:
 
else getbat:=255; //255=Function Call Failed  
 
else getbat:=255; //255=Function Call Failed  
 
end;
 
end;
</delphi>
+
</syntaxhighlight>
  
 
=== Prevent Phone from Entering in Standby Mode ===
 
=== Prevent Phone from Entering in Standby Mode ===
  
 
Inside a timer event add the following line of code:
 
Inside a timer event add the following line of code:
<delphi>
+
<syntaxhighlight lang="pascal">
 
keybd_event(VK_F24, 0, KEYEVENTF_KEYUP or KEYEVENTF_SILENT, 0);
 
keybd_event(VK_F24, 0, KEYEVENTF_KEYUP or KEYEVENTF_SILENT, 0);
</delphi>
+
</syntaxhighlight>
  
  
 
=== Installation of an app build with Lazarus on a WinCE device ===
 
=== 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:
+
The simplest way to install an app is to simply copy the executable and other files it needs, but a proper installer can be made with the instructions bellow:
 
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)
 
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):
 
I used the following (only for ARM prozessors):
  
<delphi>
+
<syntaxhighlight lang="ini">
 
[Version] ; Required section
 
[Version] ; Required section
 
Signature = "$Windows NT$"
 
Signature = "$Windows NT$"
Line 332: Line 335:
 
HKLM,Software\bilettix\%AppName%,MinorVersion,0x00010001,0
 
HKLM,Software\bilettix\%AppName%,MinorVersion,0x00010001,0
 
HKLM,Software\bilettix\%AppName%,Installpath,0x00000000,%InstallDir%
 
HKLM,Software\bilettix\%AppName%,Installpath,0x00000000,%InstallDir%
</delphi>
+
</syntaxhighlight>
  
 
2) now create a cab file out of your files using this inf file by using cabwiz.exe from the platform SDK of MS
 
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...):
 
3) generate a install.ini - my looks like this (icon-section is nor really needed...):
<delphi>
+
 
 +
<syntaxhighlight lang="ini">
 
[CEAppManager]
 
[CEAppManager]
 
Version = 1.0
 
Version = 1.0
Line 348: Line 352:
 
IconIndex = 0
 
IconIndex = 0
 
CabFiles = bilettiXscan.ARM.CAB
 
CabFiles = bilettiXscan.ARM.CAB
</delphi>
+
</syntaxhighlight>
 +
 
 
4) download EzSetup for free from here: http://www.spbsoftwarehouse.com/products/ezsetup/index.html
 
4) download EzSetup for free from here: http://www.spbsoftwarehouse.com/products/ezsetup/index.html
  
Line 356: Line 361:
  
 
be sure to have ActiveSync installed. double-click the installer and have fun :-)
 
be sure to have ActiveSync installed. double-click the installer and have fun :-)
 
--[[User:Blueicaro|Blueicaro]] 21:49, 29 April 2009 (CEST)
 
  
 
=== Debugging with a log file ===
 
=== Debugging with a log file ===
Line 363: Line 366:
 
Windows 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.
 
Windows 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.
  
<delphi>
+
<syntaxhighlight lang="pascal">
 
uses LCLProc;
 
uses LCLProc;
  
 
DbgAppendToFile(ExtractFilePath(ParamStr(0)) + '1.log', 'Some text');
 
DbgAppendToFile(ExtractFilePath(ParamStr(0)) + '1.log', 'Some text');
</delphi>
+
</syntaxhighlight>
  
 
The unit LCLProc also contains other cool routines for debugging, like GetStackTrace, which returns a string with the stack trace.
 
The unit LCLProc also contains other cool routines for debugging, like GetStackTrace, which returns a string with the stack trace.
  
=== Current Directory and Placement of DLLs ===
+
=== Current Directory and Placement of DLLs ===
 +
 +
Windows CE does not have the concept of current directory, so paths to files should always be complete and never relative to the executable path.
  
Windows 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.
+
As one exception to this rule, DLLs can be placed in the same folder as the executable and they will be loaded from there. Another suitable location for DLLs is the \Windows directory.
  
 
=== Going Full Screen ===
 
=== Going Full Screen ===
Line 385: Line 390:
 
Note that if you don't provide a quit button it will be then impossible to close the application and that if the application crashes, the taskbar will not be restored automatically. Rebooting the device will restore it.
 
Note that if you don't provide a quit button it will be then impossible to close the application and that if the application crashes, the taskbar will not be restored automatically. Rebooting the device will restore it.
  
<delphi>
+
<syntaxhighlight lang="pascal">
 
uses Windows, aygshell;
 
uses Windows, aygshell;
  
Line 419: Line 424:
 
   end;
 
   end;
 
end;
 
end;
</delphi>
+
</syntaxhighlight>
  
 
====Removing the Virtual Keyboard====
 
====Removing the Virtual Keyboard====
Line 425: Line 430:
 
One can remove the keyboard with SHFS_HIDESIPBUTTON, like this:
 
One can remove the keyboard with SHFS_HIDESIPBUTTON, like this:
  
<delphi>
+
<syntaxhighlight lang="pascal">
 
uses Windows, aygshell;
 
uses Windows, aygshell;
  
Line 433: Line 438:
 
   else SHFullScreen(Handle, SHFS_SHOWSIPBUTTON);
 
   else SHFullScreen(Handle, SHFS_SHOWSIPBUTTON);
 
end;
 
end;
</delphi>
+
</syntaxhighlight>
  
 
==== Alternative way with SHFullScreen ====
 
==== Alternative way with SHFullScreen ====
  
 
This is a different solution for going Fullscreen. 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:
 
This is a different solution for going Fullscreen. 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>
+
 
 +
<syntaxhighlight lang="pascal">
 
const
 
const
 
   //ShFullScreen
 
   //ShFullScreen
Line 450: Line 456:
 
   function SHFullScreen(hwndRequester: hWnd; dwState: DWord): WINBOOL;
 
   function SHFullScreen(hwndRequester: hWnd; dwState: DWord): WINBOOL;
 
   stdcall; external 'aygshell.dll' name 'SHFullScreen';  
 
   stdcall; external 'aygshell.dll' name 'SHFullScreen';  
</delphi>
+
</syntaxhighlight>
 +
 
 
Then in your Forms, OnCreate or OnShow (better on the OnShow) event add the following code:
 
Then in your Forms, OnCreate or OnShow (better on the OnShow) event add the following code:
<delphi>
+
 
 +
<syntaxhighlight lang="pascal">
 
procedure TForm1.FormCreate(Sender: TObject);
 
procedure TForm1.FormCreate(Sender: TObject);
 
var
 
var
Line 466: Line 474:
 
   movewindow(Form1.Handle,Rect.Left,Rect.Top-menuh,Rect.Right,Rect.Bottom+menuh,True);
 
   movewindow(Form1.Handle,Rect.Left,Rect.Top-menuh,Rect.Right,Rect.Bottom+menuh,True);
 
end;               
 
end;               
</delphi>
+
</syntaxhighlight>
 +
 
 +
=== Rotating the Screen ===
 +
 
 +
There is a Microsoft tutorial with code in C here about this: http://msdn.microsoft.com/en-us/library/ms812499.aspx
 +
Bellow is code equivalent to that tutorial, but in Pascal.
 +
 
 +
====Getting the Current Display Settings====
 +
 
 +
To obtain the current display settings, pass the ENUM_CURRENT_SETTINGS constant in the iModeNum parameter to the EnumDisplaySettings API, as illustrated by the following Pascal code.
 +
 
 +
<syntaxhighlight lang="pascal">
 +
var
 +
  dm: DEVMODE;
 +
begin
 +
  FillChar(dm, #0, SizeOf(dm));
 +
  dm.dmSize := sizeof(dm);
 +
 
 +
  if 0 <> EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, @dm) then
 +
  begin
 +
      // inspect the DEVMODE structure to obtain details
 +
      // about the display settings such as
 +
      //  - Orientation
 +
      //  - Width and Height
 +
      //  - Frequency
 +
      //  - etc.
 +
  end;
 +
</syntaxhighlight>
  
==Database Tips==
+
====Enumerating All Supported Display Settings====
 +
 
 +
To enumerate all display settings supported by the current display device pass zero in the iModeNum parameter to the EnumDisplaySettings API and then continue calling it with incremented iModeNum values until the function returns zero, as shown in the following Pascal code.
 +
 
 +
<syntaxhighlight lang="pascal">
 +
var
 +
  index: Integer = 0;
 +
  dm: DEVMODE;
 +
begin
 +
  FillChar(dm, #0, SizeOf(dm));
 +
  dm.dmSize := sizeof(dm);
 +
 
 +
  while 0 <> EnumDisplaySettings(NULL, index, @dm) do
 +
  begin
 +
      // inspect the DEVMODE structure to obtain details
 +
      // about the display settings such as
 +
      //  - Orientation
 +
      //  - Width and Height
 +
      //  - Frequency
 +
      //  - etc.
 +
    Inc(Index)
 +
  end;
 +
</syntaxhighlight>
 +
 
 +
====Changing Display Settings====
 +
 
 +
To change the display settings pass in a pointer to a valid DEVMODE structure to the ChangeDisplaySettings API. The following Pascal code demonstrates how to rotate the screen orientation clockwise by 90 degrees. Note that this code will only work with devices that support the respective display settings. It is important to obey the return value of the ChangeDisplaySettings API as some operations may require the computer to be restarted in order for the graphics mode to work.
 +
 
 +
<syntaxhighlight lang="pascal">
 +
var
 +
  dm: DEVMODE;
 +
  dwTemp: Cardinal;
 +
  lRet: Integer;
 +
begin
 +
  FillChar(dm, #0, SizeOf(dm));
 +
  dm.dmSize := sizeof(dm);
 +
 
 +
  if (0 <> EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, @dm)) do
 +
  begin
 +
      // swap height and width
 +
      dwTemp := dm.dmPelsHeight;
 +
      dm.dmPelsHeight:= dm.dmPelsWidth;
 +
      dm.dmPelsWidth := dwTemp;
 +
 
 +
      // determine new orientaion
 +
      case (dm.dmDisplayOrientation) of
 +
      DMDO_DEFAULT:    dm.dmDisplayOrientation := DMDO_270;
 +
      DMDO_270:  dm.dmDisplayOrientation := DMDO_180;
 +
      DMDO_180:  dm.dmDisplayOrientation := DMDO_90;
 +
      DMDO_90:    dm.dmDisplayOrientation := DMDO_DEFAULT;
 +
      else
 +
        // unknown orientation value
 +
        // add exception handling here
 +
      end;
 +
      lRet := ChangeDisplaySettings(@dm, 0);
 +
      if (DISP_CHANGE_SUCCESSFUL <> lRet) then
 +
      begin
 +
        // add exception handling here
 +
      end;
 +
  end;
 +
</syntaxhighlight>
 +
 
 +
==Pre-compiled Windows CE Libraries/Utils==
  
 
===Pre-compiled sqlite dll===
 
===Pre-compiled sqlite dll===
Line 476: Line 573:
 
And newer ones can be found here: http://www.parmaja.com/downloads/sqlite3/
 
And newer ones can be found here: http://www.parmaja.com/downloads/sqlite3/
  
==OpenSSL in Win CE==
+
===OpenSSL for Windows CE===
  
 
It is pretty hard to find a good binary OpenSSL library for Windows CE these days, so good versions which dont depend on any wierd, unusual library, are hosted here:
 
It is pretty hard to find a good binary OpenSSL library for Windows CE these days, so good versions which dont depend on any wierd, unusual library, are hosted here:
Line 482: Line 579:
 
https://sourceforge.net/projects/p-tools/files/OpenSSL%20for%20Windows%20CE/
 
https://sourceforge.net/projects/p-tools/files/OpenSSL%20for%20Windows%20CE/
  
==Links==
+
They were obtained from here: http://q3.snak.org/en/old.html and hosted on the link above in case this page goes offline
 +
 
 +
{{Other Interfaces}}
 +
 
 +
== See also ==
 +
 
 
Here are some links that might be useful for creating Windows CE interfaces.
 
Here are some links that might be useful for creating Windows CE interfaces.
  
[[Windows_CE_Development_Notes|Windows CE Development Notes]]
+
* [[Windows_CE_Development_Notes|Windows CE Development Notes]]
 
+
* [[KOL-CE|WinCE port of KOL GUI library]]
[[KOL-CE|WinCE port of KOL GUI library]]
 

Latest revision as of 02:11, 9 August 2020

WinCE Logo.png

This article applies to WinCE only.

See also: Multiplatform Programming Guide

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

TIPS / FAQ

The error message: SomeProject is not a valid Windows CE application

This is a generic error message from Windows CE which can be caused by one of the following reasons:

  • The executable was compiled for a different Operating System, for example desktop Windows
  • The executable was compiled for a different architecture then the device has
  • One of the DLLs which the device requires could not be found. Usually this is either a database dll or aygshell.dll. See further in this FAQ about those
  • The binary is too big and doesn't fit the available RAM

Unfortunately Windows CE does not give specific error messages in this case, so one should simply test all hypotheses.

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

Possible causes are:

Missing aygshell.dll

This error 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.

Here is a list of forum topics where people had trouble with aygshell.dll and found a solution:

And here a number of DLLs to substitute missing ones and make applications work:

Wrong architecture

Maybe your device runs a x86 or mips processor instead of the more common ARM.

Missing functions due to Operating System version

Possibly your operating system is very old and doesn't have some functions required by Lazarus.

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

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;

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

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;

Show/Hide SIP Panel

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

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;

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.

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

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.

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

Examples

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;

Vibrator it is the last LED in your device, if you can write some music you can now make your phone dance.

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;

Getting Battery Status

For more information : MSDN GetSystemPowerStatusEx

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

Prevent Phone from Entering in Standby Mode

Inside a timer event add the following line of code:

keybd_event(VK_F24, 0, KEYEVENTF_KEYUP or KEYEVENTF_SILENT, 0);


Installation of an app build with Lazarus on a WinCE device

The simplest way to install an app is to simply copy the executable and other files it needs, but a proper installer can be made with the instructions bellow: 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):

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

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...):

[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

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

Debugging with a log file

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

uses LCLProc;

DbgAppendToFile(ExtractFilePath(ParamStr(0)) + '1.log', 'Some text');

The unit LCLProc also contains other cool routines for debugging, like GetStackTrace, which returns a string with the stack trace.

Current Directory and Placement of DLLs

Windows CE does not have the concept of current directory, so paths to files should always be complete and never relative to the executable path.

As one exception to this rule, DLLs can be placed in the same folder as the executable and they will be loaded from there. Another suitable location for DLLs is the \Windows directory.

Going Full Screen

Making an application Fullscreen requires removing both the bottom menu bar and the top taskbar

Removing the top taskbar

This code should remove the taskbar by passing False to the parameter of this function:

Note that if you don't provide a quit button it will be then impossible to close the application and that if the application crashes, the taskbar will not be restored automatically. Rebooting the device will restore it.

uses Windows, aygshell;

procedure TForm1.RemoveTaskbar(AFullScreen: Boolean);
const
  MENU_HEIGHT = 26;
var
  rc: TRect;
begin
  if AFullScreen then
  begin
    GetWindowRect(Handle, @rc);

    SHFullScreen(Handle, SHFS_HIDETASKBAR);

    MoveWindow(Handle,
  	  rc.left,
  	  rc.top-MENU_HEIGHT,
  	  rc.right,
  	  rc.bottom+MENU_HEIGHT,
  	  TRUE);
  end
  else
  begin
    GetWindowRect(Handle, @rc);
    SHFullScreen(Handle, SHFS_SHOWTASKBAR);
    MoveWindow(Handle,
         rc.left,
         rc.top+MENU_HEIGHT,
         rc.right,
         rc.bottom-MENU_HEIGHT,
         TRUE);
  end;
end;

Removing the Virtual Keyboard

One can remove the keyboard with SHFS_HIDESIPBUTTON, like this:

uses Windows, aygshell;

procedure TForm1.RemoveVirtualKeyboard(ARemove: Boolean);
begin
  if ARemove then SHFullScreen(Handle, SHFS_HIDESIPBUTTON)
  else SHFullScreen(Handle, SHFS_SHOWSIPBUTTON);
end;

Alternative way with SHFullScreen

This is a different solution for going Fullscreen. 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:

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

Then in your Forms, OnCreate or OnShow (better on the OnShow) event add the following code:

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;

Rotating the Screen

There is a Microsoft tutorial with code in C here about this: http://msdn.microsoft.com/en-us/library/ms812499.aspx Bellow is code equivalent to that tutorial, but in Pascal.

Getting the Current Display Settings

To obtain the current display settings, pass the ENUM_CURRENT_SETTINGS constant in the iModeNum parameter to the EnumDisplaySettings API, as illustrated by the following Pascal code.

var
  dm: DEVMODE;
begin
  FillChar(dm, #0, SizeOf(dm));
  dm.dmSize := sizeof(dm);

  if 0 <> EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, @dm) then
  begin
      // inspect the DEVMODE structure to obtain details
      // about the display settings such as
      //  - Orientation
      //  - Width and Height
      //  - Frequency
      //  - etc.
   end;

Enumerating All Supported Display Settings

To enumerate all display settings supported by the current display device pass zero in the iModeNum parameter to the EnumDisplaySettings API and then continue calling it with incremented iModeNum values until the function returns zero, as shown in the following Pascal code.

var
  index: Integer = 0;
  dm: DEVMODE;
begin
  FillChar(dm, #0, SizeOf(dm));
  dm.dmSize := sizeof(dm);

  while 0 <> EnumDisplaySettings(NULL, index, @dm) do
  begin
      // inspect the DEVMODE structure to obtain details
      // about the display settings such as
      //  - Orientation
      //  - Width and Height
      //  - Frequency
      //  - etc.
    Inc(Index)
  end;

Changing Display Settings

To change the display settings pass in a pointer to a valid DEVMODE structure to the ChangeDisplaySettings API. The following Pascal code demonstrates how to rotate the screen orientation clockwise by 90 degrees. Note that this code will only work with devices that support the respective display settings. It is important to obey the return value of the ChangeDisplaySettings API as some operations may require the computer to be restarted in order for the graphics mode to work.

var
  dm: DEVMODE;
  dwTemp: Cardinal;
  lRet: Integer;
begin
  FillChar(dm, #0, SizeOf(dm));
  dm.dmSize := sizeof(dm);

   if (0 <> EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, @dm)) do
   begin
      // swap height and width
      dwTemp := dm.dmPelsHeight;
      dm.dmPelsHeight:= dm.dmPelsWidth;
      dm.dmPelsWidth := dwTemp;

      // determine new orientaion
      case (dm.dmDisplayOrientation) of
      DMDO_DEFAULT:    dm.dmDisplayOrientation := DMDO_270;
      DMDO_270:   dm.dmDisplayOrientation := DMDO_180;
      DMDO_180:   dm.dmDisplayOrientation := DMDO_90;
      DMDO_90:    dm.dmDisplayOrientation := DMDO_DEFAULT;
      else
         // unknown orientation value
         // add exception handling here
      end;
      lRet := ChangeDisplaySettings(@dm, 0);
      if (DISP_CHANGE_SUCCESSFUL <> lRet) then
      begin
         // add exception handling here
      end;
   end;

Pre-compiled Windows CE Libraries/Utils

Pre-compiled sqlite dll

You can find sqlite3.dll pre-compiled for Windows CE here.

And newer ones can be found here: http://www.parmaja.com/downloads/sqlite3/

OpenSSL for Windows CE

It is pretty hard to find a good binary OpenSSL library for Windows CE these days, so good versions which dont depend on any wierd, unusual library, are hosted here:

https://sourceforge.net/projects/p-tools/files/OpenSSL%20for%20Windows%20CE/

They were obtained from here: http://q3.snak.org/en/old.html and hosted on the link above in case this page goes offline

Other Interfaces

Platform specific Tips

Interface Development Articles

See also

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