一,图标
上一篇博文“[Win32SDK基本] 窗口详解(超详细)"中(地址:http://blog.csdn.net/zuishikonghuan/article/details/46378475),提到了图标的问题,上一次我是直接使用系统的默认图标了事的,这一回来讲解如何使用自己的图标。
在注册窗口类的时候,对于图标一项,是使用的LoadIcon函数,来看看LoadIcon函数的原型
MSDN:https://msdn.microsoft.com/en-us/library/windows/desktop/ms648072(v=vs.85).aspx
对于第二个参数lpIconName(图标名称),MSDN里是这样说的:
The name of the icon resource to be loaded. Alternatively, this parameter can contain the resource identifier in the low-order word and zero in the high-order word. Use the MAKEINTRESOURCE macro to create this value.
我的理解:如果实参是一个字符串,那么就直接调用资源名称为这个字符串的图标,如果是用资源id的图标,那么就这个整数的高2字节应为0x0000,低2字节为资源id。sdk为我们提供了一个叫MAKEINTRESOURCE的宏将一个id的高2字节置0。
经过测试,事实就是这样,VS默认使用id的方式用图标,而我喜欢使用字符串方式。另外值得一题的是,几乎所有用到rc资源的函数,对于资源的参数都是字符串类型,而且提供了字符串(名称)方法和id方法
我们打开上一篇博文中代码的工程,打开VS为我们生成的rc文件,然后删掉里面所有的内容,没错,是删除所有的内容!再打开Resource.h头文件,删除所有内容。
再回到rc文件,添加一个图标,注意1.ico要放到工程的文件夹中。
ICON_1 ICON "1.ico"
然后到注册窗口类的代码那儿,将LoadIcon哪儿改为
LoadIcon(hInstance,TEXT("ICON_1"))
其中,hInstance为实例句柄。
再“重新生成工程”,运行一下,看看有什么发现。
运行的效果图如下(上图为这次的,下图是上次的,详见我的上一篇博文(地址:http://blog.csdn.net/zuishikonghuan/article/details/46378475))
二,程序版本信息
给程序添加版本信息,这个其实是可以直接用VS的资源工具弄出来的,再稍微修改了下。
1 VERSIONINFO FILEVERSION 1,0,0,1 PRODUCTVERSION 1,0,0,1 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x40004L FILETYPE 0x1L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "080404b0" BEGIN VALUE "CompanyName", "TODO: <公司名>" VALUE "FileDescription", "TODO: <文件说明>" VALUE "FileVersion", "1.0.0.1" VALUE "InternalName", "Win32Pro.exe" VALUE "LegalCopyright", "Copyright (C) 2015" VALUE "OriginalFilename", "Win32Pro.exe" VALUE "ProductName", "TODO: <产品名>" VALUE "ProductVersion", "1.0.0.1" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x804, 1200 END END
我想不用再解释什么了,效果图如下
三,Manifest清单
这个我将于以后的一篇关于系统风格的博文中详细说。
四,对话框
对于不愿意使用API创建窗口的人来说,使用RC对话框无疑是一个不错的选择,但是使用对话框有一个缺陷,那就是别人拿到你的程序后,用一个PE资源编辑器就可以轻松修改掉你对话框里的文字,组件,是非常不安全的。
使用RC对话框非常的简单,可以直接使用VS的对话框编辑器,直接拖动组件在对话框上画就行。
但是对于我这种有强迫症的人来说,非要搞明白他,那我就把我早年憨憨地分析VS创建的对话框资源分析拿出来献丑:
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU //普通 STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_SYSMENU //无边框 STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME //允许改变大小 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU //对话框最初是可见的 WS_VISIBLE EXSTYLE WS_EX_APPWINDOW //在任务栏存在 EXSTYLE WS_EX_TOPMOST //总在最前 STYLE DS_ABSALIGN | DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU //相对于桌面对其 DS_ABSALIGN STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU //最大化按钮 WS_MAXIMIZEBOX STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU //最小化按钮 WS_MINIMIZEBOX STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU //居中显示 DS_CENTER 对话框ID DIALOGEX X轴, Y轴, 宽度, 高度 STYLE 风格 EXSTYLE 拓展风格 CAPTION "标题" //MENU 菜单 //CLASS "class" //窗口类 FONT 8, "MS Shell Dlg", 400, 0, 0x1 //字体 BEGIN DEFPUSHBUTTON "确定",对话框ID,198,196,50,14 //激活按钮 PUSHBUTTON "取消",对话框ID,392,196,50,14 //按钮 LTEXT "标题",-1,42,14,114,8,SS_NOPREFIX //显示字符串 EDITTEXT 对话框ID,41,112,68,29,ES_AUTOHSCROLL //编辑框 /* ES_PASSWORD | ES_AUTOHSCROLL //密码编辑框 ES_AUTOHSCROLL | ES_READONLY //只读编辑框 ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN //多行 ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_HSCROLL //多行 水平滚动条 ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL | WS_HSCROLL //多行 垂直+水平滚动条 ES_AUTOHSCROLL | NOT WS_BORDER //无边框 */ CONTROL "Radio1",对话框ID,"Button",BS_AUTORADIOBUTTON,46,147,65,28 //单选框 CONTROL "Check1",对话框ID,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,140,144,86,39 //复选框 GROUPBOX "Static",对话框ID,378,106,94,72 //分组 END INT_PTR CALLBACK Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_INITDIALOG: //创建对话框完毕 return (INT_PTR)TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDCANCEL) // IDCANCEL关闭按钮 { EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; } if (LOWORD(wParam) == 单击的按钮ID) { //....... return (INT_PTR)TRUE; } break; /*case WM_CLOSE: return (INT_PTR)TRUE;//屏蔽关闭 break;*/ } return (INT_PTR)FALSE; }
五,菜单
对于很多win32程序,他们的窗口上都有菜单,上一篇博文“[Win32SDK基本] 窗口详解(超详细)"中(地址:http://blog.csdn.net/zuishikonghuan/article/details/46378475),提到了菜单的问题,上一次我是直接用NULL了事的,这一回来讲解如何使用自己的菜单。
在RC文件里添加:
MENU1 MENU BEGIN POPUP "菜单A" BEGIN MENUITEM "菜单1", 1 MENUITEM SEPARATOR MENUITEM "上面是一个分隔条", 2 POPUP "菜单2" BEGIN MENUITEM "菜单3", 3 MENUITEM "菜单4", 4 END END POPUP "菜单B" BEGIN MENUITEM "菜单5", 5 END END
在创建窗口的时候,对于hMenu(菜单句柄)一项,我们使用在RC资源里注册的菜单。使用LoadMenu函数,类似于上文说的使用图标。(菜单还可以动态创建,使用CreateMenu和CreatePopupMenu函数)
然后运行,看看效果吧。
如果想动态显示菜单,可以使用TrackPopupMenu函数,我以后会写一篇关于菜单的文章,到时候详细说。
如何响应用户点击菜单的消息呢,在上一篇的窗口回调函数的switch中添加一下代码
case WM_COMMAND: int id; id = LOWORD(wParam); //判断菜单ID,注意不需要再判断HIWORD(wParam)了,因为菜单的通知码是一个定值(和控件不一样) switch (id) { case 3://这里使用在RC资源里面注册的菜单号 MessageBox(hwnd, TEXT("菜单3被点击"), TEXT(""), 0); break; } break;