An Ancient Story of Control Panel Applets, Page 2
Responding to the CPL_DBLCLK message
Microsoft's GUI requirements for 'Pocket PC breeded' systems say that you should create a full-screen window with its own title (not a navigation bar). Surely, you are free to choose which GUI you will support in your own applet. But, as in many other cases, a standard look-and-feel will be more comfortable for the end user. Hence, the property sheet style looks like the best choice for a Control Panel applet. Nevertheless, you always have another option to run an arbitrary standalone application in response to CPL_DBLCLK. The next sample shows you both opportunities:
// Create appropriate Property Sheet
case CPL_DBLCLK:
{
int iApplet = (UINT)lParam1;
if (!CreatePropertySheet(hwndCPL,iApplet))
return 1;
}
break;
...
// Launch arbitrary application
case CPL_DBLCLK:
{
int iApplet = (UINT)lParam1;
PROCESS_INFORMATION pi;
if ( CreateProcess(L"SomeApp.exe",L"CmdLine",0,0,0,0,0,0,0,&pi) )
{
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
else
return 1;
}
break;
Hosting applets with Control Panel
A 'host' application that calls applets is ctlpnl.exe. It enables you to easily call other applets programmatically. A syntax for a call is as follows:
ctlpnl.exe cplmain.cpl,<AppletIndex>[,<PropPageIndex>]
All it does is activate the default applet (cplmain.cpl), passing the desired predefined index of the system applet and, optionally, the property page index if the applet has several pages. Unfortunately, indexes of system applets vary between different versions of Windows CE, but this can be overcome easily. Below is a sample table that contains applets available on my Pocket PC 2003 SE. Notice that all indexing starts from 0:
| Name | Index | Page |
|---|---|---|
| Contrast | 0 | n/a |
| Password | 1 |
|
| Owner Information | 2 |
|
| Power | 3 |
|
| Memory | 4 |
|
| About | 5 |
|
| Backlight | 6 |
|
| Screen | 7 |
|
| Input | 8 |
|
| Sounds & Notifications | 9 |
|
| Remove Programs | 10 | n/a |
| Menus | 11 |
|
| Buttons | 12 |
|
| Today | 13 |
|
| Not In Use | 14 | n/a |
| Beam | 15 | n/a |
| Clock & Alarms | 16 |
|
| Network Cards | 17 | n/a |
| Regional Settings | 18 |
|
| Connections | 19 |
|
| Not in Use | 20 | n/a |
| Not in Use | 21 | n/a |
| Certificates | 22 |
|
| Bluetooth | 23 |
|
You can continue to explore cplmain.cpl even more. Becayse it is just a regilar DLL with a known exported function, you can easily load it and call CPlApplet directly:
typedef LONG (CALLBACK *LPCPlAppletType)(HWND hwndCPL, UINT uMsg,
LONG lParam1, LONG lParam2);
#include <cpl.h>
void CCPTestDlg::OnButtonHack()
{
HINSTANCE hInst = ::LoadLibrary(L"cplmain.cpl");
if ( hInst )
{
LPCPlAppletType pfnCPlApplet =
(LPCPlAppletType)GetProcAddress(hInst,L"CPlApplet");
if ( pfnCPlApplet )
{
LONG lRes = pfnCPlApplet(NULL,CPL_GETCOUNT,0,0);
CString sInfo;
sInfo.Format(L"AppletsCount = %lu",lRes);
AfxMessageBox(sInfo);
}
::FreeLibrary(hInst);
}
}
Continuing on, you can call CPlApplet with CPL_NEWINQUIRE / CPL_STOP messages, getting more info about the implemented applets.
I personally prefer a PropertySheet-like style for Control Panel applets because Property Sheet gives me a simple mechanism to provide a GUI title and hyperlinks to any other resources, including applets or whatever else. These features are available on the Pocket PC platform only. Actually, a window procedure should handle two messages: PSCB_GETTITLE and PSCB_GETLINKTEXT. The last code snippet show those simple handlers:
case PSCB_GETTITLE:
wcscpy((TCHAR*)lParam,TEXT("Test Applet"));
break;
case PSCB_GETLINKTEXT:
wcscpy((TCHAR*)lParam,TEXT("Go to <file:ctlpnl.exe cplmain.cpl,
11,1{menu}> applet.\r\n"));
wcscat((TCHAR*)lParam,TEXT("Go to <file:ctlpnl.exe cplmain.cpl,
4,1{memory}> applet.\r\n"));
wcscat((TCHAR*)lParam,TEXT("Go to <file:calc.exe{calculator}>.
\r\n"));
break;
Conclusions
Control Panel applets are still alive. They are easily doable and provide a convenient mechanism to configure your applications at the 'back-door'. You can use them even if your applications have their own GUI. I believe you'll enjoy developing applets for Control Panel.
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.
