已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也

DLL版本的一些细节

下面这个文章介绍了一些没有被微软写进文档里的细节,但是最好选择性地参考,不要依赖一些微软没有写进文档的做法,可能会降低程序的兼容性。

XXXXXXXXXXXXXXXXXXXXXXXXXXXX/studies/windows/shell/comctl32/

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/murrays/2006/10/13/richedit-versions/

comctl32.dll版本的区别

传统版本:

  • v4.0是Win95附带的,支持SysListView32,SysHeader32,SysTreeView32,SysTabControl32,ToolbarWindow32,msctls_statusbar32,msctls_trackbar32,msctls_updown32,msctls_progress32,msctls_hotkey32,SysAnimate32,tooltips_class32共12个控件(用于WinNT的v4.0版本非常少见,主要是IE3.00 for NT附带的版本,并且功能上介于v4.0和v4.70之间,可以忽略)
  • v4.70是Win95OSR2和WinNT4附带的,但可以在Win95随IE3.01-3.02装上,增加了ComboBoxEx32,ReBarWindow32,SysMonthCal32,SysDateTimePick32共4个控件,现有控件进行了升级
  • v4.71可以在之前的系统随IE4.0装上,增加了SysIPAddress32,SysPager,NativeFontCtl共3个控件,现有控件进行了升级
  • v4.72是Win98附带的,但可以在之前的系统随IE4.01装上,现有控件进行了升级
  • v5.80是Win98SE附带的,但可以在之前的系统随IE5.0装上,现有控件进行了升级
  • v5.81是Win2000,WinMe附带的,但可以在之前的系统随IE5.01,5.5,6.0装上,现有控件进行了升级
  • v5.82是WinXP附带的,不能装在以前的系统上,不再需要InitCommonControlsEx,现有控件进行了升级

需要manifest的版本:

  • v6.0是WinXP附带的,不能装在以前的系统上,需要manifest,改为使用uxtheme.dll而不是纯GDI渲染,不再需要InitCommonControlsEx,增加了SysLink控件,现有控件增加了一些功能,增强了预定义控件的功能
  • v6.10是WinVista附带的,不能装在以前的系统上,需要manifest,在v6.0的基础上继续增加了一些功能

关于SetWindowSubclass等函数

comctl32.dll中包含有SetWindowSubclass,GetWindowSubclass,RemoveWindowSubclass,DefSubclassProc四个函数,可以实现可拆卸的窗口过程替换。

  • v6.0按名称导出了全部的四个函数。
  • v5.82sp1按名称导出了除GetWindowSubclass以外的三个函数,GetWindowSubclass按照序号411导出。
  • v4.72-v5.82rtm均只按序号导出,没有按名称导出,序号依次是410,411,412,413。

不过个人并不推荐按序号使用这四个函数,因为微软并没有把这四个函数的序号写进文档里。推荐的做法:

  • 如果需要使用全部四个函数,必须确保函数是WinXP+,并且使用manifest启用comctl32.dll v6.0。
  • 如果需要使用除GetWindowSubclass以外的三个函数,但只使用comctl32.dll v5.82,必须确保系统是WinXPSP1+。
  • 不满足以上条件,应使用GetWindowLongPtr/SetWindowLongPtr,GWLP_WNDPROC和CallWindowProc实现窗口过程替换,这种窗口过程替换是不可拆卸的,因为拆卸可能会导致调用链失效。

riched20.dll v2.0和v3.0的区别

Win98/98SE/NT4自带的riched20.dll版本号是v2.0(文件版本v5.0),功能不全,不过我们可以用instmsia.exe和instmsiw.exe将其更新成v3.0(文件版本v5.30)。Win2000/Me/XP/2003的riched20.dll是v3.0,WinVista以上的riched20.dll是v3.1(文件版本v5.31)。

v2.0和v3.0下载:


attachment icon riched20_v2.rar 152.44KB RAR 32次下载
attachment icon instmsiaw_riched20v3.rar 3.30MB RAR 31次下载

一般来说,应该总是认为riched20.dll是v3.0版本,并使用"RichEdit20A"和"RichEdit20W"。除此之外,也可以使用WinXPSP1附带的msftedit.dll(v4.1,"RichEdit50W")。虽然Office 2003/2007/2010里边的riched20.dll版本更高,但是没有官方文档,用起来问题比较多。

判断DLL版本的方法

comctl32.dll导出了一个叫做DllGetVersion的函数,可以获取DLL版本。不过它没有被放到XXXXXXXXXXXb中,因为还有shell32.dll和shlwapi.dll也导出了这个函数。因此需要使用GetProcAddress调用它。它的原型在shlwapi.h头文件中定义为DLLGETVERSIONPROC。

不过由于像riched20.dll之类的大多数DLL都没有导出DllGetVersion函数,因此个人建议通过读取RT_VERSION资源的方式判断DLL文件版本号,这种方法才是最通用的方法。

这里要注意的是,riched20.dll版本v2.0的实际文件版本号是v5.0,而riched20.dll版本v3.0的实际文件版本号是v5.30。

<code class="language-cpp">#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <shlwapi.h>
#include <tchar.h>
//#include <strsafe.h>
#include <stdio.h>
#include <stdlib.h>
#pragma comment(lib, "comctl32.lib")
#pragma comment(lib, "version.lib")

BOOL CALLBACK DlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

BOOL CheckModuleFileVersion(LPCTSTR modname, WORD major, WORD minor, WORD build, WORD rev)
{
	HMODULE hmod = GetModuleHandle(modname);
	if (!hmod)
		return FALSE;
	LPVOID verblock = LockResource(LoadResource(hmod, FindResource(hmod, MAKEINTRESOURCE(1), MAKEINTRESOURCE(RT_VERSION))));
	if (!verblock)
		return FALSE;
	VS_FIXEDFILEINFO *pvsffi = NULL;
	UINT szvsffi = 0;
	if (!VerQueryValue(verblock, _T("\\"), (LPVOID*)&pvsffi, &szvsffi))
		return FALSE;
	ULONGLONG ullFileVersion = ((ULONGLONG)pvsffi->dwFileVersionMS << 32) + pvsffi->dwFileVersionLS;
	ULONGLONG ullReqVersion = ((ULONGLONG)major << 48) + ((ULONGLONG)minor << 32) + ((ULONGLONG)build << 16) + rev;
	if (ullFileVersion < ullReqVersion)
		return FALSE;
	return TRUE;
}

BOOL CheckModuleProductVersion(LPCTSTR modname, WORD major, WORD minor, WORD build, WORD rev)
{
	HMODULE hmod = GetModuleHandle(modname);
	if (!hmod)
		return FALSE;
	LPVOID verblock = LockResource(LoadResource(hmod, FindResource(hmod, MAKEINTRESOURCE(1), MAKEINTRESOURCE(RT_VERSION))));
	if (!verblock)
		return FALSE;
	VS_FIXEDFILEINFO *pvsffi = NULL;
	UINT szvsffi = 0;
	if (!VerQueryValue(verblock, _T("\\"), (LPVOID*)&pvsffi, &szvsffi))
		return FALSE;
	ULONGLONG ullProductVersion = ((ULONGLONG)pvsffi->dwProductVersionMS << 32) + pvsffi->dwProductVersionLS;
	ULONGLONG ullReqVersion = ((ULONGLONG)major << 48) + ((ULONGLONG)minor << 32) + ((ULONGLONG)build << 16) + rev;
	if (ullProductVersion < ullReqVersion)
		return FALSE;
	return TRUE;
}

void NoSupportedDllExit()
{
	MessageBox(NULL, _T("此操作系统需要安装Internet Explorer 5.01和Windows Installer 1.0或以上版本的相应组件以运行此程序。"), _T("错误"), MB_ICONERROR);
	exit(1);
}

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, _TCHAR *szCmdLine, int nShowCmd)
{
	// 检查系统支持
#ifdef UNICODE
	if (!CheckModuleProductVersion(_T("kernel32.dll"), 5, 0, 0, 0))
#else
	if (!CheckModuleProductVersion(_T("kernel32.dll"), 4, 10, 0, 0))
#endif
	{
		MessageBox(NULL, _T("此操作系统不受支持。"), _T("错误"), MB_ICONERROR);
		exit(1);
	}
	// comctl32.dll v4.70-5.81 compatible
	HMODULE hcomctl32 = LoadLibrary(TEXT("comctl32.dll"));
	INITCOMMONCONTROLSEX icc = { sizeof icc };
	typedef BOOL(WINAPI*TInitCommonControlsEx)(LPINITCOMMONCONTROLSEX);
	TInitCommonControlsEx pInitCommonControlsEx = NULL;
	if (hcomctl32)
		pInitCommonControlsEx = (TInitCommonControlsEx)GetProcAddress(hcomctl32, "InitCommonControlsEx");
	if (pInitCommonControlsEx)
		for (int i = 0; i < 16; i++)
			icc.dwICC = 1 << i, pInitCommonControlsEx(&icc);
	// riched20.dll
	LoadLibrary(TEXT("riched20.dll"));
	// 要求comctl32.dll版本v5.81和riched20.dll版本v3.0(实际文件版本v5.30)
	if (!CheckModuleFileVersion(_T("comctl32.dll"), 5, 81, 0, 0) || !CheckModuleFileVersion(_T("riched20.dll"), 5, 30, 0, 0))
		NoSupportedDllExit();
	DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc, NULL);
	return 0;
}
</stdlib.h></stdio.h></strsafe.h></tchar.h></shlwapi.h></commctrl.h></windowsx.h></windows.h></code>
文号 / 833126

千古风流
名片发私信
学术分 4
总主题 466 帖总回复 2942 楼拥有证书:进士 学者 笔友
注册于 2009-05-30 21:22最后登录 2019-01-31 17:16
主体类型:个人
所属领域:无
认证方式:邮箱
IP归属地:未同步

个人简介

暂未填写
文件下载
加载中...
{{errorInfo}}
{{downloadWarning}}
你在 {{downloadTime}} 下载过当前文件。
文件名称:{{resource.defaultFile.name}}
下载次数:{{resource.hits}}
上传用户:{{uploader.username}}
所需积分:{{costScores}},{{holdScores}}下载当前附件免费{{description}}
积分不足,去充值
文件已丢失

当前账号的附件下载数量限制如下:
时段 个数
{{f.startingTime}}点 - {{f.endTime}}点 {{f.fileCount}}
视频暂不能访问,请登录试试
仅供内部学术交流或培训使用,请先保存到本地。本内容不代表科创观点,未经原作者同意,请勿转载。
音频暂不能访问,请登录试试
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

插入资源
全部
图片
视频
音频
附件
全部
未使用
已使用
正在上传
空空如也~
上传中..{{f.progress}}%
处理中..
上传失败,点击重试
等待中...
{{f.name}}
空空如也~
(视频){{r.oname}}
{{selectedResourcesId.indexOf(r.rid) + 1}}
处理中..
处理失败
插入表情
我的表情
共享表情
Emoji
上传
注意事项
最大尺寸100px,超过会被压缩。为保证效果,建议上传前自行处理。
建议上传自己DIY的表情,严禁上传侵权内容。
点击重试等待上传{{s.progress}}%处理中...已上传,正在处理中
空空如也~
处理中...
处理失败
加载中...
草稿箱
加载中...
此处只插入正文,如果要使用草稿中的其余内容,请点击继续创作。
{{fromNow(d.toc)}}
{{getDraftInfo(d)}}
标题:{{d.t}}
内容:{{d.c}}
继续创作
删除插入插入
插入公式
评论控制
加载中...
文号:{{pid}}
加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}
ID: {{user.uid}}