Win32标准控件有哪些
acmilan2017/04/05软件综合 IP:四川

尽管很多框架非常方便,有时候我们还是希望尽量减少程序体积和复杂度,甚至连一个*.XXXXXXnfig都不想要,这时候用C/C++调用DialogBox创建Win32对话框是最好的选项。

而为了更好地使用Win32对话框,需要学习Win32标准控件的使用。学习使用Win32标准控件的最佳途径是边练习边参考Windows SDK Documentation。

新版Windows SDK已经不带帮助文档,而Visual Studio自带的MSDN帮助文档的往往故意砍掉了最重要的User Interface\Windows User Interface一节,所以还是需要下载一份Windows SDK Documentation的。

WinSDK文档的下载可以在我的另一篇帖子里找到。

标准控件.png

日常加载代码如下:

<code class="language-cpp">#include <windows.h>
#include <tchar.h>
#include <windowsx.h>
#include <commctrl.h>
#include <commdlg.h>
#pragma comment(lib, "comctl32.lib")

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

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, _TCHAR *szCmdLine, int nShowCmd)
{
	// 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"));
	DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc, NULL);
	return 0;
}
</commdlg.h></commctrl.h></windowsx.h></tchar.h></windows.h></code>

控件之外

User Interface、Graphics and Multimedia两章与用户界面有关,应该通读这些章节。

System Services、Networking等其它章节包含了大多数非用户界面的编程,也应该尽量多地了解。但是尽量还是在读完上面两章之后进行。

winsdk.png

MFC与Win32的差别

经典MFC(MFC9.1之前的版本)除了这些控件之外,还有一些私有功能,比如静态窗口分割、动态窗口分割、浮动工具栏、ActiveX控件等。

实际上,这些东西不一定非要和MFC实现得完全一致。

工具软件用得最多的是静态分割。动态分割、浮动工具栏很少使用。

实际上,静态分割用鼠标事件代码很好实现:

  • 鼠标左键按下:捕获鼠标、显示阴影
  • 鼠标移动且按下了鼠标左键:消除旧阴影、显示新阴影
  • 鼠标左键松开:消除阴影、重新布置控件、释放鼠标捕获

至于拖动阴影,虽然有的软件也没有实现,但是它可以在拖动的时候防止闪烁,提高用户体验,还是实现一下比较好。拖动阴影的实现方法:建立一个单色位图画刷,然后用PatBlt函数对矩形区域进行PATINVERT。

<code class="language-cpp">void InvertFillFocusRect(HDC hdc, int x, int y, int cx, int cy)
{
	WORD patbits[] = { 0x80, 0x40 };
	HBITMAP hpatbmp = CreateBitmap(2, 2, 1, 1, patbits);
	HBRUSH hpatbr = CreatePatternBrush(hpatbmp);
	HGDIOBJ holdbr = SelectObject(hdc, hpatbr);
	PatBlt(hdc, x, y, cx, cy, PATINVERT);
	SelectObject(hdc, holdbr);
	DeleteObject(hpatbr);
	DeleteObject(hpatbmp);
}
</code>

ActiveX功能主要用于嵌入WebBrowser控件,但是随着IE的退出竞争,这种方法越来越不好用了。现在一般使用CEF。实际上,如果使用WebBrowser,就要同时面对IE8/9/10/11四个版本,其中IE8经常导致排版混乱,甚至莫名其妙弹出一些对话框,大大降低用户体验。

但是CEF太臃肿了。对于不准备植入广告的工具软件来说,还是尽量用基于XmlHttpRequest或WebSockets的开放应用接口。实在没有可用的开放应用接口的话,再考虑使用正则表达式等工具分析HTTP文本。

[修改于 7年7个月前 - 2017/05/17 17:08:35]

来自:计算机科学 / 软件综合
6
已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也
acmilan 作者
7年8个月前 修改于 7年8个月前 IP:四川
833121

Win32 GUI编程的入门章节

Win32编程应该从以下两章入门

User Interface\Windows User Interface

标准UI.png

Graphics and Multimedia\Windows GDI

标准绘图.png

引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan作者
7年8个月前 修改于 7年5个月前 IP:四川
833123

Win32控件的分类

这里先不讨论ImageList等控件组件、对话框等,只讨论有类型名称的Win32控件。

可以从下边的列表看出来,大部分控件的宏定义名称都是以WC_开头的,另外有8个是以_CLASS结尾的,工具栏、状态栏、ReBar则是以CLASSNAME结尾。

这些控件所需要的加载代码是不同的:

  • 预定义控件是user32.dll定义的,不需要加载其它DLL
  • 富文本框需要加载riched32.dll,riched20.dll,msftedit.dll,其中msftedit.dll需要WinXPSP1+
  • 对于WinXP以前的系统,comctl32.dll最高版本为v5.81,加载comctl32.dll之后,系统会自动使用0x00FF作参数运行InitCommonControlsEx函数注册所有Win95控件
  • 对于WinXP及以后的系统,comctl32.dll默认使用v5.82,系统会自动使用0x3FFF作参数运行InitCommonControlsEx函数注册所有可用控件
  • IE3.0通用控件需要加载comctl32.dll,并使用0x0100,0x0200,0x0400作参数运行InitCommonControlsEx函数注册控件
  • Win98/IE4.0通用控件需要加载comctl32.dll,并使用0x0800,0x1000,0x2000作参数运行InitCommonControlsEx函数注册控件
  • WinXP/WinVista通用控件需要加载comctl32.dll v6.0,系统会自动使用0xFFFF作参数运行InitCommonControlsEx函数注册控件
  • 同时,多次运行InitCommonControlsEx函数注册控件的效果是累积的
  • WinVista网络地址控件需要加载shell32.dll,并运行InitNetworkAddressControl()函数注册控件

除此之外,预定义控件大多使用WM_COMMAND等比较老的通知消息;而通用控件大多使用WM_NOTIFY等比较新的通知消息,富文本框则两者都有。但是也并不总是这样的,比如加载comctl32.dll v6.0以后,部分预定义控件也会发出WM_NOTIFY消息。

预定义控件(user32.dll):

<code class="language-txt">WC_BUTTON		"BUTTON"	// Button,CheckBox,RadioButton,GroupBox
WC_COMBOBOX		"COMBOBOX"
WC_EDIT			"EDIT"
WC_LISTBOX		"LISTBOX"
WC_SCROLLBAR		"SCROLLBAR"	// Horizontal,Vertical
WC_STATIC		"STATIC"	// StaticText,PictureControl
</code>

富文本框(richedit.dll、riched20.dll、msftedit.dll):

<code class="language-txt">RICHEDIT_CLASS10A	"RICHEDIT"	// richedit.dll
RICHEDIT_CLASS(A/W)	"RichEdit20A/W"	// riched20.dll
MSFTEDIT_CLASS		"RICHEDIT50W"	// msftedit.dll (WinXPSP1+)
</code>

Win95通用控件(comctl32.dll v4.0):

<code class="language-txt">WC_LISTVIEW		"SysListView32" // 0x0001
WC_HEADER		"SysHeader32" // 0x0001
WC_TREEVIEW		"SysTreeView32" // 0x0002
WC_TABCONTROL		"SysTabControl32" // 0x0008
TOOLBARCLASSNAME	"ToolbarWindow32" // 0x0004
STATUSCLASSNAME		"msctls_statusbar32 // 0x0004
TRACKBAR_CLASS		"msctls_trackbar32" // 0x0004
UPDOWN_CLASS		"msctls_updown32"  // 0x0010
PROGRESS_CLASS		"msctls_progress32" // 0x0020
HOTKEY_CLASS		"msctls_hotkey32" // 0x0040
ANIMATE_CLASS		"SysAnimate32" // 0x0080
TOOLTIPS_CLASS		"tooltips_class32" // 0x0002,0x0004,0x0008
</code>

IE3.0通用控件(comctl32.dll v4.70):

<code class="language-txt">WC_COMBOBOXEX		"ComboBoxEx32" // 0x0200
REBARCLASSNAME		"ReBarWindow32" // 0x0400
MONTHCAL_CLASS		"SysMonthCal32" // 0x0100
DATETIMEPICK_CLASS	"SysDateTimePick32" // 0x0100
</code>

Win98/IE4.0通用控件(comctl32.dll v4.71,v4.72,v5.80,v5.81,v5.82):

<code class="language-txt">WC_IPADDRESS		"SysIPAddress32" // 0x0800
WC_PAGESCROLLER		"SysPager" // 0x1000
WC_NATIVEFONTCTL	"NativeFontCtl" // 0x2000 (这个控件好像没有官方介绍)
</code>

WinXP/Vista通用控件(comctl32.dll v6.0):

<code class="language-txt">(重新注册预定义控件)			// 0x4000 (comctl32.dll v6.0, WinXP+, 自动)
WC_LINK			"SysLink"	// 0x8000 (comctl32.dll v6.0, WinXP+, 自动)
WC_BUTTON		"BUTTON"	// SplitButton,CommandLink (comctl32.dll v6.0, WinVista+, 自动)
</code>

WinVista网络地址控件(shell32.dll):

<code class="language-txt">WC_NETADDRESS		"msctls_netaddress"	// shell32.dll (WinVista+)
</code>

comctl32.dll用5.82还是6.0

现在的系统上通用控件库有两个版本,comctl32 v5.82和comctl32 v6.0。两者的区别主要是以下几点:

  • 默认会加载5.82版,6.0版需要使用manifest手动指定
  • 5.82使用标准GDI绘制,而6.0使用uxtheme.dll绘制,在新系统上比较好看
  • 窗口回调替换:5.82支持ANSI/Unicode窗口回调,6.0只支持Unicode窗口回调
  • 6.0多了一个SysLink控件
  • 6.0给BUTTON等预定义控件增加了一些WM_NOTIFY通知
  • Windows Vista以上版本,6.0多了一个Task Dialogs和BS_[DEF]SPLITBUTTON、BS_[DEF]COMMANDLINK两个Button Styles

5.82已经包含了绝大多数程序逻辑所必需的功能。6.0风格经常跟着系统变,还需要manifest,用起来确实麻烦一些。

如果比较在意程序风格的统一性和兼容性,建议使用5.82;如果比较在意程序的美观性,也可以使用6.0。

完整集成所有标准控件的代码:

<code class="language-cpp">#include <windows.h>
#include <tchar.h>
#include <windowsx.h>
#include <commctrl.h>
#include <commdlg.h>
#pragma comment(lib, "comctl32.lib")

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

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, _TCHAR *szCmdLine, int nShowCmd)
{
	// comctl32.dll v6.0 if exists
#ifdef USE_COMCTL32_V6
#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_IA64
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' 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.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);
	// riched32.dll,riched20.dll,msftedit.dll
	LoadLibrary(TEXT("riched32.dll"));
	LoadLibrary(TEXT("riched20.dll"));
	LoadLibrary(TEXT("msftedit.dll"));
	// shell32.dll
	HMODULE hshell32 = LoadLibrary(TEXT("shell32.dll"));
	FARPROC pInitNetworkAddressControl = NULL;
	if (hshell32)
		pInitNetworkAddressControl = GetProcAddress(hshell32, "InitNetworkAddressControl");
	if (pInitNetworkAddressControl)
		pInitNetworkAddressControl();
	DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc, NULL);
	return 0;
}
</commdlg.h></commctrl.h></windowsx.h></tchar.h></windows.h></code>
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan作者
7年8个月前 修改于 7年8个月前 IP:四川
833124

系统内置对话框

MessageBox(Ex|Indirect):最简单的消息框,功能有限,但有时候非常方便。

TaskDialog(Indirect):用于Windows Vista+,需要声明comctl32 v6.0,可用于创建Vista风格的消息框。

通用对话框(Common Dialogs):ChooseColor、ChooseFont、GetOpenFileName、GetSaveFileName、PageSetupDlg、PrintDlg、PrintDlgEx、FindText、ReplaceText等。

Shell对话框:ShellAbout、SHBrowseForFolder、RestartDialog(Ex)等。

Toolbar的“自定义工具栏”对话框。

自定义模板对话框

DialogBox(Param):用于按照rc资源中的对话框模板创建模态对话框,这种对话框使用对话框回调而不是窗口回调,并且会阻塞程序运行和父窗口获得焦点,因此也称独占式对话框。

  • 除少数消息外,返回值都是(INT_PTR)(BOOL)类型,返回TRUE表示已处理,返回FALSE表示未处理,窗口消息对应的返回值用SetWindowLongPtr(hDlg, DWLP_MSGRESULT, result);设置
  • 创建对话框时收到WM_INITDIALOG而不是WM_CREATE消息
  • 按Enter键收到IDOK的WM_COMMAND消息,按Esc或关闭按钮收到IDCANCEL的WM_COMMAND消息
  • 结束对话框使用EndDialog函数而不是DestroyWindow函数
  • 用Tab键可切换焦点,会测试子窗口的WM_GETDLGCODE消息

CreateDialog(Param):用于按照rc资源中的对话框模板创建非模态对话框,这种对话框拥有与DialogBox一样的对话框回调,但是不会阻塞程序运行。

  • 需要编写消息循环,消息循环里使用IsDialogMessage处理控件焦点相关的键盘消息
  • 终止程序+销毁对话框要使用PostQuitMessage+DestroyWindow
<code class="language-cpp">MSG msg = {};
while (GetMessage(&msg, NULL, 0, 0))
{
	if (IsDialogMessage(hDlg, &msg))
		continue;
	TranslateMessage(&msg);
	DispatchMessage(&msg);
}
</code>

PropertySheet:用于创建带选项卡的对话框,也可用于创建向导界面。控制面板上很多对话框也是使用PropertySheet函数弹出的,并不是直接使用DialogBox,比如“日期与时间”对话框与“添加硬件”向导。

proertysheet1.png

wizard.png

引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan作者
7年8个月前 修改于 7年8个月前 IP:四川
833125

关于Network Address Control

Windows Vista增加了一个控件,叫做Network Address Control。这个控件不是在comctl32.dll里面,而是在shell32.dll里面。

这个控件在观感上和Edit控件没有明显的区别,但是可以提供各种类型的网络地址验证、自动转换数据类型、弹出错误提示的功能,支持IPv4、IPv6、域名等各种网络地址。

使用这个控件之前,需要使用InitNetworkAddressControl函数:

<code class="language-cpp">HMODULE hshell32 = LoadLibrary(TEXT("shell32.dll"));
FARPROC pInitNetworkAddressControl = NULL;
if (hshell32)
	pInitNetworkAddressControl = GetProcAddress(hshell32, "InitNetworkAddressControl");
if (pInitNetworkAddressControl)
	pInitNetworkAddressControl();
</code>
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan作者
7年8个月前 修改于 7年5个月前 IP:四川
833126

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>
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

所属专业
所属分类
上级专业
同级专业
acmilan
进士 学者 笔友
文章
461
回复
2934
学术分
4
2009/05/30注册,5年10个月前活动
暂无简介
主体类型:个人
所属领域:无
认证方式:邮箱
IP归属地:未同步
文件下载
加载中...
{{errorInfo}}
{{downloadWarning}}
你在 {{downloadTime}} 下载过当前文件。
文件名称:{{resource.defaultFile.name}}
下载次数:{{resource.hits}}
上传用户:{{uploader.username}}
所需积分:{{costScores}},{{holdScores}}下载当前附件免费{{description}}
积分不足,去充值
文件已丢失

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

空空如也

加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}