Question:
How do I create a Control Panel Applet?
Answer:
Creating a Control Panel Applet is a straight forward process.
Simply create a Dynamic Link Library with the extension of .cpl
(Control Panel Library) and place it in the Windows system directory.
Each cpl file can support multiple control panel applets. The cpl will
have a single function entry point called CPlApplet() that must be
exported by name. All the following control panel messages will come
through this single entry point:
Message:
CPL_INIT - Sent to indicate CPlApplet() was found. Return TRUE
to continue the loading process.
CPL_GETCOUNT - Return the number of applets supported by the cpl.
CPL_INQUIRE - Sent for information about each applet supported by the
cpl.lParam1 contains the zero based applet number for the inquiry.
lParam2 points to a TCplInfo structure. The idIcon field of the
TClpInfo structure should be initialized with the resource id for an
icon to display, and the idName and idInfo fields should be
initialized with the resource string id for the name and description
string id.lData can contain applet defined data for use by the applet.
CPL_SELECT - Sent when the applet's icon has been selected by the
user. lParam1 contains the applet number that was selected. lParam2
contains the applet's user defined lData value.
CPL_DBLCLK - Sent when the applet's icon has been double-clicked.
lParam1 contains the applet number. lParam2 contains the applet's
user defined lData value. This message initiates the display of the
applet's dialog box.
CPL_STOP - Sent for each applet when the control panel is exiting.
lParam1 contains the applet number. lParam2 contains the applet's user
defined lData value. Any applet specific cleaning up should be
performed during this call.
CPL_EXIT - Sent prior to the control panel call to FreeLibrary.
Non-applet specific cleaning up should be performed during this call.
CPL_NEWINQUIRE - Same as CPL_INQUIRE except lParam2 is a pointer to a
NEWCPLINFO structure.
Your control panel library will need some additional resources to
function. You will need to create a resource file containing a string
table containing both the name and description of your applet(s) and
icons for each applet in your cpl. You can create a res file from a
.rc (resource script file) using the BRCC.EXE or BRCC32.EXE command
line resource compiler, or a WYSIWYG resource editor like Borland's
Resource Workshop.
Example .rc file containing a string table with two strings and a
pointer to a icon file resource:
STRINGTABLE
{
1, "TestApplet"
2, "My Test Applet"
}
2 ICON C:\SOMEPATH\CHIP.ICO
To compile the .rc file to a .res file that can be linked with your
application, simply type on the dos command line the full path to the
resource compiler, and the full path to the name of the .rc file to
compile. Here is an example:
c:\Delphi\Bin\brcc32.exe c:\Delphi\MyRes.rc
When the compiler is finished, you should have a new file with the
same name as the .rc file you've compiled, only with an extension of
".res".
If you are developing for multiple platforms, you should create both a
16 and 32 bit res file for linkage with your application.
The following is an example of a control panel applet that executes a
secondary executable in response to the CPL_DBLCLK message. You can
adapt the code to show a form or dialog box as well. The example is
coded to compile for Win16 and Win32 environments.
To build the project, you will need to compile the above .rc file to a
res file named either: TCPL32.RES or TCPL16.RES.
Example:
library TestCpl;
{$IFDEF WIN32}
uses
SysUtils,
Windows,
Messages;
{$ELSE}
uses
SysUtils,
WinTypes,
WinProcs,
Messages;
{$ENDIF}
{$IFDEF WIN32}
{$R TCPL32.RES}
{$ELSE}
{$R TCPL16.RES}
{$ENDIF}
const NUM_APPLETS = 1;
{$IFDEF WIN32}
const CPL_DYNAMIC_RES = 0;
{$ENDIF}
const CPL_INIT = 1;
const CPL_GETCOUNT = 2;
const CPL_INQUIRE = 3;
const CPL_SELECT = 4;
const CPL_DBLCLK = 5;
const CPL_STOP = 6;
const CPL_EXIT = 7;
const CPL_NEWINQUIRE = 8;
{$IFDEF WIN32}
const CPL_STARTWPARMS = 9;
{$ENDIF}
const CPL_SETUP = 200;
{$IFNDEF WIN32}
type DWORD = LongInt;
{$ENDIF}
type TCplInfo = record
idIcon : integer;
idName : integer;
idInfo : integer;
lData : LongInt;
end;
PCplInfo = ^TCplInfo;
type TNewCplInfoA = record
dwSize : DWORD;
dwFlags : DWORD;
dwHelpContext : DWORD;
lData : LongInt;
IconH : HIcon;
szName : array [0..31] of char;
szInfo : array [0..63] of char;
szHelpFile : array [0..127] of char;
end;
PNewCplInfoA = ^TNewCplInfoA;
{$IFDEF WIN32}
type TNewCplInfoW = record
dwSize : DWORD;
dwFlags : DWORD;
dwHelpContext : DWORD;
lData : LongInt;
IconH : HIcon;
szName : array [0..31] of WChar;
szInfo : array [0..63] of WChar;
szHelpFile : array [0..127] of WChar;
end;
PNewCplInfoW = ^TNewCplInfoW;
{$ENDIF}
type TNewCplInfo = TNewCplInfoA;
type PNewCplInfo = ^TNewCplInfoA;
function CPlApplet(hWndCPL : hWnd;
iMEssage : integer;
lParam1 : longint;
lParam2 : longint) : LongInt
{$IFDEF WIN32} stdcall; {$ELSE} ; export; {$ENDIF}
begin
case iMessage of
CPL_INIT : begin
Result := 1;
exit;
end;
CPL_GetCount : begin
Result := NUM_APPLETS;
exit;
end;
CPL_Inquire : begin
PCplInfo(lParam2)^.idIcon := 2;
PCplInfo(lParam2)^.idName := 1;
PCplInfo(lParam2)^.idInfo := 2;
PCplInfo(lParam2)^.lData := 0;
Result := 1;
exit;
end;
CPL_NewInquire : begin
PNewCplInfo(lParam2)^.dwSize := sizeof(TNewCplInfo);
PNewCplInfo(lParam2)^.dwHelpContext := 0;
PNewCplInfo(lParam2)^.lData := 0;
PNewCplInfo(lParam2)^.IconH := LoadIcon(hInstance,
MakeIntResource(2));
lStrCpy(@PNewCplInfo(lParam2)^.szName, 'TestCPL');
lStrCpy(PNewCplInfo(lParam2)^.szInfo, 'My Test CPL');
PNewCplInfo(lParam2)^.szHelpFile[0] := #0;
Result := 1;
exit;
end;
CPL_SELECT : begin
Result := 0;
exit;
end;
CPL_DBLCLK : begin
WinExec('Notepad.exe', SW_SHOWNORMAL);
Result := 1;
exit;
end;
CPL_STOP : begin
Result := 0;
exit;
end;
CPL_EXIT : begin
Result := 0;
exit;
end else begin
Result := 0;
exit;
end;
end;
end;
exports CPlApplet name 'CPlApplet';
begin
end.