Download source files - 10 Kb
The Windows Control Panel is the ideal way to
allow a user to alter settings for an application that runs in the background,
or automatically. When I was exploring NT Services it seemed like a good idea
to control my service using a control panel applet. But what are
control panel applets and how do you write one? Well, after some exploring
in the MSDN I discovered that control panel applets are just standard DLLs
with a particular set of entry points and a .cpl extension. Place such a file
in the Windows System directory and the next time you start up control panel
your applet will be there. Having discovered what I needed to know I set about
writing a control panel applet and once I'd done that, I turned the bulk of
the code into a mini applet framework so I wouldn't have to write it ever
Anatomy of a control
Control panel applets are pretty old now, and no doubt some day soon they will
be replace by fully fledged COM objects. In the mean time they're a reasonable
first attempt at component based programming. A control panel applet is a
DLL that presents a standard interface to the Control Panel application. When
Control Panel starts it locates all the .cpl files in the Windows System directory
and tries to load them as DLLs. If this works then it tries to locate a function
CPlApplet() in the newly loaded DLL. If the DLL has the function
entry point then it's a control panel applet! But there's more, a single DLL
can contain multiple applets and they each appear as a separate icon in Control
CPlApplet() is a relatively simple function taking a window handle,
a message and a couple of message specific parameters. Writing one is similar
to writing a normal window proc and is reasonably well documented in MSDN
and the VC++ online help. The framework that I produced provides an implementation
CPlApplet(), along with a
DllMain() and wires these DLL entry
points up to a class designed to be a base class for your applets. Simply
CJBControlPanelApplet, build a DLL with a .cpl extension
and with the link with framework and you're done!
What does CJBControlPanelApplet give you?
To be a control panel applet your
CPlApplet() entry point has to respond
appropriately to messages from the Control Panel application. Most of these
messages are mundane, housekeeping.
CJBControlPanelApplet handles all
of this for you and provides virtual functions that you can override if you
want a little more control. If you wish, you only need handle one message,
by providing an
OnDoubleClick() handler for when your applet is activated
and should do its stuff. Each of the standard CPL_ messages has a corresponding
virtual message handler (except
CPL_GETCOUNT which is handled entirely
by the framework).
Your derived class
To implement your control panel applet you need
to do the following:
- include "ControlApplet.hpp" and publicly derive a class from
- call the
CJBControlPanelApplet constructor and pass resource IDs
for the applet's icon, name and description.
- implement the pure virtual function
OnDoubleClick() - this is where
your applet becomes live and can display a dialog or whatever.
- create an instance of your applet class at
- link with ControlApplet.cpp and include ControlApplet.def in your project.
ControlApplet.cpp gives you the implementation of
CPlApplet() DLL entry point functions.
If you wish you can also:
OnInit() - for resource acquisition, or start up code.
OnStop() - for resource release and shutdown code.
OnExit() - for last minute shut down code that wasn't put
OnStop() for some reason...
OnInquire() - if you really want to take over the filling
in of the
LPCPLINFO structure... Or perhaps you want to use
OnNewInquire() functionality so you might want to
return FALSE from here!
OnNewInquire() - if my handling of it doesn't suit you.
For dynamic icons or descriptions perhaps?
OnStartWithParams() - if you want to do clever things when
started with command line parameters by rundll.
Note the handling of the poorly documented
CPL_STARTWPARAMS has not
been tested since I don't have access to Windows 95 and rundll doesn't seem
to exist on NT4.
in one DLL
CJBControlPanelApplet implements a linked list of all active object
instances. Every time the constructor is called it links the current object
into the static list of all
CJBControlPanelApplet objects. Whenever
the DLL entry point processes a message it walks the static list of applets
and passes the message to each in turn. All you need to do is declare an object
of a type derived from
CJBControlPanelApplet at global scope and as
soon as the applet is loaded you object will be created and automatically
wired up to the list and begin receiving messages.
If you want to develop multiple applets as separate
DLLs that's fine, if you change your mind and want to have them all in the
same DLL then just link all the files together in one project and the framework
does the rest for you. No code changes!
See the article on Len's homepage for the latest updates.
Len has been programming for over 30 years, having first started with a Sinclair ZX-80
. Now he runs his own consulting company, JetByte Limited
and has a technical blog here
JetByte provides contract programming and consultancy services. We can provide experience in COM, Corba, C++, Windows NT and UNIX. Our speciality is the design and implementation of systems but we are happy to work with you throughout the entire project life-cycle. We are happy to quote for fixed price work, or, if required, can work for an hourly rate.
We are based in London, England, but, thanks to the Internet, we can work 'virtually' anywhere...
Please note that many of the articles here may have updated code available on Len's blog
and that the IOCP socket server framework is also available in a licensed, much improved and fully supported version, see here