Win32通用控件,加载进程(PE查看器)项目初步

在本专栏上一篇文章中带领大家学习了对话框的创建,并且在项目中创建出了对话框。在这一篇文章中,我将带领大家学习Win32通用控件,了解_WM_NOTIFY消息,并且带领大家初步写出课程中加载Windows所有进程的应用程序的雏形,带领大家详解其中的原理。

文章目录

  • 一.标准控件与通用控件
  • 二.WM_INITDIALOG消息
  • 三.WM_NOTIFY消息
    • 1.WM_NOTIFY消息的使用
    • 2.WM_NOTIFY消息参数
    • 3.NMHDR结构
  • 四.加载Windows进程应用程序项目初步
    • 1. 我们首先画出对话框界面:
    • 2. 然后我们来写出应用程序入口函数:
      • 使用通用控件的向前声明:
        • 1. INITCOMMONTROLSEX结构体:
        • 2.`InitCommonControlsEx`函数
    • 3.主对话框的回调函数
    • 4.初始化进程窗口函数:
    • 5.初始化模块窗口函数:
      • `ListView——Insertcolumn`宏
      • ` LVCOLUMN 结构`:
    • 6.向列表中加假的进程
      • `LVM_INSERTITEM`消息
      • `LVM_SETITEM`消息
      • `LVITEMA` 结构
    • 7.向模块列表中加入假的模块数据
  • 三.加载Windows进程应用程序项目初步完整代码

一.标准控件与通用控件

Windows中有很多控件,有一些控件是我们不需要加载的,使用频率很高我们称为标准控件,有一些使用频率不是很高,我们在使用的时候需要加载,我们称为通用控件。
标准控件:

Static
Group Box
Button
CHeck Box
Radio Box
Edit
ComboBox
ListBox

Windows通用控件,包含在commctrl32.dll中,使用前需要:

#include 
#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
Toolbar
Trackbar
TreeView
Up_and_Down

特别说明:
通过用控件在使用前,需要通过INITCOMMONCONTROLSEX进行初始化。 只要在你的程序中任意地方使用了该函数,就会使得Windows的程序加载器PE Loader加载该库。

INITCOMMONCONTROLSEX icex;
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_WIN95_CLASSES;
InitCOmmonControlsEx(&icex);

二.WM_INITDIALOG消息

MSDN官方文档;WM_INITDIALOG消息

#define WM_INITDIALOG                   0x0110

发送时间:在对话框显示之前,发送到对话框回调函数。
参数:
· wParem:用于接收默认键盘焦点的控件的句柄。 仅当对话框过程返回 TRUE 时,系统才分配默认键盘焦点。
lParam:其他初始化数据。

三.WM_NOTIFY消息

1.WM_NOTIFY消息的使用

该消息类型与WM_COMMAND类型相似,都是由子窗口向父窗口发送的消息。
WM_NOTIFY消息可以包含比WM_COMMAND更为丰富的信息。
Windows中有很多通用控件的消息,都是通过WM_NOTIFY来描述的。

2.WM_NOTIFY消息参数

MSDN官方文档:WM_NOTIFY消息

  • 发送时间:当发生事件或控件需要一些信息时,由公共控件发送到父窗口。
  • 参数:
    wParam:发送消息的公用控件的标识符。
    lParam:指向包含通知代码和其他信息的NMHDR的指针。
  • 注意:
    消息的目标必须是控件父级的HWND.

3.NMHDR结构

typedef struct tagNMHDR{
	HWNDhwndFrom;      //发送通知消息的控件窗口句柄
	UINT idFrom;       //发送通知消息的控件ID
	UINT code;         //通知代码
};

这个结构体能满足一般的需求,但能描述的信息任然是有限的。
解决方案:对每一种不同用途的通知消息都定义一种结构体来表示:
Win32通用控件,加载进程(PE查看器)项目初步_第1张图片

四.加载Windows进程应用程序项目初步

这一章开始,带领大家开发一个加载Windows进程的EXE,其中包括:加载Windows当前的所有进程,包括进程名,PID,镜像地址,镜像大小,并且再单击进程的时候,加载该进程所有的模块。
本篇文章将会一步一步带领大家写出基本的代码,在最后给出完整的代码。在项目开发完毕后,我会发布完整代码。

1. 我们首先画出对话框界面:

Win32通用控件,加载进程(PE查看器)项目初步_第2张图片

2. 然后我们来写出应用程序入口函数:

#include "framework.h"
#include "PEProcess.h"
#include              
#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结构体,我们来看看这个结构体:
MSDN官方文档:INITCOMMONTROLSEX结构体

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.

在写入了入口函数,并且加载了主对话框之后,我们运行,发现程序页面已经出来了:
Win32通用控件,加载进程(PE查看器)项目初步_第3张图片

3.主对话框的回调函数

我们应该想到:

  1. 在对话框显示之前,需要初始化对话框,需要我们将列名等信息全部初始化
  2. 在对话框显示之前,发送的消息为WM_INITDIALOG,初始化的工作应该在这个消息内完成
  3. 由于初始化的过程比较复杂,我这里对初始化进程窗口和初始化模块窗口分别封装了函数处理
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;
}

4.初始化进程窗口函数:

VOID InitProcessListView(HWND hDlg) {
	//设置窗口风格的话调用了结构体
	LV_COLUMN lv;
	HWND hListProcess;

	//初始化
	memset(&lv, 0, sizeof(LV_COLUMN));
	//获取IDC_LIST_PROCESS句柄
	hListProcess = GetDlgItem(hDlg, IDC_LIST3);
	//设置整行选中
	SendMessage(hListProcess, LVM_GETEXTENDEDLISTVIEWSTYLE, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);

	//第一列:
	lv.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
	lv.pszText = (LPWSTR)TEXT("进程");           //列标题
	lv.cx = 200;             //行宽
	lv.iSubItem = 0;
	//ListView_InsertColumn(hListProcess,0,&lv);
	SendMessage(hListProcess, LVM_INSERTCOLUMN, 0, (DWORD)&lv);
	//EnumProcess(hLostProcess);
	
	//第二列
	lv.pszText = (LPWSTR)TEXT("PID");
	lv.cx = 75;
	lv.iSubItem = 1;
	//ListView_InsertColumn(hListProcess, 1, &lv);
	SendMessage(hListProcess, LVM_INSERTCOLUMN, 1, (DWORD)&lv);

	//第三列
	lv.pszText = (LPWSTR)TEXT("镜像基址");
	lv.cx = 150;
	lv.iSubItem = 2;
	//ListView_InsertColumn(hListProcess, 2, &lv);
	SendMessage(hListProcess, LVM_INSERTCOLUMN, 2, (DWORD)&lv);

	//第三列
	lv.pszText = (LPWSTR)TEXT("镜像大小");
	lv.cx = 174;
	lv.iSubItem = 3;
	//ListView_InsertColumn(hListProcess, 3, &lv);
	SendMessage(hListProcess, LVM_INSERTCOLUMN, 3, (DWORD)&lv);
}

5.初始化模块窗口函数:

OID InitMoudleListView(HWND hDlg) {
	//设置窗口风格需要调用结构体
	LV_COLUMN lv;
	HWND hListMoudles;

	//初始化
	memset(&lv, 0, sizeof(LV_COLUMN));
	//获取模块列表句柄
	hListMoudles = GetDlgItem(hDlg, IDC_LIST_MOUDLE);
	//设置整行选中
	SendMessage(hListMoudles, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);

	//第一列:
	lv.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
	lv.pszText = (LPWSTR)TEXT("模块名称");
	lv.cx = 400;
	lv.iSubItem = 0;
	//ListView_Insertcolumn(hListMoudles,0,&lv);
	SendMessage(hListMoudles, LVM_INSERTCOLUMN, 0, (DWORD)&lv);

	//第二列:
	lv.pszText = (LPWSTR)TEXT("模块位置");
	lv.cx = 400;
	lv.iSubItem = 1;
	SendMessage(hListMoudles, LVM_INSERTCOLUMN, 0, (DWORD)&lv);
}

我们可以发现,在初始化进程窗口和初始化模块窗口函数中,我们先写好了我们想要显示的标题,之后使用发送消息的方式使内容显示。这里我注释掉了一个,实际上这两种方式没有什么区别,都能使内容显示。
我们来看看ListView——Insertcolumn宏:

ListView——Insertcolumn

MSDN官方文档:ListView——Insertcolumn宏

void ListView_InsertColumn(
   hwnd,
   iCol,
   pcol
);
  • 功能:从列表视图控件中插入新列
  • 参数:
    • hwnd:列表视图控件的句柄。
    • iCol:新列的索引。
    • pcol:指向包含新列属性的 LVCOLUMN 结构的指针。

LVCOLUMN 结构:

MSDN官方文档:LVCOLUMN 结构
包含有关报表视图中的列的信息。
这个结构体大家到微软文档中自行查看吧,解释起来真的很费劲。

6.向列表中加假的进程

由于我们还没有学习如何加载操作系统中的所有进程,所以今天带领大家向列表中加载假的进程数据,有关如何加载操作系统真正的进程,后续会为大家讲解。

//加载进程函数
VOID EnumProcess(HWND hListProcess) {
	LV_ITEM vitem;

	//初始化,第一个进程
	memset(&vitem, 0, sizeof(LV_ITEM));
	vitem.mask = LVIF_TEXT;

	//假数据:
	vitem.pszText = (LPWSTR)TEXT("csrss.exe");
	vitem.iItem = 0;
	vitem.iSubItem = 0;
	//ListView_Insertem(hListProcess,*vitem);
	SendMessage(hListProcess, LVM_INSERTITEM, 0, (DWORD)&vitem);

	vitem.pszText = (LPWSTR)TEXT("448");
	vitem.iItem = 0;
	vitem.iSubItem = 1;
	SendMessage(hListProcess, LVM_SETITEM, 0, (DWORD)&vitem);
	//ListView_SetItem(hListProcess, &vitem);

	vitem.pszText = (LPWSTR)TEXT("56590000");
	vitem.iItem = 0;
	vitem.iSubItem = 2;
	ListView_SetItem(hListProcess, &vitem);

	vitem.pszText = (LPWSTR)TEXT("000F0000");
	vitem.iItem = 0;
	vitem.iSubItem = 3;
	ListView_SetItem(hListProcess, &vitem);


	//第二个进程假数据:
	vitem.pszText = (LPWSTR)TEXT("QQ.exe");
	vitem.iItem = 1;
	vitem.iSubItem = 0;
	SendMessage(hListProcess, LVM_INSERTITEM, 0, (DWORD)&vitem);

	vitem.pszText = (LPWSTR)TEXT("153");
	vitem.iItem = 1;
	vitem.iSubItem = 1;
	ListView_SetItem(hListProcess, &vitem);

	vitem.pszText = (LPWSTR)TEXT("65580000");
	vitem.iItem = 1;
	vitem.iSubItem = 2;
	ListView_SetItem(hListProcess, &vitem);

	vitem.pszText = (LPWSTR)TEXT("001E0000");
	vitem.iItem = 1;
	vitem.iSubItem = 3;
	ListView_SetItem(hListProcess, &vitem);

	//第三个进程假数据:
	vitem.pszText = (LPWSTR)TEXT("WeChat.exe");
	vitem.iItem = 2;
	vitem.iSubItem = 0;
	SendMessage(hListProcess, LVM_INSERTITEM, 0, (DWORD)&vitem);

	vitem.pszText = (LPWSTR)TEXT("256");
	vitem.iItem = 2;
	vitem.iSubItem = 1;
	ListView_SetItem(hListProcess, &vitem);

	vitem.pszText = (LPWSTR)TEXT("75960000");
	vitem.iItem = 2;
	vitem.iSubItem = 2;
	ListView_SetItem(hListProcess, &vitem);

	vitem.pszText = (LPWSTR)TEXT("015B0000");
	vitem.iItem = 2;
	vitem.iSubItem = 3;
	ListView_SetItem(hListProcess, &vitem);
}

这里加载了一些假的数据。
这里有个需要尤其注意的地方: 就是在列表中显示我们加入的数据的时候,只有在第一个,我们使用SendMessage函数的时候,发送了LVM_INSERTITEM类型的消息,使用宏的时候使用了ListView_Insertem宏,在后续显示数据的时候,我们都是用的是LVM_SETITEM类型的消息,或者是使用了ListView_SetItem宏,这里要尤其注意,如果使用错误的话,是不能显示的。
我们来看看这两种消息的区别:

LVM_INSERTITEM消息

MSDN官方文档:LVM_INSERTITEM消息

  • 发送时间:在列表视图控件中插入新项。
  • 附加信息:
    • wParam:必须为0.
    • lParam:指向指定列表视图项属性的 LVITEM 结构的指针。

LVM_SETITEM消息

MSDN官方文档:LVSETITEM消息

  • 发送时间:设置列表视图项的某些或全部属性。 还可以发送LVM_SETITEM来设置子项的文本
  • 附加信息:
    • wParam:必须为0.
    • lParam:指向包含新项属性的 LVITEM 结构的指针

注意两者区别为在列表视图控件中插入新项和添加子项。

LVITEMA 结构

MSDN官方文档:LVITEMA结构
结构用途:用于指定或接收列表视图项的属性。
这个结构由于用法很多,大家自行到MSDN官方文档中查阅。

7.向模块列表中加入假的模块数据

这个函数与老师上课讲的完全一致,但是并非真的添加了数据:

VOID EnumMoudles(HWND hListProcess, WPARAM wParam, LPARAM lParam) {
	DWORD dwRowId;
	TCHAR szPid[21];
	LV_ITEM lv;

	//初始化
	memset(&lv, 0, sizeof(LV_ITEM));
	
	//获取选择行
	dwRowId = SendMessage(hListProcess, LVM_GETNEXTITEM,-1 , LVNI_SELECTED);
	if (dwRowId == -1) {
		MessageBox(NULL, TEXT("请选择进程"), TEXT("出错啦"), MB_OK);
		return;
	}

	//获取PID
	lv.iSubItem = 1;
	lv.pszText = szPid;
	lv.cchTextMax = 0x20;
	SendMessage(hListProcess, LVM_GETITEMTEXT, dwRowId, (DWORD)&lv);

	MessageBox(NULL, szPid, TEXT("PID"), MB_OK);
}

三.加载Windows进程应用程序项目初步完整代码

讲述了这些代码,这里给大家给出完整代码,但是由于控件的ID不同,复制的时候还需要自己改动。

// PEProcess.cpp : 定义应用程序的入口点。
//

#include "framework.h"
#include "PEProcess.h"
#include 
#pragma comment(lib,"comctl32.lib")
HINSTANCE hIns = 0;

//程序向前声明
BOOL CALLBACK MainDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);     //主窗口(对话框)回调函数
VOID InitProcessListView(HWND hDlg);       //初始化主窗口进程列表函数
VOID EnumProcess(HWND hListProcess);       //设置假的进程数据函数
VOID InitMoudleListView(HWND hDlg);        //初始化主窗口模块列表函数
VOID EnumMoudles(HWND hListProcess, WPARAM wParam, LPARAM lParam);  //设置假的模块列表函数

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;
}


//各类函数实现
BOOL 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的风格,初始化进程列表
			InitMoudleListView(hDlg);          //设置MoudleListView的风格,初始化模块列表
			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);
					PostQuitMessage(0);
					return TRUE;
				}
			}
		}
		case WM_NOTIFY: {
			NMHDR* pNMHDR = (NMHDR*)lParam;
			if (wParam == IDC_LIST_PROCESS && pNMHDR->code == NM_CLICK) {
				EnumMoudles(GetDlgItem(hDlg, IDC_LIST_PROCESS), wParam, lParam);
			}
			break;
		}
	}
	return nRet;
}

VOID InitProcessListView(HWND hDlg) {
	//设置窗口风格调用结构体
	LV_COLUMN lv;
	HWND hListProcess;

	//初始化
	memset(&lv, 0, sizeof(LV_COLUMN));
	//获取进程列表句柄
	hListProcess = GetDlgItem(hDlg, IDC_LIST_PROCESS);
	//设置整行选中
	SendMessage(hListProcess, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);
	//出错代码:::::
	SendMessage(hListProcess, LVM_GETEXTENDEDLISTVIEWSTYLE, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);

	//第一列:
	lv.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
	lv.pszText = (LPWSTR)TEXT("进程");           //列标题
	lv.cx = 350;             //行宽
	lv.iSubItem = 0;
	//ListView_InsertColumn(hListProcess,0,&lv);
	SendMessage(hListProcess, LVM_INSERTCOLUMN, 0, (DWORD)&lv);
	
	//第二列
	lv.pszText = (LPWSTR)TEXT("PID");
	lv.cx = 100;
	lv.iSubItem = 1;
	//ListView_InsertColumn(hListProcess, 1, &lv);
	SendMessage(hListProcess, LVM_INSERTCOLUMN, 1, (DWORD)&lv);

	//第三列
	lv.pszText = (LPWSTR)TEXT("镜像基址");
	lv.cx = 150;
	lv.iSubItem = 2;
	//ListView_InsertColumn(hListProcess, 2, &lv);
	SendMessage(hListProcess, LVM_INSERTCOLUMN, 2, (DWORD)&lv);

	//第四列
	lv.pszText = (LPWSTR)TEXT("镜像大小");
	lv.cx = 200;
	lv.iSubItem = 3;
	//ListView_InsertColumn(hListProcess, 3, &lv);
	SendMessage(hListProcess, LVM_INSERTCOLUMN, 3, (DWORD)&lv);
	EnumProcess(hListProcess);
}

//加载进程函数
VOID EnumProcess(HWND hListProcess) {
	LV_ITEM vitem;

	//初始化,第一个进程
	memset(&vitem, 0, sizeof(LV_ITEM));
	vitem.mask = LVIF_TEXT;

	//假数据:
	vitem.pszText = (LPWSTR)TEXT("csrss.exe");
	vitem.iItem = 0;
	vitem.iSubItem = 0;
	//ListView_Insertem(hListProcess,*vitem);
	SendMessage(hListProcess, LVM_INSERTITEM, 0, (DWORD)&vitem);

	vitem.pszText = (LPWSTR)TEXT("448");
	vitem.iItem = 0;
	vitem.iSubItem = 1;
	SendMessage(hListProcess, LVM_SETITEM, 0, (DWORD)&vitem);
	//ListView_SetItem(hListProcess, &vitem);

	vitem.pszText = (LPWSTR)TEXT("56590000");
	vitem.iItem = 0;
	vitem.iSubItem = 2;
	ListView_SetItem(hListProcess, &vitem);

	vitem.pszText = (LPWSTR)TEXT("000F0000");
	vitem.iItem = 0;
	vitem.iSubItem = 3;
	ListView_SetItem(hListProcess, &vitem);


	//第二个进程假数据:
	vitem.pszText = (LPWSTR)TEXT("QQ.exe");
	vitem.iItem = 1;
	vitem.iSubItem = 0;
	SendMessage(hListProcess, LVM_INSERTITEM, 0, (DWORD)&vitem);

	vitem.pszText = (LPWSTR)TEXT("153");
	vitem.iItem = 1;
	vitem.iSubItem = 1;
	ListView_SetItem(hListProcess, &vitem);

	vitem.pszText = (LPWSTR)TEXT("65580000");
	vitem.iItem = 1;
	vitem.iSubItem = 2;
	ListView_SetItem(hListProcess, &vitem);

	vitem.pszText = (LPWSTR)TEXT("001E0000");
	vitem.iItem = 1;
	vitem.iSubItem = 3;
	ListView_SetItem(hListProcess, &vitem);

	//第三个进程假数据:
	vitem.pszText = (LPWSTR)TEXT("WeChat.exe");
	vitem.iItem = 2;
	vitem.iSubItem = 0;
	SendMessage(hListProcess, LVM_INSERTITEM, 0, (DWORD)&vitem);

	vitem.pszText = (LPWSTR)TEXT("256");
	vitem.iItem = 2;
	vitem.iSubItem = 1;
	ListView_SetItem(hListProcess, &vitem);

	vitem.pszText = (LPWSTR)TEXT("75960000");
	vitem.iItem = 2;
	vitem.iSubItem = 2;
	ListView_SetItem(hListProcess, &vitem);

	vitem.pszText = (LPWSTR)TEXT("015B0000");
	vitem.iItem = 2;
	vitem.iSubItem = 3;
	ListView_SetItem(hListProcess, &vitem);
}


VOID InitMoudleListView(HWND hDlg) {
	//设置窗口风格需要调用结构体
	LV_COLUMN lv;
	HWND hListMoudles;

	//初始化
	memset(&lv, 0, sizeof(LV_COLUMN));
	//获取模块列表句柄
	hListMoudles = GetDlgItem(hDlg, IDC_LIST_MOUDLE);
	//设置整行选中
	SendMessage(hListMoudles, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);

	//第一列:
	lv.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
	lv.pszText = (LPWSTR)TEXT("模块名称");
	lv.cx = 400;
	lv.iSubItem = 0;
	//ListView_Insertcolumn(hListMoudles,0,&lv);
	SendMessage(hListMoudles, LVM_INSERTCOLUMN, 0, (DWORD)&lv);

	//第二列:
	lv.pszText = (LPWSTR)TEXT("模块位置");
	lv.cx = 400;
	lv.iSubItem = 1;
	SendMessage(hListMoudles, LVM_INSERTCOLUMN, 0, (DWORD)&lv);
}


VOID EnumMoudles(HWND hListProcess, WPARAM wParam, LPARAM lParam) {
	DWORD dwRowId;
	TCHAR szPid[21];
	LV_ITEM lv;

	//初始化
	memset(&lv, 0, sizeof(LV_ITEM));
	
	//获取选择行
	dwRowId = SendMessage(hListProcess, LVM_GETNEXTITEM,-1 , LVNI_SELECTED);
	if (dwRowId == -1) {
		MessageBox(NULL, TEXT("请选择进程"), TEXT("出错啦"), MB_OK);
		return;
	}

	//获取PID
	lv.iSubItem = 1;
	lv.pszText = szPid;
	lv.cchTextMax = 0x20;
	SendMessage(hListProcess, LVM_GETITEMTEXT, dwRowId, (DWORD)&lv);

	MessageBox(NULL, szPid, TEXT("PID"), MB_OK);
}

程序效果:
Win32通用控件,加载进程(PE查看器)项目初步_第4张图片

今天的分享就到这里,如果文章中出现错误或者是本人理解不到位的地方,还请大家及时指出来,我会非常虚心地学习。希望大家共同进步!!!

你可能感兴趣的:(#,滴水逆向三期win32编程,windows,microsoft,网络安全,系统安全,c++)