September 29, 2020
Hot Topics:

Developing Windows CE Device Drivers: May a Regular Application Benefit from It?

  • By Alex Gusev
  • Send Email »
  • More Articles »

The next step is to implement the PWR_Open function. Because your driver does nothing, almost all its interface functions will be empty. PWR_Open stands a bit aside, because here you can decide what kind of access to the device you are going to implement: single or multiple. So, by having as such simple code as:

                          DWORD dwAccessCode,
                          DWORD dwShareMode)
   // return the same value for single access or a different one
   // for multiple
   return 1;

the driver's behavior can vary. You use the simplest case, so your driver provides single access only. For the implementation of all other stream functions, you will return an error.

Now, turn to core driver's procedure, PWR_IOControl:

           DWORD hOpenContext,     // open context handle
           DWORD dwCode,           // I/O control code
           PBYTE pBufIn,           // input buffer
           DWORD dwLenIn,          // input buffer size
           PBYTE pBufOut,          // output buffer
           DWORD dwLenOut,         // output buffer size
           PDWORD pdwActualOut)    // actual output bytes returned
   BOOL bRet = FALSE;
   PDWORD pDatIn  = (PDWORD) pBufIn;
   PDWORD pDatOut = (PDWORD) pBufOut;

   switch (dwCode) {

      // return power up notification value in the output buffer
      *pDatOut = g_bPoweredUp;
      *pdwActualOut = sizeof(g_bPoweredUp);
      bRet = TRUE;

      // reset the power up notification value
      g_bPoweredUp = FALSE;
      bRet = TRUE;

      // enable the power up notification messaging by getting the
      // messaging HWND in the input buffer
      g_hMsgWnd = (HWND) *pDatIn;
      bRet = TRUE;

      // disable the power up notification messaging
         g_hMsgWnd = NULL;
      bRet = TRUE;

   return bRet;

This function is a connection point between your driver and other applications. Regular code may call DeviceIOControl to talk to your driver. You normally provide an API header, something like this:

// Definitions to be included by an application using the
// power on notification driver, PWRDRV.DLL.

// Power up detected windows message, sent to the application
// by the driver
#define WM_PWR_POWERUP  (WM_USER+0x1000)

// IO control functions to be used in DeviceIoControl calls to
// the driver as the dwIoControlCode parameter.
//   Get the current power up detection value.
//     The lpOutBuffer parameter should be of size DWORD and
//     will contain the boolean state of power up detection.
#define IOCTL_PWR_GET_POWERUP_STATE         0x00000001
//   Reset the power up detection value.
//     Requires no parameters.
#define IOCTL_PWR_RESET_POWERUP_STATE       0x00000002
//   Enable the power up detection messaging.
//     The lpInBuffer parameter should point to the HWND
//     (not contain the HWND itself) for the window to
//     receive the power up messages.
//   Disable the power up detection messaging.
//     Requires no parameters.

Third-party applications use this API in the following manner:

   g_hPwrDll,                         // file handle to the driver
   IOCTL_PWR_ENABLE_POWERUP_MESSAGE,  // I/O control code (enable
                                      // messages)
   &g_hWnd,                           // in buffer (HWND to send
                                      // messages to)
   sizeof(g_hWnd),                    // in buffer size
   NULL,                              // out buffer
   0,                                 // out buffer size
   &dwBytesReturned,                  // number of bytes returned
   NULL);                             // ignored (=NULL)

The last topic is notification handling. There is nothing new there because your driver simply posts a message to the given window. You may easily modify the code to send broadcast messages to all windows. Thus, a typical message handler for an MFC application may look like this:

LRESULT CYourClass::OnPowerUp(WPARAM wParam, LPARAM lParam)
   // do whatever you want to here
   return 1;

As a bottom line, such a mechanism allows you to utilize system services in your own applications when standard APIs don't provide the required support.


This article overviewed a simple device driver and its usage from a regular application. Such a technique may allow your software to utilize a lot of things a standard OS API just can't provide. Working together with the driver, the application gets additional functionality and can significantly empower itself.


Download the accompanying code's zip file here.

About the Author

Alex Gusev started to play with mainframes at the end of the 1980s, using Pascal and REXX, but soon switched to C/C++ and Java on different platforms. When mobile PDAs seriously rose their heads in the IT market, Alex did it too. Now, he works at an international retail software company as a team leader of the Mobile R department, making programmers' lives in the mobile jungles a little bit simpler.

Page 2 of 2

This article was originally published on May 4, 2006

Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Thanks for your registration, follow us on our social networks to keep up-to-date