代码改变世界

Windows Mobile控制面板程序

  王克伟  阅读(3919)  评论(12编辑  收藏  举报

什么是控制面板程序?看到下图就一目了然了。控制面板应用程序是一个以cpl为后缀的文件,其实是个dll文件(把项目生成的dll文件后缀改为cpl,或者从VS中修改配置直接生产cpl文件)。部署控制面板程序非常简单,直接把生产的cpl文件Copy到手机的Windows目录下即可。当你点击自己编写的控制面板程序的图标时,ctlpnl.exe进程会加载Windows目录下对应的cpl文件。

clip_image002clip_image002[5]clip_image002[8]

clip_image002[1]clip_image002[3]

其实系统自带的一些控制面板程序被集成在cplmain.cpl中(但是像无线管理器等并不是cpl文件,而是一个exe程序,这个可以从注册表中找到设置,微软这么设计的原因是因为无线管理器在很多地方都是需要的。),所以如果你需要在你的程序中打开这些面板的话会经常看到如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
SHELLEXECUTEINFO info;
TCHAR szControlPanelCmdLine[ 200 ];
swprintf( szControlPanelCmdLine, L\\windows\\cplmain.cpl,5);  //参数5代表调用about
info.cbSize = sizeof( info );
info.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI;
info.lpVerb = NULL;
info.lpFile = TEXT("ctlpnl.exe");
info.lpParameters = szControlPanelCmdLine;
info.lpDirectory = NULL;
info.nShow = SW_SHOW;
info.hInstApp = NULL;
ShellExecuteEx( &info );

以下是更多对应关系:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ctlpnl.exe cplmain.cpl,1 - set password
ctlpnl.exe cplmain.cpl,2 - set ownerinfo
ctlpnl.exe cplmain.cpl,3 - battery status
ctlpnl.exe cplmain.cpl,4 - memory status
ctlpnl.exe cplmain.cpl,5 - about
ctlpnl.exe cplmain.cpl,7 - align
ctlpnl.exe cplmain.cpl,8 - keyboard settings
ctlpnl.exe cplmain.cpl,9 - sound
ctlpnl.exe cplmain.cpl,10 - remove programs
ctlpnl.exe cplmain.cpl,11 - start menu
ctlpnl.exe cplmain.cpl,12 - button assignments
ctlpnl.exe cplmain.cpl,13 - today screen
ctlpnl.exe cplmain.cpl,15 - beam settings
ctlpnl.exe cplmain.cpl,16 - clock
ctlpnl.exe cplmain.cpl,17 - network adapters
ctlpnl.exe cplmain.cpl,18 - regional settings
ctlpnl.exe cplmain.cpl,19 - connections
ctlpnl.exe cplmain.cpl,20 - phone settings
ctlpnl.exe cplmain.cpl,22 - manage certificates
ctlpnl.exe cplmain.cpl,23 – bluetooth

言归正传开始介绍cpl的编写

cpl文件中的回调函数CPlApplet为ctlpnl.exe进程进入你的cpl的入口点(需要导出,不管你在def文件里面,还是在函数前制定dllexport属性),一个cpl可以支持多个applets,见下面的代码中的注释。

1
2
3
4
5
6
LONG CPlApplet(
  HWND hwndCPl,  //Handle to the main window of the controlling application.
  UINT msg,  //Message being sent to the Control Panel application.
  LPARAM lParam1,
  LPARAM lParam2
);

msg有:

CPL_INIT
初始化,控制面板应用程序此时做一些全局的初始化工作,如内存分配。

CPL_GETCOUNT
获取控制面板应用程序支持的dialog boxes个数。

CPL_NEWINQUIRE
查询控制面板应用程序的dialog boxes的信息,信息包含在lParam2参数中,使用(LPNEWCPLINFO) lParam2获得指针。

1
2
3
4
5
6
7
8
9
10
typedef struct tagNEWCPLINFO {
  DWORD dwSize;
  DWORD dwFlags;
  DWORD dwHelpContext;
  LONG lData;
  HICON hIcon;  //Handle to the icon that represents the dialog box. 
  TCHAR szName[32]; //The name is intended to be displayed below the icon.
  TCHAR szInfo[64]; //The description is intended to be displayed when the icon for the dialog                      box is selected.
  TCHAR szHelpFile[128]; //忽略。要想使用帮助,处理WM_NOTIFY消息,然后取得“lppsn = (LPPSHNOTIFY) lParam;”判断是否等于PSN_HELP,如果是即可调出帮助文档。
} NEWCPLINFO;

CPL_IDNAME
获得控制面板应用程序的名称,通过设置注册表键值[HKEY_LOCAL_MACHINE\ControlPanel\<ID name>]可以改变应用位于控制面板属性页的位置,主键值"Group"默认为dword类型1,也就是说当你不指定位置时,默认放在系统这个tab中。另外还有如下值可以选择:

1
2
3
0                    Personal
1 (default value)    System
2                    Connections

CPL_DBLCLK
当用户双击控制面板上的icon时,系统会发送这个消息给你的控制面部应用程序,此时你可以弹出一个dialog box。处理完这个消息之后返回0表示你成功处理这个消息了(其它消息也一样),非0表示其它。

CPL_STOP
关闭控制面部应用程序之前那一刻发送这个消息给你的控制面板应用程序。

CPL_EXIT
释放DLL文件之前那一刻发送这个消息给你的控制面板应用程序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
////////////////////////////////////////////////////////
//    This is the entry point called by ctlpnl.exe
// 
////////////////////////////////////////////////////////
extern "C"
__declspec(dllexport)
LONG WINAPI CPlApplet(HWND hwndCPL, UINT uMsg, LONG lParam1, LONG lParam2)
{
    static int        iInitCount = 0;
    int                iApplet;
 
    switch (uMsg)
    {
        // First message sent. It is sent only once to
        // allow the dll to initialize it's applet(s)
        case CPL_INIT:
            if (!iInitCount)
            {
                if (!InitApplet(hwndCPL))
                    return FALSE;
            }
            iInitCount++;
            return TRUE;
             
        // Second message sent. Return the count of applets supported
        // by this dll
        case CPL_GETCOUNT:
            // Return the number of applets we support
            return (LONG)((sizeof(SystemApplets))/(sizeof(SystemApplets[0])));
 
        // Third message sent. Sent once for each applet supported by this dll.
        // The lParam1 contains the number that indicates which applet this is
        // for, from 0 to 1 less than the count of applets.
        // lParam2 is a NEWCPLINFO that should be filled with information about
        // this applet before returning
        case CPL_NEWINQUIRE:
            {
                LPNEWCPLINFO    lpNewCPlInfo;
 
                lpNewCPlInfo = (LPNEWCPLINFO)lParam2;
                iApplet = (int)lParam1;
                lpNewCPlInfo->dwSize = (DWORD)sizeof(NEWCPLINFO);
                lpNewCPlInfo->dwFlags = 0;
                lpNewCPlInfo->dwHelpContext    = 0;
                lpNewCPlInfo->lData = SystemApplets[iApplet].icon;
                lpNewCPlInfo->hIcon = LoadIcon(g_hInstance, (LPCTSTR)MAKEINTRESOURCE(SystemApplets[iApplet].icon));
                lpNewCPlInfo->szHelpFile[0] = '\0';
 
                LoadString(g_hInstance,SystemApplets[iApplet].namestring, lpNewCPlInfo->szName,32);
                LoadString(g_hInstance,SystemApplets[iApplet].descstring, lpNewCPlInfo->szInfo,64);
            }
 
            break;
 
        // This is sent whenever the user clicks an icon in Settings for one of
        // the applets supported by this dll. lParam1 contains the number indicating
        // which applet. Return 0 if applet successfully launched, non-zero otherwise
        case CPL_DBLCLK:
            iApplet = (UINT)lParam1;
            if (!CreatePropertySheet(hwndCPL,iApplet))
                return 1;
            break;
             
        // Sent once per applet, before CPL_EXIT
        case CPL_STOP:
            break;
             
        // Sent once before the dll is unloaded
        case CPL_EXIT:
            iInitCount--;
            if (!iInitCount)
                TermApplet();
            break;
             
        default:
            break;
    }
 
    return 0;
}

更详细的代码请见例子\Samples\PocketPC\CPP\win32\myBackLight,或者点这里下载。

关于任何调试cpl代码,请参照下面的文章。

编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示