Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Inside the WinCE GUI


November 2001/Inside the WinCE GUI


Microsoft Windows CE is a compact, scalable operating system designed to run on a variety of devices. Windows CE programming is based on the Win32 API, but there are some tricks to targeting smaller devices. I’m going to discuss Windows CE 3.0 GUI changes using sample code for the Pocket PC platform. Four of the most important GUI characteristics on the Pocket PC are:

  1. The task bar is at the top of the Pocket PC screen.
  2. The menu is located at the bottom of the Pocket PC screen. The resource uses raw data.
  3. All dialog boxes on the Pocket PC must be full screen.
  4. Property sheet tabs are at the bottom of the screen.

I’ll review these along with several other distinctive aspects of Windows CE programming. To get started, download Microsoft’s eMbedded Visual Tools 3.0, available free online or for a small fee on CD. I used eMbedded Visual C++ 3.0, which requires Windows NT or 2000. The CD includes Windows Platform SDK for HPC, Palm PC, and Pocket PC.

The Combo Menu

The menu bar combines menu items and toolbar commands. The menu bar appears at the bottom of the device screen (see Figure 1) so that the user’s hand does not obstruct information content as he or she uses commands to manipulate it. Place menu items appearing on the menu bar on the leftmost portion of the bar.

This resource-definition statement specifies a raw data resource for an application: nameID RCDATA [[optional-statements]] { raw-data . . . }. Raw data resources permit the inclusion of binary data directly in the executable file. For example, the following resource example will create a menu with two menu items.

IDM_MAIN_MENU RCDATA DISCARDABLE
BEGIN
  // nameID, an integer number of menu items
  IDM_MAIN_MENU,
  I_IMAGENONE, IDM_MAIN_MENUITEM2,
  TBSTATE_ENABLED,TBSTYLE_DROPDOWN
  |TBSTYLE_AUTOSIZE,
  IDS_MAIN_MENUITEM2, 0,0,
  I_IMAGENONE, IDM_MAIN_MENUITEM3,
  TBSTATE_ENABLED,TBSTYLE_DROPDOWN
  |TBSTYLE_AUTOSIZE,
  IDS_MAIN_MENUITEM3, 0,1,
END
IDM_MAIN_MENU MENU DISCARDABLE
BEGIN
   POPUP "Colors"
   BEGIN
      MENUITEM "Blue",  IDM_BLUE
      MENUITEM "Red",   IDM_RED
      MENUITEM "Green", IDM_GREEN
   END
END
STRINGTABLE DISCARDABLE
BEGIN
   IDS_MAIN_MENUITEM2   "Colors"
   IDS_MAIN_MENUITEM3   "Weapon"
END

To create a menu bar, add the following code:

  SHMENUBARINFO mbi;
  memset (&mbi, 0,
          sizeof(SHMENUBARINFO));
  mbi.cbSize =
           sizeof(SHMENUBARINFO);
  mbi.hwndParent = hwnd;
  mbi.nToolBarId = IDM_MAIN_MENU;
  mbi.hInstRes   = hInst;
  mbi.nBmpId     = 0;
  mbi.cBmpImages = 0;
  SHCreateMenuBar (&mbi );

To save the window handle of the menu bar:

hwndCB = mbi.hwndMB;

Full Screen Dialogs

To display information and input fields in a clearer manner, the Pocket PC has adopted full-screen child windows, or dialog boxes, as a standard. The SHInitDialog function is primarily used to create a full-screen dialog box with an OK button in the navigation bar. Here is an example showing how to use SHInitDialog to create a full screen dialog.

case WM_INITDIALOG: {
SHINITDLGINFO shidi;
//Create Done button and size it.
shidi.dwMask = SHIDIM_FLAGS;
shidi.dwFlags =
SHIDIF_DONEBUTTON|SHIDIF_SIPDOWN|
           IDIF_SIZEDLGFULLSCREEN;
shidi.hDlg = hDlg;
//initializes the dialog based
//on the dwFlags parameter
SHInitDialog (&shidi);
}
break;

Property Sheets and Property Pages

A property sheet has three main parts: the containing dialog box, one or more property pages shown one at a time, and a tab at the bottom of each page that the user clicks to select that page. (see Figure 2) A property sheet is a dialog box that contains property pages. Each page contains controls, is based on a dialog template resource, and appears on a tab, an enclosure that looks like a file folder with a tab at the bottom. The tab names the page and indicates its purpose. Dialog box controls can be divided into logical groups putting each group on its own property page. Users click a tab in the property sheet to select a set of controls.

Pocket PC property sheets should be supported with tabs for navigating between groups of properties. Property sheets typically allow the user to change the values for a property and then apply those transactions. A Pocket PC property sheet with such functionality usually requires an OK button to make such changes, but should not have an OK button if OK/Cancel controls are present in the client area.

Messages are sent to a tab control to add tabs and to affect the appearance and behavior of the control. Each message has a corresponding macro, which can be used instead of sending the message explicitly. Although individual tabs cannot be disabled in a tab control, a tab control can be disabled in a property sheet by disabling the corresponding page. Property sheets have a capability that standard dialog boxes do not: they allow the user to apply changes they have made before closing the property sheet. The PocketPropSheet sample code is available online.

Control Panel Applets

Users can alter the devices settings using Control Panel applets. Applets can be created that let users examine and modify the settings and operational modes of specific hardware and software. Control Panel applets are just DLLs with special entry points and with .cpl extensions. A Control Panel applet is stored in the windows system directory (See Figure 3). When the control panel is started, the applet will be there. A Control Panel extension is a DLL with a special function called CPlApplet(). It’s a relatively simple function taking a window handle, a message, and a couple of message specific parameters. CplApplet has the following signature: LRESULT CplApplet (HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lParam2).

When the Windows Control Panel (CONTROL.EXE) starts up, it looks for XXX.cpl in the Windows System directory. It loads each DLL and calls its CplApplet function with various messages. The Control Panel application communicates only with files with the “.cpl” extension.

For example, when the Control Panel first starts up, it calls the CplApplet function with msg=CPL_INIT. When the user double-clicks the applet’s icon, it calls CplApplet with msg=CPL_DBLCLK, and the applet displays its dialog. Each Control Panel DLL can support more than one icon or applet. Tell the Control Panel how many applets there are by responding to CPL_GETCOUNT, and the Control Panel requests information about each one by sending CPL_INQUIRE or CPL_NEWINQUIRE. Example 1 is the code sample for the Control Panel callback function. This function must be named CplApplet. It is an export function.

To support more than one applet, create a ListView with an ICON view. Make each icon as one of the applets. After setting up the ICON ListView, each icon will bring up an applet. To display the applet on the first page of the Control Panel, do the following: CPL_IDNAME will need to be handled. The string returned will be the name used to find the applets information in the registry. Set the registry group to the tab where the applet should go.

For example, when handling CPL_IDNAME, return SampleApplet. In the registry, create the key HKLM\Control Panel\SampleApplet and create the Group value under that key. The applet referred to by SampleApplet will be shown on the tab specified in the Group value. The sample code for CplApplet is available online.

//===========================================================
BOOL WINAPI DllMain (
           HINSTANCE hinstDLL,  // handle to DLL module
           DWORD fdwReason,     // reason for calling function
           LPVOID lpReserved )  // reserved
{
    // Perform actions based on the reason for calling.
    switch( fdwReason )
    {
        case DLL_PROCESS_ATTACH:
        //Initialize once for each new process. Return FALSE to
        //fail DLL load.
        break;
        case DLL_THREAD_ATTACH:
             // Do thread-specific initialization.
        break;
        case DLL_THREAD_DETACH:
            // Do thread-specific cleanup.
        break;
        case DLL_PROCESS_DETACH:
            // Perform any necessary cleanup.
        break;
    }
    return TRUE;  // Successful DLL_PROCESS_ATTACH.
}

Running Apps That Won’t Quit

The first thing needed is to create a parent window with null style, use this window to hide the running program from the OS list.

HWND hwndParent = CreateWindow(
                   TEXT("static"), g_szTitle, 0,
                   CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
                   CW_USEDEFAULT, NULL, NULL, hInstance, NULL);

g_hWnd = CreateWindow (
            YOURWINCLASS, g_szTitle, WS_POPUP|WS_VISIBLE,
            CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
            CW_USEDEFAULT, hwndParent, NULL, hInstance, NULL);

Custom Drawn Controls on Pocket PC

To create custom-drawn controls, create an owner drawn button in the response, as in Example 2. In this case, a WM_DRAWITEM message will be received. Process the following function to do the owner drawing for the custom buttons (see Figure 4).

To make the dialog divider have a 3-D look, create a static box with a control ID and use the following function:

// This will resize the divider line to look like a small 3D like line.
// This function takes the dialog handle and the handle of the control
// you want to resize.
BOOL ResizeLine (HWND hWndDlg, HWND hWndLine)
{
    RECT rctLine;
    POINT p;

    VERIFY( hWndLine );

    If (hWndLine == NULL)
        return FALSE;

    // Get original rect for line
    GetWindowRect(hWndLine, &rctLine);

    // Center
    // rctLine.top = ((rctLine.bottom - rctLine.top)/2)
    //                                      +rctLine.top-4;
    p.x = rctLine.left;
    p.y = rctLine.top;
    ScreenToClient (hWndDlg, &p);

    // Set new rect
    MoveWindow (hWndLine, p.x, p.y,
                rctLine.right-rctLine.left, 2, TRUE);
    return TRUE;
}

Using Pocket Outlook Object Module

The Pocket Outlook Object Module (POOM) is a smaller subset of the Outlook Object Module (Outlook). There are subtle differences between POOM and Outlook. POOM does not have the NameSpace object that Outlook has to log on to a MAPI session. The main interface to POOM is the Pocket Outlook Application object. This is the only object that can be created by calling CoCreateInstance, and it is from this object that all other objects are derived.

// To Use Pocket Outlook make sure pimstore.dll is
// on the device, and create the instance for IID_IPOutlookApp
#define  POA_OBJECT   TEXT("PocketOutlook.Application")

BOOL ConnectToPocketOutLook (void)
{
   CLSID       clsid;
   HRESULT     hr;
   HRFUNC      pProc;

   // Start by initializing COM
   CoInitializeEx (NULL, 0);

   // Get the CLSID for the application
   hr = CLSIDFromProgID (POA_OBJECT, &clsid);

   if (FAILED(hr))
   {
      g_hPimstore = LoadLibrary
                        (TEXT("\\windows\\pimstore.dll"));
      if (!g_hPimstore)
      {
         // You gotta have pimstore.dll, dude
         return FALSE;
      }

      pProc =(HRFUNC)GetProcAddress (g_hPimstore,
                                    TEXT("DllRegisterServer"));
      if (!pProc)
      {
         return FALSE;
      }

      hr = CLSIDFromProgID(POA_OBJECT, &clsid);
      if (FAILED(hr))
      {
         return FALSE;
      }
   }

   // Now, let's get the main application
   hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER,
                         IID_IPOutlookApp, (PPVOID) &g_polApp);
   if (FAILED(hr))
   {
      return FALSE;
   }
   return TRUE;
}

Extending Pocket Outlook Menus

The Calendar, Tasks, and Contacts applications support menu add-ins for external applications. Providing an add-in for one of these applications allows the menu item to appear on the Tools menu. When the user selects the menu item, Pocket Outlook calls a function in a registered DLL, which passes the object identifiers of the currently selected items in the application. To register your application, create a registry key under the following key:

#define  YOURAPP_REG_KEY \
  TEXT ("Software\Microsoft\PimApps\PimExtensions\pim_app\AddIns")

Any name can be used for the key. To avoid conflicts with other add-ins, I suggest that the key contain the name of your company. Replace pim_app with Contacts, Tasks, or Calendar, depending on which application’s menu you want the add-in to appear.

After creating this key, create two values for the key. The first value is DLL, which is set to the name of the DLL. The second value is Menu, which is set to the name to be displayed on the Tools menu. Others may add tool items, so try to create a unique, descriptive name that will distinguish your application.

For example, the following registry key would register a phone-dialer application in the Contacts application:

Software\Microsoft\PimApps\PimExtensions\Contacts\AddIns\MyDialer
DLL: MyDialer.dll
Menu: "Dial Contact"

Pocket Outlook calls the CePimCommand function to create a menu add-in in the Tools menu in the Contacts, Calendar, or Tasks applications. The DLL that supports the menu add-in must define and expose this function, which is called automatically when the user chooses the menu item. (See Listing 1)

Multiple Threads

Windows CE 3.0 offers improved windows compatibility, better threading response, additional task priorities, and semaphores, allowing the OS to respond immediately to events and interrupts. These make Windows CE 3.0 suited for industrial applications. Improvement in thread response allows developers to know specifically when the thread transitions occur. Windows CE includes some features that increase the capabilities of monitoring and controlling hardware:

  • Shorter Interrup Service Routine (ISR)
  • Support for nested interrupts.
  • Increased priority levels.
  • Support for semaphores.
  • Kernel-level security.

To create a thread, call the CreateThread function. The following code example shows the CreateThread function prototype.

HANDLE CreateThread (
    // not supported in CE set to NULL
    LPSECURITY_ATTRIBUTES lpThreadAttributes,
    // not supported in CE set to 0
    DWORD    dwStackSize,  
    // Pointer to the start of the thread routine
    LPTHREAD_START_ROUTINE lpStartAddres,
    // Specifies an application-defined value that
    // is passed to the thread
    LPVOID  lpParameter,
    // set to 0 or CREATE_SUSPENDED
    DWORD dwCreationFlags,
    // receives the new thread's identifier
    LPDWORD lpThreadId);

Windows CE does not support the lpThreadAttributes and dwStackSize parameters, so set them to NULL or 0.

If CreateThread is successful, it returns the handle to the new thread and the thread identifier. A thread can be terminated by calling ExitThread, which frees the resources that are used by a thread when they are no longer needed.

The code in Listing 2 will create a progress monitoring dialog running on its own thread.

About the Author

Meiyu E. Lin is a Senior Software Engineer of Bsquare Corp. Specializing in Win32, Windows CE and Web development technologies. She can be reached at [email protected].


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.