大家应该都非常熟悉控制面板吧,大家也都有操作过控制面板吧,但如何使用Delphi对控制面板进行编程呢?
一、控制面板的原理
下面我就来讲讲控制面板的原理:控制面板在windows中的system目录下,其中所有以CPL为扩展名的,就都是我们的控制面板。要想对控制面板进行编程,就要对CPlApplet这个函数非常熟悉,它是构成CPL文件的核心,原型如下:
function CPlApptet(
hwndCPL:HWND;
uMsg:UINT;
lParam1:LPARAM;
lParam2:LPARAM
):LongInt;stdcall;
参数说明:
hwndCPL:激活控制面板组件的应用程序窗口handle。
uMsg:由外界传入的控制消息。
lParam1:根据消息种类而定的参数1。
lParam2:根据消息种类而定的参数2。
返回值:根据消息种类而定。
当我们想编程激活某个CPL文件时,就会加载此CPL文件,取得CPlApplet函数地址然后调用它。而CPlApplet函数的任务是,根据uMsg消息参数得知外界的请求并做出适当响应。可以传入的消息种类如下表所示:
CPL_INIT CPL文件加载后 供CPL文件有机会进行各控制面板组件的数据结构、变量及配置内存等初始化及前置工作
CPL_GETCOUNT 紧接在CPL_INIT消息后 取得CPL文件提供的控制面板组件数目
CPL_INQUIRE 紧接在CPL_GETCOUNT消息后 取得个别控制面板的信息
CPL_NEWINQUIRE 紧接在CPL_INQUIRE消息后 取得个别控制面板的信息,作用与消息CPL_INQUIRE相同,但应用场合不同,组件通常只须选择二者之一支持即可
CPL_DBLCLK 激活个别组件前 激活某一控制面板组件,通常的响应都是显示Modal对话框供用户设置
CPL_STOP 激活个别组件后 激活中的控制面板组件关闭后,控制面板程序会送出此消息进行个别组件的善后工作
CPL_EXIT 释放CPL文件前 控制面板程序要释放此CPL文件前会送出此消息,提供资源释放或其它善后工作的机会
二、CPlApplet函数的详解
现在我就来讲讲,以上列表中各个消息的详细作用:
1、CPL_INIT:lParam1、lParam2:均未使用。返回值:成功返回非零值;失败返回零。
CPL程序第一个收到的消息一定是CPL_INIT,这时我们可以利用此机会初始化所有控制面板组件共享的数据结构及变量。若初始化失败,返回零,这会使得控制面板不继续传送其它消息给此CPL文件,而这个CPL包含的控制面板的组件就不会出现在控制面板内。
2、CPL_GETCOUNT:lParam1、lParam2:均未使用。返回值:返回此CPL文件所支持的控制面板组件数目。
继CPL_INIT消息后,紧接着会收到CPL_GETCOUNT消息,此时必须返回CPL文件所支持的控制面板组件数目。
3、CPL_INQUIRE:lParam1:组件编号,值为0~(CPL_GETCOUNT返回数目-1)。lParam2:指向TCPLInfo结构的指针。返回值:成功返回零,失败返回非零。
CPL_INQUIRE是编程中最重要的消息,控制面板就是利用这个消息来取得每个组件的确良名称、描述及图标。参数一传入组件编号,我们必须根据组件编号将对应的组件信息填入参数2指向的TCPLInfo结构中。
TCPLInfo结构定义如下:
TCPLInfo=pccked record
idIcon:integer;//指向组件图标
idName:integer;//指向组件名称
idInfo:integer;//指向组件描述CPL_DBLCLKCPL_STOP
lData:Longint;//用户自定义参数
end;
idIcon、idName、idInfo这三个字段是存放组件图标、名称、描述的,我们要调用LoadString及LoadIcon API函数,从CPL文件中取得实际字符串及图标的。
lData字段的类型为Longint,长度为4个字节的无符号整数,不过也可改为指针变量来使用,lData中的值会在控制面板程序下次传送CPL_DBLCLK、CPL_STOP消息时由lParam2参数返回供组件使用,你可以自由决定它的功能。
4、CPL_NEWINQUIRE:lParam1:组件编号,值为0~(CPL_GETCOUNT返回数目-1)。lParam2:指向TNewCPLInfo结构的指针。返回值:成功返回零,失败返回非零。TNewCPLInfo结构比TCPLInfo结构稍微复杂,定义如下:
TNewCPLInfo=pccked record
dwSize:DWORD;//结构占用长度
dwFlags:DWORD;//目前未使用
dwHelpContext:DWORD;//说明页编号,目前未使用
lData:Longint;//用户自定义参数
hIcon:HICON;//组件图示
szName:array[0..31] of char;//组件名称
szInfo:array[0..63] of char;
szHelpFile:array[0..127] of char;//说明文件名,目前未使用
end;
szName、szInfo 、hIcon、lData这4个字段与上一个CPLInfo结构中对应的4个字段作用完全相同,只不过szName、szInfo 、hIcon字段变成为字符串及HICN类型了。这使得CPL程序可以动态地根据情况来产生及返回组件的名称、描述及图标。
5、CPL_DBLCLK:lParam1:组件编号,值为0~(CPL_GETCOUNT返回数目-1)。lParam2:指向TCPLInfo或TNewCPLInfo结构的返回的lData字段值。返回值:成功返回零,失败返回非零。
当我们双击控制面板中的组件图标时,就会触发CPL_DBLCLK消息。这个就是我们用来打开控制面板,打开相应的对话框,然后来设置用的。
6、CPL_STOP:lParam1:组件编号,值为0~(CPL_GETCOUNT返回数目-1)。lParam2:指向TCPLInfo或TNewCPLInfo结构的返回的lData字段值。返回值:成功返回零,失败返回非零。
这个消息提供机会让个别组件进行善后工作,例如释放GDI或核心对象等等。如果一切无误,返回零。
7、CPL_EXIT:lParam1、lParam2:均未使用。返回值:成功返回零;失败返回非零值。就是退出啦。
好了,关于控制面板的研究,到此就告一段落了,若想对它进行深入的编程,可转入到实例中进行练习练习。三、我的控制面板的制作
大家一定用过Windows优化大师吧,它里面有个控制面板,可以把我们电脑里的控制面板都显示出来,我们经过了前面的学习,是否可以也编一个类似的程序呢?回答是肯定的。下面我们就来编个看看吧!
经过我们观察,决定用TlistView控件 。
为了美观,TlistView控件做如下设置:Checkboxes设为True;Columnclick设为False;FlatScrollBar设为True;SortType设为stText;ViewStyle设为vsReport;单击Columns,加上三个数值:项目名称、项目说明、项目作用。在USES中加入声明:CPL。
编程代码:
procedure TForm1.FormCreate(Sender: TObject);
procedure newview(ANode: TListItem);
var
hLib : THandle;
CPLProc : TCPLApplet;//指向 CPlApplet 函数的指针
iCount, I : Integer; // 用来取得控制面板的结构
cplInfo : TCPLInfo;
// 记录元件的名称、描述及图标
sName, sInfo: array[0..255] of char;
hAppIcon : hIcon;
begin
hLib := LoadLibrary(PChar(ANode.Caption));
if hLib = 0 then
begin
ANode.SubItems.Add(' - 无法加载!!');
Exit;
end;
try
CPLProc := TCPLApplet(GetProcAddress(hLib, 'CPlApplet'));
if @CPLProc = nil then Exit;
if CPLProc(Handle, CPL_INIT, 0, 0) = 0 then Exit;
iCount := CPLProc(Handle, CPL_GETCOUNT, 0, 0);
for I := 0 to iCount - 1 do
begin
FillChar(cplInfo, sizeof(TCPLInfo), 0);
CPLProc(Handle, CPL_INQUIRE, I, LongInt(@cplInfo));
LoadString(hLib, cplInfo.idName, @sName, 255);
LoadString(hLib, cplInfo.idInfo, @sInfo, 255);
hAppIcon := LoadIcon(hLib,MAKEINTRESOURCE(cplInfo.idIcon));
ANode.SubItems.Add(sName);
ANode.SubItems.Add(sInfo);
end;
CPLProc(Handle, CPL_EXIT, 0, 0);
finally
FreeLibrary(hLib);
end;
end;
var
sSysdir:array[0..255] of char;
SearchRec:TSearchRec;
J: Integer;
NewItem: TListItem;
begin
GetsystemDirectory(sSysdir,255);//取得系统目录
J:=FindFirst(sSysdir+'\*.cpl',faAnyFile,SearchRec);//开始寻找系统目录下的CPL文件
while J=0 do
begin
NewItem:=ListView1.Items.add;
NewItem.caption:=AnsiLowerCase(searchRec.name);
NewView(NewItem);//调用自定义函数NewView
J:=FindNext(searchRec);//寻找下一个CPL文件
end;
FindClose(searchRec);
end;
若想双击进行运行选中的控制面板,代码如下:
procedure TForm1.ListView1DblClick(Sender: TObject);
var
hLib : THandle;
CPLProc: TCPLApplet;
NewItem: TListItem;
cplInfo: TCPLInfo;
begin
NewItem:=ListView1.Selected;
if (not Assigned(NewItem)) then Exit;
hLib := LoadLibrary(PChar(NewItem.Caption));//加载CPL文件, CPL文件名就是项目名
if hLib = 0 then
begin
MessageDlg('无法运行' + NewItem.Caption,
mtError,[mbOK], 0);
Exit;
end;
CPLProc := TCPLApplet(GetProcAddress(hLib, 'CPlApplet'));
if @CPLProc <> nil then
begin
CPLProc(Handle, CPL_INIT, 0, 0);//运行面板
FillChar(cplInfo, sizeof(TCPLInfo), 0);
CPLProc(Handle, CPL_INQUIRE, NewItem.Index, LongInt(@cplInfo));
CPLProc(Handle, CPL_DBLCLK, NewItem.Index, cplInfo.lData);
CPLProc(Handle, CPL_STOP, NewItem.Index, cplInfo.lData);
CPLProc(Handle, CPL_EXIT, 0, 0);
end;
FreeLibrary(hLib);//释放CPL文件
end;
好了,编程完毕。程序在Windows98+Delphi5下调试通过。
如果大家不想麻烦编写这么多代码的话,可以写信向本人索取源代码,我的E-Mail:[email protected]。
本文地址:http://com.8s8s.com/it/it5734.htm