INTELLIGENT WORK FORUMS
FOR COMPUTER PROFESSIONALS

Log In

Come Join Us!

Are you a
Computer / IT professional?
Join Tek-Tips Forums!
  • Talk With Other Members
  • Be Notified Of Responses
    To Your Posts
  • Keyword Search
  • One-Click Access To Your
    Favorite Forums
  • Automated Signatures
    On Your Posts
  • Best Of All, It's Free!

*Tek-Tips's functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.

Posting Guidelines

Promoting, selling, recruiting, coursework and thesis posting is forbidden.

Jobs

How To

How do I write a Control Panel Applet? by Glenn9999
Posted: 29 Jul 11

This gives a short example of how to write a control panel applet in Delphi.  While I am aware that later Delphis have the option to create a "control panel" application, this shows what is needed to construct one otherwise.  This FAQ will only show the remarkable steps and parts of a Control Panel app and will leave out other things.

Much of this is based off the "Creating Control Panel Applets with Delphi" by Ted Houts entry that was copied to a searched web page.  Source has been cleaned up and documented.

Resource File
A number of resource entries are required.  A string table listing the title and information regarding each applet your file will support is required.  As well, an icon for each applet entry is required.  You will need to build this file using BRCC32.  An example for that is to come.

cp_resource.rc

CODE

STRINGTABLE {
//the "title" of applet #1
10, "Demo Current Time #1"
//the description of applet #1
11, "Shows the current system time..."
//the "title" of applet #2
20, "Demo Current Time #2"
//the description of applet #2
21, "Shows the current system time..." }

12 ICON applet1.ico //the icon for applet #1
22 ICON applet2.ico //the icon for applet #2

Application Source
The next major question is the application source itself.  CPL files are DLL files with a different extension and support the export by name of a function called "CPlApplet".  The forms as defined in this file are standard VCL forms which may be developed as regular applications for testing, since there is nothing remarkable that we need to do for control panel applications within those.  Hopefully the documentation in the comments should be sufficient:

myapplets.dpr

CODE

library myapplets;
  uses SysUtils, Classes, Windows, cpl //a unit in Delphi 3,
       frmApplet1 in 'frmApplet1.pas',
       frmApplet2 in 'frmApplet2.pas';

{ Demo control panel application
  based off of a link to "Creating Control Panel Applets with Delphi" by Ted Houts
  cleaned up & posted on tek-tips by Glenn9999 }

{$E cpl}                 //changes the extension to CPL from DLL
{$R cp_resource.RES}     //resource built containing the icons and string for the applets in this .CPL
const
  APPLETS_COUNT = 2;     //the number of applets (items that show up in Control Panel)

var
  Frm_Applet1 : TFrm_Applet1; //applet #1
  Frm_Applet2 : TFrm_Applet2; //applet #2
//This procedure puts the action of opening applet dialog boxes into one place

procedure OpenDialogBox(DlgNo,PageNo : Integer);
{
  This project has 2 applets (dialogs) which are roughly identical.
  If zero is passed, open the first applet; otherwise, one should be passed,
  but just in case, any other value for dialog number will open the second applet.
}
  begin
    if DlgNo = 0 then
      begin
        Frm_Applet1 := TFrm_Applet1.Create(nil);
        // this line puts the icon resource associated with this form in control panel
        // to the VCL form itself
        Frm_Applet1.Icon.Handle :=
               LoadIcon(hInstance, MakeIntResource( (10 * (DlgNo + 1)) + 2));
        Frm_Applet1.ShowModal;
      end
    else
      begin
        Frm_Applet2 := TFrm_Applet2.Create(nil);
        // this line puts the icon resource associated with this form in control panel
        // to the VCL form itself
        Frm_Applet2.Icon.Handle :=
               LoadIcon(hInstance, MakeIntResource( (10 * (DlgNo + 1)) + 2));
        Frm_Applet2.ShowModal;
      end;
   end;

{
CPlApplet is the callback function that processes all messages from
"controlling application", i.e. Control Panel
}

function CPlApplet(hWndCPL : hWnd; iMessage : integer; lParam1 : longint;
         lParam2 : longint) : LongInt stdcall;
  begin
    case iMessage of
      CPL_INIT :
      //first message, sent once: this is the time to create global objects
        begin
          Result := 1;
          exit;
        end;
      CPL_GETCOUNT :
      //second message sent once, return the number of applets supported by this file
        begin
          Result := APPLETS_COUNT; //number of dialog boxes supported
          exit;
        end;
      CPL_INQUIRE :
     //Filling in the CPLINFO record with resource information. NOTE resource
     //file has clever IDs so as to make the code based on the dialog number,
     //see cp_resource.rc. lParam1 is zero-based dialog (or applet) number.
     //lParam2 is a pointer to a CPLINFO record that's filled with the applet
     //information, including "lData," which can point to application-specific
     //stuctures. Fill the record and return 0.
        begin
          PCplInfo(lParam2)^.idName := (10 * (lParam1 + 1)) + 0;
          PCplInfo(lParam2)^.idInfo := (10 * (lParam1 + 1)) + 1;
          PCplInfo(lParam2)^.idIcon := (10 * (lParam1 + 1)) + 2;
          PCplInfo(lParam2)^.lData := 0;
          Result := 0; //handled, returning zero
          exit;
        end;
      CPL_NEWINQUIRE :
     //This has an identical function to CPL_INQUIRE except that it requires
     //a different format set for data.  See above for notes.
        begin
          PNewCplInfo(lParam2)^.dwSize := sizeof(TNewCplInfo);
          PNewCplInfo(lParam2)^.lData := 0;
          PNewCplInfo(lParam2)^.HIcon :=
               LoadIcon(hInstance, MakeIntResource( (10 * (lParam1 + 1)) + 2));
          LoadString(hInstance, (10 * (lParam1 + 1)) + 0,
               @PNewCplInfo(lParam2)^.szName, sizeof(PNewCplInfo(lParam2).szName));
          LoadString(hInstance, (10 * (lParam1 + 1)) + 1,
               @PNewCplInfo(lParam2)^.szInfo, sizeof(PNewCplInfo(lParam2).szInfo));
          PNewCplInfo(lParam2)^.dwHelpContext := 0;
          PNewCplInfo(lParam2)^.szHelpFile[0] := #0;
          Result := 0; //handled, returning zero
          exit;
        end;
      CPL_SELECT :
      // obsolete message supported for backwards compatibility.
        begin
          Result := 0;
          exit;
        end;
      CPL_DBLCLK :
      //user has double-clicked one of your icons in the control panel, respond here
        begin
          OpenDialogBox(lParam1,0);
          Result := 0; //handled, returning zero
          exit;
        end;
      CPL_STOP :
      //sent once per applet, do form shutdown code here.
        begin
          if lParam1 = 0 then
            Frm_Applet1.Free  //user has closed Applet #1 form
          else
            Frm_Applet2.Free; //user has closed Applet #2 form
          Result := 0; //handled, returning zero
          exit;
        end;
      CPL_EXIT :
        begin //sent once this is the time to free global objects
          Result := 0; //handled, return 0
          exit;
        end;
      CPL_STARTWPARMS : //CPL_STARTWPARMSA, CPL_STARTWPARMSW
        //sent when applet started via rundll32.exe this .CPL will support an
        //integer param to indicate the page number, default to page one
        //if invalid
        //lParam2 is the parameter string passed in the command line.
        //lParam1 and return value are the same as CPL_DBLCLK
        begin
          OpenDialogBox(lParam1, StrToIntDef(String(lParam2),1));
          Result := 1; //handled, so return 1
          exit;
        end;
      else
        begin
          Result := 0; // return 0 to indicate that this message isn't processed
          exit;
        end;
    end;
end;

//as required export CPLApplet by name
  exports CPlApplet name 'CPlApplet';

begin
end.

The above code is all that is required to write a control panel application.

Testing
Testing, however, is another story.  To generate the RES file for the RC posted above, one needs to call BRCC32 against this file.  I like to make a batch file and have it run the compile against the project as well, since I find this is usually required if a change is required in the RC file.  A sample is below and you will need to change it to match what your system is.

BUILD.BAT

CODE

"C:\Program Files\Borland\Delphi 3\Bin\brcc32.exe" cp_resource.rc
"C:\Program Files\Borland\Delphi 3\Bin\dcc32.exe" myapplets.dpr
rem To Deploy to the system directory if necessary.
rem copy myapplets.cpl C:\Windows\system32

rem clean up old files
del *.~*
pause

In running the code, you can either make the file so control panel picks it up and test there, or use RUNDLL32.  Doing the former involves either:
1. Copy the .CPL file to the system directory.
2. Copy the .CPL file to the directory where the controlling application exists (Control.exe).
3. Setting a direct Install Location String: Place key in HKCU/Control Panel/MMCPL Key should be in format:  <AppletName>=<path to CPL file>

To run with RUNDLL32, use the following call (case sensitivity matters):

CODE

rundll32 shell32.dll,Control_RunDLL "myapplets.cpl", @0

This can be beneficial in testing your code as well, as to not run into WFP on later versions of Windows.  It is useful to test your control panel app using both methods just to be sure.

Back to Embarcadero: Delphi FAQ Index
Back to Embarcadero: Delphi Forum

My Archive

Resources

Close Box

Join Tek-Tips® Today!

Join your peers on the Internet's largest technical computer professional community.
It's easy to join and it's free.

Here's Why Members Love Tek-Tips Forums:

Register now while it's still free!

Already a member? Close this window and log in.

Join Us             Close