An Ancient Story of Control Panel Applets

Control Panel is really an ancient creature in MS Windows. It was introduced when Windows first began. But nevertheless, it is still alive, and can serve your needs perfectly, providing an easy and powerful mechanism for Control Panel applets. You will definitely find a lot of articles on this theme all over the Web, which more or less desribe what you should do to develop an applet. In this tutorial, I’d like to combine different aspects of Control Panel programming, so you will be able to get a relatively full picture of what’s happening there.

Dry Theory

Prior to diving into coding, let me formalize what I am going to speak about. Each Control Panel applet is just a DLL that exports only one function: CPlApplet. Well, applets also have an extension of ‘cpl’ instead of ‘dll,’ so you will simply need to change it in project settings. Thus, a typical DEF-file may look like this:

LIBRARY TESTAPPLET

EXPORTS CPlApplet

CPlApplet is called upon for a few basic events. I’ll show you its schematic definition:

LONG CALLBACK CPlApplet (HWND hwndCPL, UINT uMsg, LONG lParam1,
                         LONG lParam2)
{
...
   switch (uMsg)
   {
      // First message sent. It is sent only once to allow the
      // DLL to initialize its applet(s)
      case CPL_INIT:
      ...
         return TRUE;

      // Second message sent. Return the count of applets supported
      // by this DLL
      case CPL_GETCOUNT:
         // Return the number of applets we support
         return (LONG) nApplets;

      // Third message sent. Sent once for each applet supported by
      // this DLL.
      // The lParam1 contains the number that indicates which applet
      // this is for, from 0 to 1 less than the count of applets.
      // lParam2 is a NEWCPLINFO that should be filled with
      // information about this applet before returning
      case CPL_NEWINQUIRE:
         {
            LPNEWCPLINFO lpNewCPlInfo;
            // Fill this struct in
            ...
         }

         break;

      // This is sent whenever the user clicks an icon in Settings
      // for one of the applets supported by this DLL. lParam1
      // contains the number indicating which applet. Returns 0 if
      // applet was successfully launched; non-zero otherwise
      case CPL_DBLCLK:
         ...
         break;

      // Sent once per applet, before CPL_EXIT
      case CPL_STOP:
         break;

      // Sent once before the DLL is unloaded
      case CPL_EXIT:
         ...
         break;

      default:
         break;
   }

   return 0;
}

You’ll find it quite simple. The OS informs your DLL when it should perform the following actions:

  • DLL’s initialization—Here you can proceed any required ‘global’ initialization
  • DLL’s deinitialization—Here you will release all ‘globally’ allocated resources
  • Provide a number of applets in the DLL—Each DLL can contain several applets, so the OS wants to know how many your DLL keeps inside
  • An intialization for each applet in the DLL—Here you will initialize each applet; for example, create some GUI components and so forth.
  • Stop notification for each applet in the DLL—that’s a point to release applets’ resources
  • Launch a selected applet—and finally—Go!

That is actually the whole fact sheet you need to know about this business to start programming Control Panel applets.

Turning to Practice

Well, you will be quite right in claiming that all that was written above is not enough to produce a standard-fit CP applet. This section will provide you with some additional useful information on this topic. You will add some flesh to the previously created skeleton.

Initializing an applet

First, I’ll present the NEWCPLINFO struct. A pointer to this data is sent to CPlApplet as an lParam2 parameter of the CPL_NEWINQUIRE message when Control Panel needs to obtain initial information regarding your applet and initialize it. The following table contains some short explanations and comments on NEWCPLINFO‘s members:

typedef struct tagNEWCPLINFO {
   DWORD dwSize;
   DWORD dwFlags;
   DWORD dwHelpContext;
   LONG lData;
   HICON hIcon;
   TCHAR szName[32];
   TCHAR szInfo[64];
   TCHAR szHelpFile[128];
} NEWCPLINFO;
Name Description
dwSize The length of struct in bytes; in other words, sizeof(NEWCPLINFO)
dwFlags Ignored in Windows CE
dwHelpContext Ignored in Windows CE
lData Application-defined data sent to your applet by Control Panel when it launches and stops it. The application should return an icon ID in this member
hIcon Icon handle to be displayed in Control Panel
szName Null-terminated string that contains the name displayed below the icon in Control Panel
szInfo Null-terminated string that contains the applet’s description. The description is intended to be displayed when the icon for the applet is selected
szHelpFile Ignored in Windows CE

To illustrate all this, the tiny code snippet below guides you through the flow:

int            iApplet      = (int)lParam1;
LPNEWCPLINFO   lpNewCPlInfo = (LPNEWCPLINFO)lParam2;

lpNewCPlInfo->dwSize        = (DWORD)sizeof(NEWCPLINFO);
lpNewCPlInfo->dwFlags       = 0;
lpNewCPlInfo->dwHelpContext = 0;
lpNewCPlInfo->lData         = g_nIconID;
lpNewCPlInfo->hIcon         = LoadIcon(g_hInstance,
                              (LPCTSTR)MAKEINTRESOURCE(g_nIconID));
lpNewCPlInfo->szHelpFile[0] = '';

LoadString(g_hInstance,IDS_NAME,lpNewCPlInfo->szName,32);
LoadString(g_hInstance,IDS_DESC,lpNewCPlInfo->szInfo,64);

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read