Windows Mobile-based Pocket PC Programming


A Pocket PC application is still a Windows application, so it has a message loop, a main window, and window procedures. The following figure shows two screen shots of a simple Pocket PC application called HelloPPC. The left image shows the window with the soft input panel, or SIP hidden; the image on the right shows HelloPPC with the SIP showing. Notice how the text centers itself in the visible portion of the workspace. The HelloPPC window has a red outline to highlight its size and position.


Below shows the source code for HelloPPC. The HelloPPC application creates a main window and prints Hello Pocket PC in the center of the window. It also draws a red rectangle around the border of its window to clearly show the extent of the window. The program creates a menu bar without a menu but with a button to display the SIP. If you tap the SIP button, you will see the main window resize to avoid being covered by the SIP.

 HelloPPC.rc 

//======================================================================
// Resource file
//
// Written for the book Programming Windows CE
// Copyright (C) 2003 Douglas Boling
//======================================================================
#include "windows.h"                 // Windows stuff
#include "commctrl.h"                // Common ctl stuff
#include "aygshell.h"                // Pocket PC stuff
#include "HelloPPC.h"                // Program-specific stuff

//----------------------------------------------------------------------
// Icons and bitmaps
//
ID_ICON      ICON   "HelloPPC.ico"   // Program icon

//----------------------------------------------------------------------
// Accelerator keys
//
ID_ACCEL ACCELERATORS DISCARDABLE 
BEGIN
  "Q",  IDM_EXIT,  VIRTKEY, CONTROL, NOINVERT
END
       

 HelloPPC.h 

//======================================================================
// Header file
//
// Written for the book Programming Windows CE
// Copyright (C) 2003 Douglas Boling
//
//================================================================
// Returns number of elements
#define dim(x) (sizeof(x) / sizeof(x[0])) 

//----------------------------------------------------------------------
// Generic defines and data types
//
struct decodeUINT {                          // Structure associates
  UINT Code;                                 // messages 
                                             // with a function. 
  LRESULT (*Fxn)(HWND, UINT, WPARAM, LPARAM);
}; 

struct decodeCMD {                           // Structure associates
  UINT Code;                                 // menu IDs with a 
  LRESULT (*Fxn)(HWND, WORD, HWND, WORD);    // function.
};

//----------------------------------------------------------------------
// Generic defines used by application
#define  ID_ACCEL          1                   // Accelerator table ID

#define  IDM_EXIT          100

//----------------------------------------------------------------------
// Function prototypes
//
HWND InitInstance (HINSTANCE, LPWSTR, int);
int TermInstance (HINSTANCE, int);

// Window procedures
LRESULT CALLBACK MainWndProc (HWND, UINT, WPARAM, LPARAM);

// Message handlers
LRESULT DoCreateMain (HWND, UINT, WPARAM, LPARAM);
LRESULT DoPaintMain (HWND, UINT, WPARAM, LPARAM);
LRESULT DoCommandMain (HWND, UINT, WPARAM, LPARAM);
LRESULT DoSettingChangeMain (HWND, UINT, WPARAM, LPARAM);
LRESULT DoActivateMain (HWND, UINT, WPARAM, LPARAM);
LRESULT DoHibernateMain (HWND, UINT, WPARAM, LPARAM);
LRESULT DoDestroyMain (HWND, UINT, WPARAM, LPARAM);

// WM_COMMAND message handlers
LPARAM DoMainCommandExit (HWND, WORD, HWND, WORD);
       

 HelloPPC.c 

//======================================================================
// HelloPPC - A simple application for the Pocket PC
//
// Written for the book Programming Windows CE
// Copyright (C) 2003 Douglas Boling
//
//======================================================================
#include <windows.h>                 // For all that Windows stuff
#include <commctrl.h>                // Command bar includes
#include <aygshell.h>                // Pocket PC includes
#include "helloppc.h"                // Program-specific stuff

//----------------------------------------------------------------------
// Global data
//
const TCHAR szAppName[] = TEXT ("HelloPPC");
HINSTANCE hInst;                      // Program instance handle

// Pocket PC globals
HWND hwndMenuBar = NULL;              // Handle of menu bar control
BOOL fHibernated = FALSE;             // Indicates hibernated state
SHACTIVATEINFO sai;                   // Used to adjust window for SIP

// Message dispatch table for MainWindowProc
const struct decodeUINT MainMessages[] = {
  WM_CREATE, DoCreateMain,
  WM_PAINT, DoPaintMain,
  WM_COMMAND, DoCommandMain,
  WM_SETTINGCHANGE, DoSettingChangeMain,
  WM_ACTIVATE, DoActivateMain,
  WM_HIBERNATE, DoHibernateMain,
  WM_DESTROY, DoDestroyMain,
};

// Command Message dispatch for MainWindowProc
const struct decodeCMD MainCommandItems[] = {
  IDM_EXIT, DoMainCommandExit,
};

//======================================================================
// Program entry point
//
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPWSTR lpCmdLine, int nCmdShow) {
  MSG msg;
  int rc = 0;
  HWND hwndMain;
  HACCEL hAccel;

  // Initialize this instance.
  hwndMain = InitInstance (hInstance, lpCmdLine, nCmdShow);
  if (hwndMain == 0) return 0x10;

  hAccel = LoadAccelerators(hInstance, MAKEINTRESOURCE (ID_ACCEL));

  // Application message loop
  while (GetMessage (&msg, NULL, 0, 0)) {
    // Translate accelerator keys.
    if (!TranslateAccelerator(hwndMain, hAccel, &msg)) {
      TranslateMessage (&msg);
      DispatchMessage (&msg);
    }
  }
  // Instance cleanup
  return TermInstance (hInstance, msg.wParam);
}

//------------------------------------------------------------------
// InitInstance - Instance initialization
//
HWND InitInstance (HINSTANCE hInstance, LPWSTR lpCmdLine, int nCmdShow) {
  WNDCLASS wc;
  HWND hWnd;

  // Save program instance handle in global variable.
  hInst = hInstance;

  // Allow only one instance of the application.
  hWnd = FindWindow (szAppName, NULL);
  if (hWnd) {
    SetForegroundWindow ((HWND)(((DWORD)hWnd) | 0x01));    
    return 0;
  }

  // Register application main window class.
  wc.style = CS_VREDRAW | CS_HREDRAW;       // Window style
  wc.lpfnWndProc = MainWndProc;             // Callback function
  wc.cbClsExtra = 0;                        // Extra class data
  wc.cbWndExtra = 0;                        // Extra window data
  wc.hInstance = hInstance;                 // Owner handle
  wc.hIcon = NULL,                          // Application icon
  wc.hCursor = LoadCursor (NULL, IDC_ARROW); // Default cursor
  wc.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
  wc.lpszMenuName =  NULL;                  // Menu name
  wc.lpszClassName = szAppName;             // Window class name

  if (RegisterClass (&wc) == 0) return 0;

  // Create main window.
  hWnd = CreateWindow (szAppName,           // Window class
                       TEXT ("Hello"),      // Window title
                       WS_VISIBLE,          // Style flags
                       CW_USEDEFAULT,       // x position
                       CW_USEDEFAULT,       // y position
                       CW_USEDEFAULT,       // Initial width
                       CW_USEDEFAULT,       // Initial height
                       NULL,                // Parent
                       NULL,                // Menu, must be null
                       hInstance,           // Application instance
                       NULL);               // Pointer to create
                                            // parameters
  if (!IsWindow (hWnd)) return 0;           // Fail if not created.

  // Standard show and update calls
  ShowWindow (hWnd, nCmdShow);
  UpdateWindow (hWnd);
  return hWnd;
}

//----------------------------------------------------------------------
// TermInstance - Program cleanup
//
int TermInstance (HINSTANCE hInstance, int nDefRC) {
  return nDefRC;
}

//======================================================================
// Message handling procedures for main window
//
//----------------------------------------------------------------------
// MainWndProc - Callback function for application window
//
LRESULT CALLBACK MainWndProc (HWND hWnd, UINT wMsg, WPARAM wParam, 
    LPARAM lParam) {
  INT i;
  //
  // Search message list to see if we need to handle this
  // message.  If in list, call procedure.
  //
  for (i = 0; i < dim(MainMessages); i++) {
    if (wMsg == MainMessages[i].Code)
      return (*MainMessages[i].Fxn)(hWnd, wMsg, wParam, lParam);
  }
  return DefWindowProc (hWnd, wMsg, wParam, lParam);
}

//----------------------------------------------------------------------
// DoCreateMain - Process WM_CREATE message for window.
//
LRESULT DoCreateMain (HWND hWnd, UINT wMsg, WPARAM wParam, 
    LPARAM lParam) {
  SHMENUBARINFO mbi;
  SIPINFO si;
  int cx, cy;

  // Initialize the shell to activate info structure.
  memset (&sai, 0, sizeof (sai));
  sai.cbSize = sizeof (sai);

  // Create a menu bar.
  memset(&mbi, 0, sizeof(SHMENUBARINFO)); // Zero structure
  mbi.cbSize = sizeof(SHMENUBARINFO);     // Size field
  mbi.hwndParent = hWnd;                  // Parent window
  mbi.dwFlags = SHCMBF_EMPTYBAR;          // Flags like hide SIP btn
  mbi.nToolBarId = 0;                     // ID of toolbar resource
  mbi.hInstRes = 0;                       // Inst handle of app
  mbi.nBmpId = 0;                         // ID of bitmap resource
  mbi.cBmpImages = 0;                     // Num of images in bitmap 
  mbi.hwndMB = 0;                         // Handle of bar returned

  // Create menu bar and check for errors.
  if (!SHCreateMenuBar(&mbi)) {
    MessageBox (hWnd, TEXT ("Couldn\'t create menu bar"), 
      szAppName, MB_OK);
    DestroyWindow (hWnd);
  }
  hwndMenuBar = mbi.hwndMB;               // Save the menu bar handle.

  // Query the sip state and size our window appropriately.
  memset (&si, 0, sizeof (si));
  si.cbSize = sizeof (si);
  SHSipInfo(SPI_GETSIPINFO, 0, (PVOID)&si, FALSE); 
  cx = si.rcVisibleDesktop.right - si.rcVisibleDesktop.left;
  cy = si.rcVisibleDesktop.bottom - si.rcVisibleDesktop.top;

  // If the sip is not shown, or showing but not docked, the
  // desktop rect doesn't include the height of the menu bar.
  if (!(si.fdwFlags & SIPF_ON) ||
      ((si.fdwFlags & SIPF_ON) && !(si.fdwFlags & SIPF_DOCKED))) {
    RECT rectMB;
    GetWindowRect (hwndMenuBar, &rectMB);
    cy -= (rectMB.bottom - rectMB.top);  
  }
    
  SetWindowPos (hWnd, NULL, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER);
  return 0;
}

//----------------------------------------------------------------------
// DoCommandMain - Process WM_COMMAND message for window.
//
LRESULT DoCommandMain (HWND hWnd, UINT wMsg, WPARAM wParam,
    LPARAM lParam) {
  WORD idItem, wNotifyCode;
  HWND hwndCtl;
  INT  i;

  // Parse the parameters.
  idItem = (WORD) LOWORD (wParam);
  wNotifyCode = (WORD) HIWORD (wParam);
  hwndCtl = (HWND) lParam;

  // Call routine to handle control message.
  for (i = 0; i < dim(MainCommandItems); i++) {
    if (idItem == MainCommandItems[i].Code)
      return (*MainCommandItems[i].Fxn)(hWnd, idItem, hwndCtl,
          wNotifyCode);
  }
  return 0;
}

//----------------------------------------------------------------------
// DoPaintMain - Process WM_PAINT message for window.
//
LRESULT DoPaintMain (HWND hWnd, UINT wMsg, WPARAM wParam, 
    LPARAM lParam) {
  PAINTSTRUCT ps;
  HPEN hPen, hOld;
  RECT rect;
  HDC hdc;

  hdc = BeginPaint (hWnd, &ps); 
  GetClientRect (hWnd, &rect);

  // Draw a red rectangle around the window.
  hPen = CreatePen (PS_SOLID, 1, RGB (255, 0, 0));
  hOld = (HPEN)SelectObject (hdc, hPen);
  Rectangle (hdc, rect.left, rect.top, rect.right, rect.bottom);
  SelectObject (hdc, hOld);
  DeleteObject (hPen);

  // Draw the standard hello text centered in the window.
  DrawText (hdc, TEXT ("Hello Pocket PC! "), -1, &rect, 
      DT_CENTER | DT_VCENTER | DT_SINGLELINE);

  EndPaint (hWnd, &ps); 
  return 0;
}

//----------------------------------------------------------------------
// DoSettingChangeMain - Process WM_SETTINGCHANGE message for window.
//
LRESULT DoSettingChangeMain (HWND hWnd, UINT wMsg, WPARAM wParam, 
    LPARAM lParam) {
 
  // Notify shell of our WM_SETTINGCHANGE message.
  SHHandleWMSettingChange(hWnd, wParam, lParam, &sai);
  return 0;
}

//----------------------------------------------------------------------
// DoActivateMain - Process WM_ACTIVATE message for window.
//
LRESULT DoActivateMain (HWND hWnd, UINT wMsg, WPARAM wParam, 
    LPARAM lParam) {

  // If activating, restore any hibernated stuff.
  if ((LOWORD (wParam) != WA_INACTIVE) && fHibernated) {
    fHibernated = FALSE;
  }

  // Notify shell of our activate message.
  SHHandleWMActivate(hWnd, wParam, lParam, &sai, 0);
  return 0;
}

//----------------------------------------------------------------------
// DoHibernateMain - Process WM_HIBERNATE message for window.
//
LRESULT DoHibernateMain (HWND hWnd, UINT wMsg, WPARAM wParam, 
    LPARAM lParam) {
 
  // If not the active window, reduce our memory footprint.
  if (GetActiveWindow() != hWnd) {
    fHibernated = TRUE;
  }
  return 0;
}

//----------------------------------------------------------------------
// DoDestroyMain - Process WM_DESTROY message for window.
//
LRESULT DoDestroyMain (HWND hWnd, UINT wMsg, WPARAM wParam, 
    LPARAM lParam) {
  PostQuitMessage (0);
  return 0;
}

//======================================================================
// Command handler routines
//----------------------------------------------------------------------
// DoMainCommandExit - Process Program Exit command.
//
LPARAM DoMainCommandExit (HWND hWnd, WORD idItem, HWND hwndCtl,
    WORD wNotifyCode) {
  SendMessage (hWnd, WM_CLOSE, 0, 0);
  return 0;
}