您的位置:首页 > 编程语言 > Delphi

如何在Delphi中编写控制面板程序

2005-03-25 11:45 435 查看
摘要:

  对计算机的运行环境的配置有多种方法,而在WINDOWS 9X/NT中引入了一种新的方法,即控制面板。利用控制面板配置环境,方便直观。本文详细地介绍了控制面板程序的原理和编写方法,并给出了用Delphi4.0编写的一个实际例子。

关键字:

  控制面板程序、动态链接库、消息处理、注册表

前言:

  我们在编写软件时,有的时候需要用户对应用环境进行参数设置。常见的做法有编写一个安装程序,在安装过程中进行参数配置,或者在软件中提供一个专门的功能选项,用户在使用时可以利用这些功能选项来配置。这两种方法尤其是后者是一般软件中最常用的方法。在这里,向大家介绍一种新的方法:即利用控制面板程序(Control Panel applets)进行参数设置。我们都知道,在WINDOWS 9X/NT 中提供了控制面板,用户可以通过它很轻松地完成各种环境变量的设置,例如输入方法、ODBC等等。本文将用一个很简单的例子来说明如何在Delphi中实现控制面板程序。

1.控制面板程序

1.1CPlApplet

  控制面板程序是一种特殊的动态链接库(DLL),首先,其扩展名与一般的动态链接库不同,不是.DLL而是为.cpl。其次,它的标准入口函数不是DllMain()而是CplApplet()。CplApplet接收从控制面板发来的消息并作出相应的反映。CPlApplet的函数原形如下:

function CPlApplet(

hwndCPl:HWND; //程序主窗口的句柄

uMsg:word; //发送到控制面板程序的消息

lParam1:Longint; //消息参数

lParam2:Longint //消息参数

):Longint

uMsg有如下几种形式:

消息
发生时刻
相应的处理方法

CPL_DBLCLK

用户双击了该程序对应的图标
显示程序的主界面

CPL_EXIT

CPL_STOP之后
释放所有资源

CPL_GETCOUNT
CPL_INIT后
返回程序中对话框的数目

CPL_INIT
程序被装入内存后
初始化工作

CPL_INQUIRE*
CPL_GETCOUNT后
设定某个特定窗口的性质

CPL_NEWINQUIRE
CPL_GETCOUNT后
设定某个特定窗口的性质

CPL_SELECT*

CPL_STOP
程序关闭之前
释放对话框资源

* 是与旧版本的Windows兼容,Windows 9X/NT 4.0不再使用。

1.2控制面板程序中的消息处理过程

  CPlApplet函数处理发送到控制面板程序的所有消息。发送到控制面板程序的消息是按照一定的顺序进行的。

① 当程序被装入内存时,CPlApplet函数接收到CPL_INT消息。当接收到该消息后,CPlApplet函数应该作一些初始化的工作,例如分配内存等。如果初始化完成,应该返回非零,否则,返回零,这样程序将被终止。

② 如果CPL_INT被成功处理,CPlApplet函数将接收到CPL_GETCOUNT消息。CPlApplet必须返回对话框的数目。

③ 接着,CPlApplet接收到CPL_NEWINQUIRE消息。此时的lParam2是一个指向NEWCPL_INFO结构的指针。

Type

NEWCPL_INFO =Record

dwSize:Longword; //该结构的大小

dwFlags:Longword; //未用

dwHelpContext:Longword; //未用

lData:integer; //当消息为CPL_DBCLICK或CPL_STOP时,其为返回值

hIcon:HICON; //对话框的图标的句柄

szName:array[0..31] of char; //在控制面板中图标下的说明文字。

szInfo:array[0..63] of char; //在控制面板中状态行中的说明信息。

szHelpFile:array[0..127] of char; //未用

End;

接收到该消息后,CPlApplet必须填充该结构。指出其名称,提示信息、图标等。

④ 接着,CPlApplet接收到CPL_DBCLICK消息,在这里,一般是显示对话框以及处理用户的输入等。

⑤ 当用户关闭程序时,CPlApplet接收到CPL_STOP消息。此时应该释放分配的内存资源,若无,则可以忽略这一步。

⑥ 接着,CPlApplet接收到CPL_EXIT消息,Unregister各种窗口。

⑦ 最后,系统调用FreeLibrary将DLL(该控制面板程序)从内存中卸出。

一般情况下,我们只需处理CPL_DBCLICK和CPL_NEWINQUIRE即可。

2.一个简单的例子:

  本例是一个CPL的演示程序,其作用在于为某个客户软件设置其Socket的通信端口。该端口值放在HKEY_LOCAL_MACHINE/Software/silicon/papers下的port中。通过该程序可以更改其端口号。

其源代码如下:

//mycpl.dpr的源代码

library mycpl;

uses

SysUtils, Classes, u_main in 'u_main.pas' {f_main};

{$E cpl}

exports

CPlApplet ;

begin

end.

//u_main.pas的源代码

unit u_main;

interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

ComCtrls, ToolWin, StdCtrls, Buttons,registry;

type

Tf_main = class(TForm)

edPort: TEdit;

btnOk: TBitBtn;

btnCancel: TBitBtn;

Label1: TLabel;

procedure FormCreate(Sender: TObject);

procedure btnOkClick(Sender: TObject);

private

{ Private declarations }

public

{ Public declarations }

end;

type

NEWCPLINFO =record // ncpli

dwSize:Longword;

dwFlags:Longword;

dwHelpContext:Longword;

lData:integer;

hIcon:HICON;

szName:array[0..31] of char;

szInfo:array[0..63] of char;

szHelpFile:array[0..127] of char;

end;

type

PNEWCPLINFO=^NEWCPLINFO;

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;

var

f_main: Tf_main;

aa:TIcon;

RegF:TRegistry;

function CPlApplet(hwndCPl:HWND; uMsg:word;lParam1:Longint; lParam2:Longint):Longint ;stdcall;

function OnInquire(uAppNum:word; pInfo:PNEWCPLINFO):integer;stdcall;

function OnDblclk(hwndCPl:HWND;uAppNum:word;lData:integer):integer;stdcall;

implementation

{$R *.DFM}

{$R icon.res}

//处理各种消息

Function CPlApplet(hwndCPl:HWND; uMsg:word;lParam1:Longint; lParam2:Longint):Longint ;stdcall;

begin

case uMsg of

CPL_DBLCLK:

OnDblclk(hwndCPl, lParam1, lParam2);

CPL_EXIT:

result:=0;

CPL_GETCOUNT:

result:=1;

CPL_INIT:

result:=1;

CPL_NEWINQUIRE:

OnInquire(lParam1, PNEWCPLINFO(lParam2));

CPL_INQUIRE:

result:= 0; // not handled

CPL_SELECT:

result:=1;

CPL_STOP:

result:=1;

else

result:=0;

end;

result:=1;

end;

//填充NEWCPLINFO结构。

function OnInquire(uAppNum:word; pInfo:PNEWCPLINFO):integer;stdcall;

begin

with pInfo^ do

begin

dwSize:=sizeof(NEWCPLINFO);

dwFlags:=0;

dwHelpContext := 0;

lData := 0;

hIcon:=loadicon(hinstance,'I1');

szName:='MyDemo';

szInfo:='MyDemo 系统设置';

szHelpFile:='';

end;

result:=0;

end;

//显示对话框

function OnDblclk(hwndCPl:HWND;uAppNum:word;lData:integer):integer;stdcall;

var

f_main:TF_main;

begin

f_main:=TF_main.Create(application);

f_main.ShowModal;

result:=0;

end;

//将port的值从注册表中读出,写到Edit edPort中。

procedure Tf_main.FormCreate(Sender: TObject);

var

port:integer;

begin

aa:=ticon.Create;

aa.Handle :=loadicon(hinstance ,'I1');

if(aa.Handle =0) then showmessage('error icon');

icon:=aa;

RegF:=TRegistry.Create;

RegF.RootKey:=HKEY_LOCAL_MACHINE;

RegF.OpenKey('SOFTWARE/Silicon/papers',True);

Port:=0;

if regF.ValueExists ('port')=true then

port:=RegF.ReadInteger('port');

edPort.Text :=inttostr(port);

RegF.CloseKey;

RegF.Free ;

end;

//将port的值写回注册表

procedure Tf_main.btnOkClick(Sender: TObject);

begin

RegF:=TRegistry.Create;

RegF.RootKey:=HKEY_LOCAL_MACHINE;

RegF.OpenKey('SOFTWARE/Silicon/papers',True);

RegF.WriteInteger('port', strtoint(edPort.text));

RegF.CloseKey;

RegF.Free ;

end;

end.

说明:

① 其中 icon.res中包含了程序的图标,所以在程序中加入一句{$R icon.res}。

② {$E cpl}表示动态连接库的扩展名为cpl。

③ exports关键字后的表示输出的函数,只需输出CplApplet即可。

3.控制面板程序的安装:

  在Delphi中选择project|bulid mycpl编译程序。Mycpl是该示例程序的名字。然后将mycpl.cpl拷贝到Windows目录下的System目录下即可(在Windows NT 下是System32)。然后选择|开始|设置控制面板即可看到结果。

  双击MyDemo,将显示对话框:

该程序在Windows 95,Windows 98,Windows NT4.0下已测试通过。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息