Windows CE Development Notes

From Lazarus wiki
Jump to navigationJump to search
WinCE Logo.png

This article applies to WinCE only.

See also: Multiplatform Programming Guide

English (en) 中文(台灣)‎ (zh_TW)

Other Interfaces

Platform specific Tips

Interface Development Articles

Debugging your applications

General info is here Windows_CE_Interface#Debbuging Windows CE software on the Lazarus IDE

  • Sometimes GDB will crash, just reset debugger and start again.
  • If you have an open call stack window it will take lots of time each time you trace or debug your program and it sometimes crashes the debugger, so use it only when needed.
  • Always put breakpoints where needed; you can not-or hardly can- pause your program or even stop/reset it.
  • You can strip your program with --only-keep-debug which save you around 1 mg.There are some issues with strip utility, sometimes it makes your program not executable, So I generally don't recommend using it.
  • Sometimes stepping takes lots of time, just be patient ,I've experienced once a simple assignment took 1 min for debugger to execute that code.

Alignment problems

Using ARM processors, some times you may get a EBusError exception with a message about misaligned data access. The following section explains what this is and how to fix it.


What is misaligned data access?

Suppose a CPU has a 8bit data bus to memory and you want to read a byte. Since you have a 8bit bus, you are able to address all individual bytes, so reading is not a problem. Now imagine a CPU with a 32bit data bus and reading a byte. Data is read in chunks of 32bits (=4 bytes) and it is addressed by multiples of 4. For getting the exact byte, the CPU "shifts" the right byte.


Now we do the same for reading a 32bits integer. On an 8 bit CPU, you have to read 4 times one byte and then you have the integer. On a 32bits CPU it can be read in one go if the address is aligned to 4 bytes. If not, it has to be read in 2 halves and then combined to one integer. The x86 supports reading like this, although it is inefficient. The SPARC and some implementations of the ARM (*) don't support this and raise a bus error if you read data like this.


(*) there are extensions to the ARM core which can handle it, but this Depends on what functionality the manufacturer of a specific core has Implemented.


How to solve this?

Use typecasts of pointers very carefully. 16-bit and 32-bit values need to be 4-byte aligned in memory. Otherwise bus error will occur. Or use newly added "unaligned" keyword before using them. You can use unaligned keyword both in left or right side of your assignments.

Examples:

var
p1:^Longint;
l:longint;
begin
p1^:=20;  //might cause error if p points to an unaligned memory, i.e. not 4-byte aligned.
unaligned(p1^):=20;  //it is ok 
l:=pl^;  //this can also generate error
l:=unaligned(pl^);  //it is ok 
end.

When using Pack records, compiler automatically generates all access to the record members as unaligned access. Currently there are some small issues which sometimes with nested pack records compiler does not generate the required code. You just have to use unaligned keyword. But note that using packed records will influence speed a lot as all of its members are treated as unaligned. So use them only if needed.

Implementation details

ApplicationType

The Windows CE interface will try to automatically detect the kind of device which is being run if nothing is specifyed by the user. The possible devices are:

  • atDefault - The LCL will detect automatically the type
  • atPDA - A PDA or Smartphone with a touch screen and a small screen. Forms are usually maximized to ocupy the whole work area, and custom positioning and sizing is ignored. Windows CE in default resolution will always have a Width of 240 pixels, and the Height can change from device to device, but 320 pixels is a good guess. In some devices it is possible to specify a bigger size if the screen supports it.
  • atKeyPadDevice - Simple phones and some GPS devices and Bar-code scanners. Devices of this type had are very limited and have a small screen, lacking a touch screen or other pointing device. The very limited navigation capabilities mean that the application must be simplified at a maximum. Under WindowsCE for example only 2 top level menus are possible and all forms need to be maximized.
  • atDesktop - A full desktop application, for which the operating system just happens to be WinCE. Should work just like any desktop application.

Note that before Lazarus 0.9.29 atKeyPadDevice was named atSmartphone and there was an unsupported atHandheld.

How to specify a fixed device:

<delphi> program MyProgram;

...

begin

 Application.ApplicationType := atKeyPadDevice;
 // On Application.Initialize a default device would be detected if 
 // ApplicationType = atDefault, but now the detection is suppressed.
 Application.Initialize;
 ...

end. </delphi>

Positioning and size of Dialogs and Forms

At run-time the position and size of forms on the WinCE interface is different then designed. Specifically, it's dependent on the kind of device being run and on the border style.


ApplicationType BorderStyle Behavior WindowState Title bar Status
atDesktop Any Not yet defined. Currently it should work just like on win32, althougth maybe the Left/Top position should always be ignored, because a Handheld may have a small screen. It's also necessary to check if all border styles are supported (how could one resize a form on a handhelp?) As on desktops As on desktops Implemented
atPDA, atKeyPadDevice bsDialog Accepts custom sizing. The X, Y position is ignored and always set to be the top-left corner, but taking into account the existence of an eventual Taskbar on the top. Not applicable Separate title bar with a "OK" close button Implemented
atPDA, atKeyPadDevice bsNone Allows full control of the size and position to the user. Not applicable Doesn't exist Implemented
atPDA, atKeyPadDevice bsSizable, bsSingle, bsToolWin, bsSizeToolWin Rejects custom size and position and is always set to fill the entire work area excluding the menu. The definition of Work Area already excludes the Taskbar Not applicable Merged into the taskbar with a "OK" close button Implemented

Obs:

  • Initially atDefault was defined as atPDA, but since 0.9.27 (maybe earlier) in Application.Initialize the type will be checked automatically and the ApplicationType will be changed to the correct value.

Links with information

  • Code to position a form on the work area: [1]

The Title "OK" and "X" buttons

A very common problem found in previous LCL for WinCE versions was that under Windows CE, by default, there exists no close button available in the title bar. There is, however, a "X" minimize button, which minimizes the form. Because there is a "X" written on it, and because a very similar button in desktops closes the form, the majority of Lazarus for WinCE users expected that button to close the form. To attend this expectation we have changed the default behavior for our forms and now they will all have a "OK" close button instead of a "X" minimize button.

Predicting that some people will desire to have the X button, it was provided a switch to control the title buttons policy. There are some values possible:

Value Description
tpAlwaysUseOKButton The default one and all forms will have an "OK" close button.
tpOKButtonOnlyOnDialogs Can also be choosen and all forms will have "X" minimize buttons instead of forms with bsDialog borderstyle, which will still have an "OK" close button.
tpControlWithBorderIcons If biMinimize is included in the form's BorderIcons, then a "X" minimize button will be shown. A "OK" button is shown otherwise.

Be very careful using any option which allows the "X" button, because:

  • Clicking in the X in the main form of the application won't quit it. You are responsible for providing code so that when the user starts a new instance of your application it will detect the running instance, show the running instance and then quit, or else you will fill the users memory with instances of your application.

Example code to change the default policy bellow:

<delphi> {$ifdef LCLWinCE} uses

 WinCEInt;

{$endif}

...

begin {$ifdef LCLWinCE}

 WinCEWidgetset.WinCETitlePolicy := tpOKButtonOnlyOnDialogs;

{$endif} end; </delphi>

Screenshots

This is a title with "X" minimize button:

Title with x button.PNG

This is a title with "OK" close button:

Title with ok button.PNG

Implementation details

The "OK" button will send a WM_COMMAND message, which is handled on wincecallback.inc, with wID=IDOK. There we respond by throwing a WM_CLOSE to the form.

Bug Reports

TWinControl.PopupMenu showing

Showing the popup menu of a windowed control is implemented using the native behavior of the Windows CE platform for touch screens. The user holds the pointer in a given control for a certain amount of time and the popup shows. This is implemented on the WM_LBUTTONDOWN message handler by calling SHRecognizeGesture.

For more details see:

TRadioButton and TGroupBox

See Also: Win32/64_Interface#Background_color_of_Standard_Controls

Several different problems with TCustomCheckBox descendents (like TRadioButton) and TGroupBox were found on Lazarus 0.9.25 and are being fixed.

1 - The autosize of TCustomCheckBox descendents under Windows CE produces a too small area, both inside a TRadioGroup and a alone in a form. That indicates that there was a problem with TWSWinCECustomCheckBox.GetPreferedSize. Even with the code exactly equal to the win32 interface the width was still too small, so an extra 10 pixels factor was added arbitrarely to fix that until a better solution is found - Fixed

2 - Aditionally TCustomCheckBox descendents inside a TGroupBox (but not on a form) paint a white background instead of painting the correct background color. The way to handle background color changing on a series of controls is by handling the WM_CTLCOLORSTATIC message. Even with the code exactly the same as the Win32 one that still happens, and for unknown misterious reasons if the control is on a form instead of a GroupBox it works normally.

3 - A third problem found while investigating the other ones is that the difference between the windows client are and the client area that LCL expects was being ignored under Windows CE. This would be seen when one places a control on a TGroupBox or other controls with a border that the position of the places control was wrong - Fixed

TRadioGroup before fixes

Wince radiogroup before.png

(Obs: The captions should be "Item1", "Yet another Item", "Item2", "Item3")

TRadioGroup after fixes

Not yet fixed

Bug Tracker items

TCheckListBox

See also: Win32/64_Interface#TCheckListBox

TCheckListBox presented some color problems under Windows CE which needed to be fixed. Specifically it was found that on several places where system colors were used, the constant SYS_COLOR_INDEX_FLAG wasn't added. LCLIntf.GetSysColor makes sure the constant is added, so it should always be used instead of Windows.GetSysColor. On desktop Windows this constant equals to zero, so it can be ignored.

The drawing code itself is located at TCustomListBox.LMDrawListItem and TCustomListBox.DrawItem, but what needed fixing was LCLIntf.GetSysColor.

The colors of the TCheckListBox items under Windows CE are:

Description Code Value before fix Correct value Corrected?
background of the entire item GetSysColor(COLOR_WINDOW) black white Yes
background of unselected text default background color white white Yes
background of selected text SetBkColor(GetSysColor(COLOR_HIGHLIGHT)) black blue Yes
background of selected item GetSysColor(COLOR_HIGHLIGHT) black blue Yes
color of selected text SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT)) black white Yes
color of disabled text SetTextColor(GetSysColor(COLOR_GRAYTEXT)) black Gray Yes
color of normal text SetTextColor(GetSysColor(COLOR_WINDOWTEXT)) black black Yes

Acording to the MSDN docs a result of 0 for GetSysColor under Windows CE should identify that it isn't available. Now, 0 is also an RGB value (black), so maybe the WinCE docs are wrong and the Win32 docs should be used.

TChecklistbox before fixes

Wince checklistbox.png

TChecklistbox after fixes

Wince checklistbox after workaround.png

MSDN Docs

Bug tracker items

Tab Controls (TPageControl)

While most controls work just "as-is" from normal Win32 code, Tab Controls present a big amount of "gotchas" which make development of a tab control harder then in Win32.

A small list:

  • Vertical text is not supported, so tab buttons located on the left and right won't show text
  • For whatever reason (a bug in WinCE?) tab controls with tab buttons located on the top won't display text on the tab

Also, Microsoft recomends using tabs with bottom style under Windows CE, so that the user won't cover the touch screen with his hand when changing tabs. Combining all those together made me decide to hard-code page controls into always using bottom style under Windows CE, regardless of the control properties.

The default stype is a bit old. But I found the new style too minimalistic. You can barely see it's a tab control at all. The call to set new style (flat stype) is on the code (TWinCEWSCustomNotebook.CreateHandle), just commented, so it will be easy to change in the future

Some docs are located here:

http://msdn2.microsoft.com/en-us/library/aa921319.aspx

Background and sheet position problems

The background of each page seams not to be painted by default, and because the border around the control is very thin and incomplete (not all edges have borders), you can barely see what is the client area of the sheet

I used a magick change on the sheet position given by WinCE as described here:

http://www.pocketpcdn.com/forum/viewtopic.php?t=499

Here is a TPageControl before the sheet position adjust:

Before tab adjust.png

And after:

After tab adjust.png

Note that you can only clearly see the client area on the bottom page control because I put a TPanel aligned to alClient inside it.

I couldn't decide if fixing a background color was a good idea, or which color would I use for it, so I'm leaving this problem be for now.

Bug tracker items

DataAware controls

For some unknown reason, data-aware controls crash the application.

Bug tracker items


Brushes

CreateBrushIndirect doesn't exist under Windows CE, so the interface maps it to CreateSolidBrush, CreateDIBPatternBrushPt and GetStockObject.

If special flags are used they are ignored and CreateSolidBrush is used instead.

From CreateBrushIndirect on wincewinapi.inc: <delphi>

 if lb.lbStyle= BS_NULL then
   Result := Windows.GetStockObject(NULL_BRUSH)
 else if lb.lbStyle = BS_DIBPATTERNPT then
   Result := CreateDIBPatternBrushPt(pointer(lb.lbHatch), lb.lbColor)
 else { lb.lbStyle = BS_SOLID }
   Result := Windows.CreateSolidBrush(LB.lbColor);

</delphi>

SetProp - GetProp - RemoveProp APIs

Windows CE does not have SetProp and GetProp API's which is used a lot. So I (User:Roozbeh) have created/emulated them. The current implementation is not exactly as win32 API. In win32 you can set multiple properties with different names to each window but here I ignore names so we can only have one kind of property assigned to each control. (It is easy to implement that, but I find it currently of no use). Also removeprop is not called yet! So a memory leak happens each time you exist the program. (I don't know if wince also frees memory itself or not when window handles are destroyed).Should be implemented soon.

Modal Dialogs and the OK and X buttons

Under Windows CE some dialogs will present both the OK and the X button. It is possible to distinguish between them according to the ModalResult that they send. The OK close button will send mrOK, while the X minimize button will close the dialog and send a mrCancel result.

Here is the dialog produced by the following code under Windows CE:

  MessageDlg('Shall I test a very, really, long string?', mtConfirmation, [mbYes, mbNo, mbOk, mbCancel],0);


Messagedlg wince.PNG

Bug reports:

Overlapping menu bottom

There is a flaw in Windows CE. The routine Windows.SystemParametersInfo(SPI_GETWORKAREA, 0, @WR, 0); doesn't return what we expect in some systems, and returns it on other ones. The problem is that on some systems the menu bar is considered part of the work area, and in others it isn't. So, when a menu is present we need to check if our program is overlapping the menubar, and if it is, we should make our window smaller.

Some software solve this by applying a factor of 26 to the window height, but this approach isn't that good because there is no way to determina if the device is of the kind that needs the factor.

The solution was implemented in CESetMenu, so the window will only have it's final size after the menu is set. This makes it unclear at the moment if the size of the window would be wrong in some events of the form.

Here is a screenshot of an application which is overlapping the menu:

Wince overlapping menu.png

Microsoft Newsgroup Links:

Routine to maximize a window in Windows CE. Not very good, because it just uses a lot of ifdefs:

http://groups.google.com/group/microsoft.public.pocketpc.developer/browse_thread/thread/f4bba1733d3f6cfa/342497d1797af97a?lnk=gst&q=unreliable#342497d1797af97a

Workarea problem description:

http://groups.google.com/group/microsoft.public.windowsce.embedded.vc/browse_thread/thread/2f4ecdade7fe48aa?q=menu+SystemParametersInfo+group:microsoft.public.windowsce.*#44941f01c43edbd7

Fixed in version: 0.9.27

Standard dialogs

The native dialogs in Windows CE are too simplistic and limit the user to a small number of directories. Better dialogs will be built instead. There are some missing controls in the LCL, so those will need to be created first.

Steps to implement the standard dialogs:

  1. Implement TShellTreeView
  2. Implement TShellListView
  3. Implement TFilterComboBox
  4. Implement TOpenDialog and TSaveDialog
  5. Implement other dialogs
  6. Fix any bugs that appear

The implementation should be very similar to this:

http://www.codeproject.com/KB/mobile/cefileopendlg.aspx

In the save dialog I would remove the TFileListBox to make room for a TEdit.

A special care will need to be made to make sure that the dialog fits any resolution.

Images

State of the open and save dialogs in Lazarus 0.9.28

Wince opendialog 0 9 28.PNGWince savedialog 0 9 28.PNG

Bug tracker items

Running in desktop Windows

Yes, the Windows CE interface also works for desktop Windows. I (Felipe Carvalho) implemented this feature to speed up debugging, as the desktop windows debugger is much quicker, and also the desktop compiler is much quicker. There are still bugs to be solved for this interface, but it has served well its purpose until now.

Smartphone menus

A particularly hard to implement feature are smartphone menus, which are very limited and often hard to work with. Their most visible limitation is the number of top-level menu items being at most 2, so that they can be easily accessed in devices without touchscreen.

Another important thing to notice is that PocketPC and Windows Mobile top-level menus are implemented with a TOOLBAR windows class, not with MENU class. The MENU class is destined for popup menus, those which are activated by clicking in the top-level menu, or in a popup menu.

Also, the top-level menu can only be set to a resource menu, it cannot be completely programatically created, but it can be alreared later, which offers an equivalent solution. The menu is set to a resource menu with SHCreateMenuBar.

Differences between smartphone and pocketpc menus:

Some usual things don't work with smartphone menus, for example if a menu item has been set as not having a submenu, then it cannot be changed to have one, that's why we need many menu solutions in

Flow of information of menu items:

First the handle of the menus are created with TWinCEWSMenuItem.CreateHandle and TWinCEWSMenu.CreateHandle, which just creates an empty menu item/menu. The real building of the item is processed in TWinCEWSMenuItem.AttachMenuEx, which connects a menu item with it's corresponding parent menu, or parent menu item. This routine will save all menu items attached (which is the effective creation) in WinCEWSMenus.MenuItemsList: TStringList, so that they can be later found when clicked.

With the menus built and attached, the routine LCLIntf.SetMenu is called to attach a menu to a window. In Windows CE only one menu is visible at a time (except for atHandheld and atDesktop application modes), so this will be the only menu visible in the device. This routine will then procede to set this single device menu to the best fit for the application menu setting all the top-level menus and their properties, such as supporting a submenu. With this in place, the already created handle of the menus is attached to the single device menu by calling TWinCEWSMenuItem.AttachMenuEx for each subitem of the top-level menu. Further items are already attached to those handles, so only a double loop is necessary, to cover all subitems of the all top-level menu items.

Upon clicking a menu, the list in WinCEWSMenus.MenuItemsList: TStringList is read and the menu is searched for, this works for all not-top-level menus.

Revisions related to this implementation:

http://svn.freepascal.org/cgi-bin/viewvc.cgi?view=rev&root=lazarus&revision=22236, 22238, 22239

Bug tracker items:

Regressions

From time to time there can be regressions and specially in 0.9.29 a good amount of regressions were introduced in the Windows CE Widgetset. This documents the effort to find and fix those regressions.

Table about the behavior of a single issue in time:

Revision Version Group Box issues Label issues PageControl issues
23000 - correct position The label inside a group box doesn't even show. Other labels show correct position. Border broken
23136 - correct position The label inside a group box doesn't even show. Other labels show correct position. Border broken
23137 - correct position The label inside a group box / pagecontrol doesn't even show. Other labels show in (0,0). Full border drawn
23500 - correct position The label inside a group box / pagecontrol doesn't even show. Other labels show in (0,0). Full border drawn
23750 - correct position The label inside a group box / pagecontrol doesn't even show. Other labels show in (0,0). Full border drawn
23900 - correct position The label inside a pagecontrol doesn't even show. Other labels show in (0,0). Full border drawn
24000 - correct position All labels have zero X,Y position Full border drawn
24176 - correct position All labels have zero X,Y position Full border drawn
24177 - painted wrongly the label inside a group box has too small x-position Border broken
24500 - painted wrongly the label inside a group box has too small x-position Border broken
25000 0.9.29 painted wrongly the label inside a group box doesn't even show Border broken
25180 0.9.29 5 may 2010 painted wrongly the label inside a group box has too small x-position Border broken

Table of what was broken and fixed in each revision:

Revision Version Description
23137 - Broke label in form positioning to (0, 0), fixed pagecontrol frame
23794 - Fixes label showing in Group Box
24177 - Broke Group Box title, Group Box painting, label inside control X position, pagecontrol frame
25203, 25202, 25201, 25194, 25185 - Broke Group Box title, Child-Component y positioning, label inside control X position, pagecontrol frame
25214 - Fixes Group Box title, Group Box painting, label painting and pagecontrol frame. Removes support to clipping to achieve that.

The problems in rev23137 were caused by the introduction of LCLIntf.SetViewPortOrgEx which made this routine no longer be implemented, as now it was calling LCLIntf version of SetViewPortOrgEx (not implemented under WinCE) instead of the WinAPI:

<delphi> function TWinCEWidgetSet.SetWindowOrgEx(DC: HDC; NewX, NewY: Integer;

 OldPoint: PPoint): Boolean;

begin

{ roozbeh:does this always work?it is heavily used in labels and some other drawing controls}
 Result := Boolean(SetViewPortOrgEx(DC, -NewX, -NewY, LPPoint(OldPoint)));

// Result:=inherited SetWindowOrgEx(dc, NewX, NewY, OldPoint); end; </delphi>

rev24177 fixed that, but it didn't fix the problem completely.

Bug tracker items:

Networking crash bug

Something in FPC introduced between 2.2.0 and 2.2.2 is causing a crash in WinCE applications.

FPC 2.2.0 was tagged in revision 8339 FPC 2.2.2 was tagged in revision 11490

The involved FPC Branch is: http://svn.freepascal.org/cgi-bin/viewvc.cgi/branches/fixes_2_2/

List of merged revisions into FPC 2.2.2:

8404 - Only linux


Bug tracker items:

List of devices with information about them

There are differences between devices, so it would be interresting to have a list with information about each of them. Please contribute.


Device Name WinCE Version ApplicationType (Auto-detection works?) Touchscreen? Width* Height* Menu Size** Observations
WM 5.0 Emulator - PocketPC 5.0 atPDA (yes) Yes 240 268 26
WM 5.0 Emulator - Smartphone 5.0 atKeyPadDevice (yes) No 176 180 0
WM 5.0 Emulator - Smartphone QVGA 5.0 atKeyPadDevice (yes) No 240 266 0
WM 2003 SE Emulator - Pocket PC 4.20 atPDA (?) Yes 240 294 0
WM 2003 SE Emulator - Pocket PC Square 4.20 atPDA (?) ? Yes 240 214 0
  • * - Values available for a maximized program will all extras activated (start menu, menu correction, PID, etc).
  • ** - The size of the correction which needs to be applyed when a menu is present. The LCL should calculate this automatically.

Abreviations:

  • WM = Windows Mobile
  • SE = Second Edition

Links

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

How to Port Your Win32 Code to Windows CE

Old but useful article show flags required for creating wince controls

Page with nice descriptions of lots of flags

Adapting Application Menus to the CE User Interface

Differences between normal Win32-API and Windows CE (old wince)

Resource-Definition Statements

GUI Control Styles

Developing Orientation and dpi Aware Applications

Developing Screen Orientation-Aware Applications

Introduction to User Interface Controls in a Windows Mobile-based Smartphone

WinCE port of KOL GUI library

Step by Step: Writing Device-Independent Windows Mobile Applications with the .NET Compact Framework