控制面板的小应用程序东北大学 张春明 张春丽 姜绍飞 |
01-4-23 上午 11:35:13 |
在Windows操作系统中,控制面板中的“显示”、“系统”、“网络”、“字体”、“键盘”和“鼠标”等操作选项都是各自独立的应用程序,它们分别对应于Windows/System文件夹下扩展名为CPL的特殊动态链接库程序。我们称这些程序为控制面板小应用程序(Control Panel Applet),它们为用户设置软、硬件提供了许多方便。其实,这些控制面板小应用程序的编程并不复杂,我们完全可以自己编写。本文以Delphi语言为例,介绍如何自己编写控制面板小应用程序。 |
虽然我们可以直接创建一个扩展名为CPL的DLL动态链接库工程,但由于DLL工程调试起来相当麻烦,因此笔者建议首先创建一个EXE标准应用程序工程,然后当程序调试无误后再将其转换为控制面板小应用程序。 |
步骤一: |
将工程文件首行的program改为library,即把“program mycpl;”语句改为: |
library mycpl; |
步骤二: |
将工程文件中begin到end之间的所有程序代码(包括创建窗体以及运行应用程序等代码)移至一个自己创建的子程序中。 |
procedure RunApp; |
begin |
Application.Initialize; |
Application.CreateForm(TForm1, Form1); |
Application.Run; |
end; |
这样,就可以在CPL工程中随时调用该子程序,来实现应用程序原有的全部功能。 |
注意:上述方法比较适合于编写CPL,但不适合用于编写普通的DLL,因为在关闭DLL主窗口的同时,也将自动退出调用该DLL的应用程序。 |
步骤三: |
在工程文件的uses语句中加入对Windows和CPL两个单元的引用。 |
步骤四: |
在工程文件中加入{$E cpl}语句,即把动态链接库文件的扩展名设置为CPL。然后将Project Options对话框中Output Directory一项设置为Windows/system。这样一来,Delphi会自动将编译生成的CPL文件拷贝到Windows/System文件夹下。 |
步骤五: |
编写一个名为CPLApplet的标准回调函数,作为CPL文件的入口函数。控制面板程序(即CONTROL.EXE)通过向该入口函数发送消息来与小应用程序对话。如,发送CPL_INIT消息来确定该CPL文件是否是小应用程序;发送CPL_GETCOUNT消息来确定该CPL文件包含多少个小应用程序(注:每个CPL文件可以包含多个小应用程序)等等。 |
下面是在CPL.PAS单元文件中被声明且可以由CPLApplet回调函数处理的所有消息的说明。 |
1.CPL_DYNAMIC_RES消息(值为0) |
控制面板程序通过CPLInfo数据结构的idIcon, idName或idInfo字段来获得资源ID,并将对应的资源存储到一个缓冲区,以后就直接从缓冲区中读取,而不再从资源中读取。而CPL_DYNAMIC_RES消息用于通知控制面板程序不要缓存上述资源,即每次都必须重新读取资源。这样一来,小应用程序就可以动态实时地改变图标说明等信息,常用于显示设备当前的状态等场合。但这种方法比从缓冲区中读取资源的速度要慢得多。 |
2.CPL_INIT消息(值为1) |
控制面板程序向小应用程序发送该消息,以确定它是否为小应用程序。若返回TRUE,则表明它是小应用程序,然后可以继续向它发送其他消息,否则立即终止发送消息。 |
3.CPL_GETCOUNT消息(值为2) |
控制面板程序向小应用程序发送该消息,以返回该CPL包含的小应用程序数目,即显示在控制面板窗口中的图标数目。 |
4.CPL_INQUIRE消息(值为3) |
控制面板程序向小应用程序发送该消息,以获得每个小应用程序的信息。其中lParam1为小应用程序编号(起始编号为0),lParam2参数为指向CPLInfo数据结构的远指针。在CPL_Info结构的idIcon, idName, idInfo和lData字段中分别填充待显示的图标、名称、说明和自定义数据的资源标识符。 |
5.CPL_SELECT消息(值为4) |
当用户单击小应用程序图标时向小应用程序发送该消息。lParam1参数为对应的小应用程序编号,lParam2参数指向自定义的lData。 |
6.CPL_DBLCLK消息(值为5) |
当用户双击小应用程序图标时向小应用程序发送该消息。lParam1参数为对应的小应用程序编号,lParam2参数指向自定义的lData。小应用程序可以打开一个对话框作为响应。 |
7.CPL_STOP消息(值为6) |
控制面板程序在结束运行之前向每个小应用程序发送该消息。其中lParam1参数为小应用程序编号,lParam2参数指向lData。与小应用程序相关的清理工作必须在这个期间内完成。 |
8.CPL_EXIT消息(值为7) |
控制面板程序在调用FreeLibrary函数之前向小应用程序发送该消息。此时可以做一些与小应用程序无关的清理工作。 |
9.CPL_NEWINQUIRE消息(值为8) |
该消息与CPL_INQUIRE消息类似。区别在于lParam2参数指向一个NewCPLInfo数据结构。若应用程序响应了该消息,则控制面板程序将不再发送CPL_INQUIRE消息。 |
10.CPL_STARTWPARMS消息(值为9) |
当通过RUNDLL命令启动小应用程序时发送该消息,且可以包含很多附加指令。其中lParam1参数为小应用程序编号,lParam2参数为指向附加指令字符串的一个长指针。若消息被处理,则返回TRUE,否则返回FALSE。与CPL_DBLCLK消息一样,小应用程序此时可以打开一个对话框作为响应。 |
11.CPL_SETUP消息(值为200) |
该消息供控制面板程序内部使用。仅在系统安装过程中从命令行启动时才发送该消息。 |
综上所述,CPLApplet回调函数看似复杂,实则不然。下面是一个典型例子的代码: |
function CPLApplet(hwndCPl: THandle; uMsg: |
DWORD;lParam1, lParam2: LongInt): LongInt; stdcall; |
var |
NewCPLInfo: PNewCPLInfo; |
begin |
{ 设置默认的返回值 } |
Result:=0; |
case uMsg of |
{控制面板程序发送该消息进行初始化。若返回1,则表示为一个小应用程序 } |
CPL_INIT: |
Result := 1; |
{控制面板程序发送该消息来获得该CPL文件包含的小应用程序的数目 } |
CPL_GETCOUNT: |
Result := 1; |
{控制面板程序对每个小应用程序均发送该消息,以显示图标、名称和说明 } |
CPL_NEWINQUIRE: |
begin |
NewCPLInfo := PNewCPLInfo(lParam2); |
with NewCPLInfo^ do |
begin |
{ 设置数据结构的大小(以字节计) } |
dwSize := SizeOf(TNewCPLInfo); |
{ 设置标志位 } |
dwFlags := 0; |
{ 设置帮助上下文 } |
dwHelpContext := 0; |
{ 设置用户自定义数据指针 } |
lData := 0; |
{ 设置小应用程序的图标} |
hIcon:=LoadIcon(hInstance,‘MAINICON’); |
{ 设置显示在图标下面的小应用程序名称 } |
szName :=‘我的小应用’; |
{ 设置显示在控制面板窗口状态栏的文字 } |
szInfo := ‘小应用程序测试’; |
{ 设置帮助文件 } |
szHelpFile :=‘’; |
end; |
end; |
{ 当用户双击小应用程序图标时发送该消息,编程者可以自行确定要执行的代码 } |
CPL_DBLCLK: |
begin |
RunApp; |
end; |
end; |
end; |
对于32位应用程序而言,CPLApplet函数后面不必加export编译指令。 |
步骤六: |
在工程文件的exports语句中输出CPLApplet回调函数。 |
exports |
CPLApplet; |
begin |
end; |
通过以上6步,即可实现一个控制面板小应用程序的设计。 |