Comctl32公共控件
2024-03-17 17:33:41

Comctl32 是什么?

Comctl的全称是Common Controls,也就是公共控件的意思,属于Windows系统的一部分,提供了一组标准的UI控件,如ButtonListView等等。
微软工具 Control Spy 用于查看所有公共控件。

Comctl32 版本

v5和v6的区别

主要有两个大版本,v5v6,最明显的两个区别:

  1. 外观,一个是古老的Windows 98风格,一个是跟随系统的风格。
    5.X的控件样式,是固定的样式。

    6.X的控件样式,会随着系统主题变化。
  2. 兼容性,6.0以后的某些控件对多字节字符集的应用存在兼容性问题。

获取正在使用的 Comctl32 版本号

Comctl32.dll有一个导出函数DllGetVersion可以获取当前版本号。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
DWORD GetVersion(HMODULE h)
{
DWORD dwVersion = 0;
auto pDllGetVersion = reinterpret_cast<DLLGETVERSIONPROC>(GetProcAddress(h, "DllGetVersion"));
if (pDllGetVersion) {
DLLVERSIONINFO dvi{};
dvi.cbSize = sizeof(dvi);
HRESULT hr = (*pDllGetVersion)(&dvi);
if (SUCCEEDED(hr)) {
dwVersion = MAKELONG(dvi.dwMajorVersion, dvi.dwMinorVersion);
}
}
return dwVersion;
}

DWORD dwVer = GetVersion(GetModuleHandleA("ComCtl32.dll"));

Windows XP SP3上得到的值是0x00050052,意味版本号是5.82

链接指定的 Comctl32 版本

在新建一个 MFC 工程时,默认会生成这样一段代码:

1
2
3
4
5
6
7
8
9
#ifdef _UNICODE
#if defined _M_IX86
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_X64
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#else
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#endif
#endif

通过编译器指令添加了清单文件以支持链接到指定的 Comctl32 版本。注意这里判断了程序使用 Unicode 字符集时才会生效,原因上面说过了,因为v6多字节字符集存在兼容性问题,所以不建议使用,多字节字符集的程序最好用v5,不过这意味着程序无法使用现代的UI。

当程序指定链接到v6或更高版本后,还需要在程序内定义一个宏_WIN32_IE,如果没有定义它,编译时会将这个值设置为0x500,这将影响程序正在使用的与控件有关的结构体大小。
试想一下,如果程序链接到v6版的 Comctl32,但因为没有定义_WIN32_IE宏而使用了较旧的SDK,这可能会引起程序异常。
_WIN32_IE所有支持的值看这里:https://docs.microsoft.com/en-us/windows/win32/controls/common-control-versions#project-versions

Windows XP SP3已经自带了v6版,所以我们可以放心的将程序链接到v6版本。

InitCommonControlsEx

在新建一个 MFC 工程时,初始化的第一行代码就是对公共控件初始化

1
2
3
4
INITCOMMONCONTROLSEX InitCtrls;
InitCtrls.dwSize = sizeof(InitCtrls);
InitCtrls.dwICC = ICC_WIN95_CLASSES;
InitCommonControlsEx(&InitCtrls);

但在今天,初始化行为并不是必须的,因为在首次创建控件时,Comctl32 内部会自动注册相关控件类,历史原因可以看文章末尾的链接。

参考

关于公共控件
InitCommonControlsEx
Is common control 6 supported in MBCS applications?
CEdit works in ComCtrl32 Version 5.82 but not with 6.10