在本专栏上一篇文章中带领大家学习了对话框的创建,并且在项目中创建出了对话框。在这一篇文章中,我将带领大家学习Win32通用控件,了解_WM_NOTIFY
消息,并且带领大家初步写出课程中加载Windows所有进程的应用程序的雏形,带领大家详解其中的原理。
一.标准控件与通用控件
Windows中有很多控件,有一些控件是我们不需要加载的,使用频率很高我们称为标准控件,有一些使用频率不是很高,我们在使用的时候需要加载,我们称为通用控件。
标准控件:
Static
Group Box
Button
CHeck Box
Radio Box
Edit
ListBox
Windows通用控件,包含在commctrl32.dll
中,使用前需要:
#include <commctrl.h> #pragma comment(lib,"comctl32.lib")
通用控件包括:
Animation
ComboBoxEx
Drag_List_Box
Flat_Scroll_bar
Header
HotKey
ImageList
IPAddress
List_View
Month_Calendar
Pager
Progress_Bar
Property_Sheets
Rebar
Status Bars
SysLink
Tab
Trackbar
TreeView
Up_and_Down
特别说明:
通过用控件在使用前,需要通过INITCOMMONCONTROLSEX
进行初始化。 只要在你的程序中任意地方使用了该函数,就会使得Windows的程序加载器PE Loader加载该库。
INITCOMMONCONTROLSEX icex; icex.dwSize = sizeof(INITCOMMONCONTROLSEX); icex.dwICC = ICC_WIN95_CLASSES; InitCOmmonControlsEx(&icex);
二.WM_INITDIALOG消息
#define WM_INITDIALOG 0x0110 • 1
发送时间:在对话框显示之前,发送到对话框回调函数。
参数:
· wParem:用于接收默认键盘焦点的控件的句柄。 仅当对话框过程返回 TRUE 时,系统才分配默认键盘焦点。
lParam:其他初始化数据。
三.WM_NOTIFY消息
1.WM_NOTIFY消息的使用
该消息类型与WM_COMMAND类型相似,都是由子窗口向父窗口发送的消息。
WM_NOTIFY消息可以包含比WM_COMMAND更为丰富的信息。
Windows中有很多通用控件的消息,都是通过WM_NOTIFY来描述的。
2.WM_NOTIFY消息参数
- 发送时间:当发生事件或控件需要一些信息时,由公共控件发送到父窗口。
- 参数:
wParam:发送消息的公用控件的标识符。
lParam:指向包含通知代码和其他信息的NMHDR的指针。 - 注意:
消息的目标必须是控件父级的HWND.
3.NMHDR结构
typedef struct tagNMHDR{ HWNDhwndFrom; //发送通知消息的控件窗口句柄 UINT idFrom; //发送通知消息的控件ID UINT code; //通知代码 };
这个结构体能满足一般的需求,但能描述的信息任然是有限的。
解决方案:对每一种不同用途的通知消息都定义一种结构体来表示:
四.加载Windows进程应用程序项目初步
这一章开始,带领大家开发一个加载Windows进程的EXE,其中包括:加载Windows当前的所有进程,包括进程名,PID,镜像地址,镜像大小,并且再单击进程的时候,加载该进程所有的模块。
本篇文章将会一步一步带领大家写出基本的代码,在最后给出完整的代码。在项目开发完毕后,我会发布完整代码。
1. 我们首先画出对话框界面:
2. 然后我们来写出应用程序入口函数:
#include "framework.h" #include "PEProcess.h" #include <CommCtrl.h> #pragma comment(lib,"comctl32.lib") //需要使用通用控件 HINSTANCE hIns = 0; //入口函数 int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { hIns = hInstance; //使用通用控件的向前声明 INITCOMMONCONTROLSEX icex; icex.dwSize = sizeof(INITCOMMONCONTROLSEX); icex.dwICC = ICC_WIN95_CLASSES; InitCommonControlsEx(&icex); DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG_MAIN), NULL, (DLGPROC)MainDlgProc); //加载主对话框 return 0; }
使用通用控件的向前声明:
1. INITCOMMONTROLSEX结构体:
这里我们使用到了INITCOMMONCONTROLSEX
结构体,我们来看看这个结构体:
typedef struct tagINITCOMMONCONTROLSEX { DWORD dwSize; DWORD dwICC; } INITCOMMONCONTROLSEX, *LPINITCOMMONCONTROLSEX;
该结构通常用于从动态链接库加载常见控件类信息。
参数说明:
dwSize:结构大小(以字节为单位)
dwICC:指向将从DLL加载哪些常见控件类的位标志集。
2.InitCommonControlsEx
函数
MSDN官方文档:InitCOmmonControlsEx函数
BOOL InitCOmmonControlsEx( [in] const INITCOMMONCONTROLSEX *pocce );
函数说明:
函数功能:确保加载公共控件(Comctl32),并从该DLL注册特定的公共控件类
参数说明:
指向INITCOMMONCONTROLSEX结构体,该结构包含指定将注册哪些控件类信息。
返回值:
成功返回TRUE,失败返回FALSE.
在写入了入口函数,并且加载了主对话框之后,我们运行,发现程序页面已经出来了:
3.主对话框的回调函数
我们应该想到:
- 在对话框显示之前,需要初始化对话框,需要我们将列名等信息全部初始化
- 在对话框显示之前,发送的消息为
WM_INITDIALOG
,初始化的工作应该在这个消息内完成 - 由于初始化的过程比较复杂,我这里对初始化进程窗口和初始化模块窗口分别封装了函数处理
OOL CALLBACK MainDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { BOOL nRet = FALSE; switch (uMsg) { case WM_CLOSE: { EndDialog(hDlg, 0); PostQuitMessage(0); break; } case WM_INITDIALOG: { InitProcessListView(hDlg); //设置ProcessListView的风格 break; } case WM_COMMAND: { switch (LOWORD(wParam)) { case IDC_BUTTON_ABOUT: { DialogBox(hIns, MAKEINTRESOURCE(IDD_ABOUTBOX), NULL, NULL); } case IDC_BUTTON_PE: { //打开新的对话框,PE查看器 return 0; } case IDC_BUTTON_OUT: { EndDialog(hDlg, 0); return TRUE; } } } } return nRet; }