1.标准控件与通用控件
标准控件:是指常用的一些控件,在使用的时候可以直接拿来用
例如:Static、Group Box、Button、Check Box、Edit、ComboBox等
通用控件:是指一些不是太常用的控件,因为如果把所有的控件都存储在一个EXE程序中的话,就会显得很臃肿,因此微软就将不常用的一些控件放进一个dll中,因此我们在使用通用控件的时候不能直接使用,要将dll导入之后才能使用
#include <commctrl.h>
#pragma comment(lib,"comctl32.lib")
这里我们导入dll之后,只是表示我们能够使用这些控件了,还不能完全能够使用
此时我们需要在WinMain函数中定义该结构体的变量,如下:
INITCOMMONCONTROLSEX control; //声明一个对象
control.dwSize=sizeof(INITCOMMONCONTROLSEX); //结构体的大小,以字节为单位
control.dwICC=ICC_WIN95_CLASSES; //指示将从DLL加载哪些公共控制类的位标志集,
//ICC_WIN95_CLASSES是所有的集合
InitCommonControlsEx(&control); //该函数和该结构体搭配使用
此时我们已经创建好对话框中的控件
接下来需要初始化控件中的名字和数据
2.ListView的使用
初始化List控件的名字
LV_COLUMN lv;
//包含有关报表视图中某列的信息。此结构可用于创建和操作列
//创建这个结构体,里面为了存储一些信息
HWND hListProcess;
//初始化
memset(&lv,0,sizeof(LV_COLUMN));
//获取IDC_LIST_PROCESS句柄
hListProcess = GetDlgItem(hDlg,IDC_LIST_PROCESS);
//设置整行选中
SendMessage(hListProcess,LVM_SETEXTENDEDLISTVIEWSTYLE,LVS_EX_FULLROWSELECT,LVS_EX_FULLROWSELECT);
//第一列
lv.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
lv.pszText = TEXT("进程"); //列标题
lv.cx = 200; //列宽
lv.iSubItem = 0;
//ListView_InsertColumn(hListProcess, 0, &lv);
SendMessage(hListProcess,LVM_INSERTCOLUMN,0,(DWORD)&lv);
//第二列
lv.pszText = TEXT("PID");
lv.cx = 100;
lv.iSubItem = 1;
//ListView_InsertColumn(hListProcess, 1, &lv);
SendMessage(hListProcess,LVM_INSERTCOLUMN,1,(DWORD)&lv);
//第三列
lv.pszText = TEXT("镜像基址");
lv.cx = 100;
lv.iSubItem = 2;
ListView_InsertColumn(hListProcess, 2, &lv);
//第四列
lv.pszText = TEXT("镜像大小");
lv.cx = 100;
lv.iSubItem = 3;
ListView_InsertColumn(hListProcess, 3, &lv);
添加数据到List控件
LV_ITEM vitem; //指定或接收列表视图项的属性
//初始化
memset(&vitem,0,sizeof(LV_ITEM));
vitem.mask = LVIF_TEXT;
vitem.pszText = "csrss.exe";
vitem.iItem = 0; //行数
vitem.iSubItem = 0; //列数
//ListView_InsertItem(hListProcess, &vitem);
SendMessage(hListProcess, LVM_INSERTITEM,0,(DWORD)&vitem);
//这里只有第一行的事件叫LVM_INSERTITEM
vitem.pszText = TEXT("448");
vitem.iItem = 0;
vitem.iSubItem = 1;
ListView_SetItem(hListProcess, &vitem);
//剩下的事件叫LVM_SetItem
vitem.pszText = TEXT("56590000");
vitem.iItem = 0;
vitem.iSubItem = 2;
ListView_SetItem(hListProcess, &vitem);
vitem.pszText = TEXT("000F0000");
vitem.iItem = 0;
vitem.iSubItem = 3;
ListView_SetItem(hListProcess, &vitem);
vitem.pszText = TEXT("winlogon.exe");
vitem.iItem = 1;
vitem.iSubItem = 0;
//ListView_InsertItem(hListProcess, &vitem);
SendMessage(hListProcess, LVM_INSERTITEM,0,(DWORD)&vitem);
vitem.pszText = TEXT("456");
vitem.iSubItem = 1;
ListView_SetItem(hListProcess, &vitem);
vitem.pszText = TEXT("10000000");
vitem.iSubItem = 2;
ListView_SetItem(hListProcess, &vitem);
vitem.pszText = TEXT("000045800");
vitem.iSubItem = 3;
ListView_SetItem(hListProcess, &vitem);
3.WM_NOTIFY消息类型
前面我们使用按钮子窗口的时候,消息处理函数中对于按钮的消息类型是WM_COMMAND
但是在这里,我们想要发送对于List控件的消息时,明显无法实现许多参数的传参
因此这里我们使用WM_NOTIFY消息类型
WM_NOTIFY消息类型特点:
1.该消息类型与WM_COMMAND类型相似,都是由子窗口向父窗口发送的消息。
2.WM_NOTIFY可以包含比WM_COMMAND更丰富的信息
3.Windows通用组件中有很多消息,都是通过WM_NOTIFY来描述的.
4.作业
画出PETools的第一个界面
// LordPE.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "resource.h"
#include <commctrl.h>
#pragma comment(lib,"comctl32.lib")
void EnumProcess(HWND hListProcess)
{
LV_ITEM vitem;
//初始化
memset(&vitem,0,sizeof(LV_ITEM));
vitem.mask = LVIF_TEXT;
vitem.pszText = "csrss.exe";
vitem.iItem = 0;
vitem.iSubItem = 0;
//ListView_InsertItem(hListProcess, &vitem);
SendMessage(hListProcess, LVM_INSERTITEM,0,(DWORD)&vitem);
vitem.pszText = TEXT("448");
vitem.iItem = 0;
vitem.iSubItem = 1;
ListView_SetItem(hListProcess, &vitem);
vitem.pszText = TEXT("56590000");
vitem.iItem = 0;
vitem.iSubItem = 2;
ListView_SetItem(hListProcess, &vitem);
vitem.pszText = TEXT("000F0000");
vitem.iItem = 0;
vitem.iSubItem = 3;
ListView_SetItem(hListProcess, &vitem);
vitem.pszText = TEXT("winlogon.exe");
vitem.iItem = 1;
vitem.iSubItem = 0;
//ListView_InsertItem(hListProcess, &vitem);
SendMessage(hListProcess, LVM_INSERTITEM,0,(DWORD)&vitem);
vitem.pszText = TEXT("456");
vitem.iItem = 1;
vitem.iSubItem = 1;
ListView_SetItem(hListProcess, &vitem);
vitem.pszText = TEXT("10000000");
vitem.iItem = 1;
vitem.iSubItem = 2;
ListView_SetItem(hListProcess, &vitem);
vitem.pszText = TEXT("000045800");
vitem.iItem = 1;
vitem.iSubItem = 3;
ListView_SetItem(hListProcess, &vitem);
}
void EnumModule(HWND hListProcess,HWND hListModule,WPARAM wParam,LPARAM lParam)
{
DWORD row;
LV_ITEM item;
TCHAR szName[0x20];
TCHAR szImageBase[0x20];
memset(&item,0,sizeof(LV_ITEM));
memset(szName,0,0x20);
row=SendMessage(hListProcess,LVM_GETNEXTITEM,-1,LVNI_SELECTED);
if(row<0)
{
MessageBox(NULL,TEXT("请选择进程"),TEXT("ERROR"),MB_OK);
return ;
}
item.iSubItem=0; //这部分我们将数据存入szName中 0表示第一列
item.pszText=szName;
item.cchTextMax=0x20;
SendMessage(hListProcess,LVM_GETITEMTEXT,row,(DWORD)&item);
item.iSubItem=2; //这部分是将数据存入szImageBse中 2表示第3列
item.pszText=szImageBase;
item.cchTextMax=0x20;
SendMessage(hListProcess,LVM_GETITEMTEXT,row,(DWORD)&item);
item.mask = LVIF_TEXT;
item.pszText =szName; //这部分是将数据新增入表
item.iItem = 0; //代表行数
item.iSubItem = 0; //代表列数
//ListView_InsertItem(hListProcess, &vitem);
SendMessage(hListModule, LVM_INSERTITEM,0,(DWORD)&item);
//这里我们要注意,只有第一列的消息类型用LVM_INSERTITEM
item.pszText =szImageBase; //这部分是将数据新增入表
item.iItem = 0;
item.iSubItem = 1;
//ListView_InsertItem(hListProcess, &vitem);
ListView_SetItem(hListModule, &item);
}
void InitProcess(HWND hwndDlg)
{
LV_COLUMN lv;
HWND hListProcess;
memset(&lv,0,sizeof(LV_COLUMN));//
hListProcess=GetDlgItem(hwndDlg,IDC_LIST_PROCESS);
SendMessage(hListProcess,LVM_SETEXTENDEDLISTVIEWSTYLE,LVS_EX_FULLROWSELECT,LVS_EX_FULLROWSELECT);
lv.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
lv.pszText = TEXT("进程"); //列标题
lv.cx = 200; //列宽
lv.iSubItem = 0;
//ListView_InsertColumn(hListProcess, 0, &lv);
SendMessage(hListProcess,LVM_INSERTCOLUMN,0,(DWORD)&lv);
//第二列
lv.pszText = TEXT("PID");
lv.cx = 100;
lv.iSubItem = 1;
//ListView_InsertColumn(hListProcess, 1, &lv);
SendMessage(hListProcess,LVM_INSERTCOLUMN,1,(DWORD)&lv);
//第三列
lv.pszText = TEXT("镜像基址");
lv.cx = 100;
lv.iSubItem = 2;
ListView_InsertColumn(hListProcess, 2, &lv);
//第四列
lv.pszText = TEXT("镜像大小");
lv.cx = 100;
lv.iSubItem = 3;
ListView_InsertColumn(hListProcess, 3, &lv);
EnumProcess(hListProcess);
}
void InitModule(HWND hwndDlg)
{
LV_COLUMN lv;
HWND hListModule;
memset(&lv,0,sizeof(LV_COLUMN));
hListModule=GetDlgItem(hwndDlg,IDC_LIST_MODULE);
SendMessage(hListModule,LVM_SETEXTENDEDLISTVIEWSTYLE,LVS_EX_FULLROWSELECT,LVS_EX_FULLROWSELECT);
lv.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
lv.pszText = TEXT("模块名称"); //列标题
lv.cx = 300; //列宽
lv.iSubItem = 0;
//ListView_InsertColumn(hListProcess, 0, &lv);
SendMessage(hListModule,LVM_INSERTCOLUMN,0,(DWORD)&lv);
//第二列
lv.pszText = TEXT("模块位置");
lv.cx = 300;
lv.iSubItem = 1;
ListView_InsertColumn(hListModule, 2, &lv);
}
BOOL CALLBACK DialogProc(
HWND hwndDlg, // handle to dialog box
UINT uMsg, // message
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
switch(uMsg)
{
case WM_NOTIFY:
{
NMHDR* pHMHRD=(NMHDR*)lParam;
if(wParam==IDC_LIST_PROCESS && pHMHRD->code==NM_CLICK)
{
EnumModule(GetDlgItem(hwndDlg,IDC_LIST_PROCESS),GetDlgItem(hwndDlg,IDC_LIST_MODULE),wParam,lParam);
}
break;
}
case WM_CLOSE:
{
EndDialog(hwndDlg,0);
break;
}
case WM_INITDIALOG :
{
InitProcess(hwndDlg);
InitModule(hwndDlg);
return TRUE;
}
case WM_COMMAND :
switch (LOWORD (wParam))
{
case IDC_BUTTON_ABOUT:
return TRUE;
case IDC_BUTTON_EXIT:
EndDialog(hwndDlg, 0);
return TRUE;
}
break;
}
return FALSE;
}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
INITCOMMONCONTROLSEX control;
control.dwSize=sizeof(INITCOMMONCONTROLSEX);
control.dwICC=ICC_WIN95_CLASSES;
InitCommonControlsEx(&control);
DialogBox(hInstance, MAKEINTRESOURCE (IDD_DIALOG_MAIN),NULL,DialogProc);
return 0;
}
思路:
我们此时已经创建好了对话框和通用组建
首先我们定义对于Process和Module的类型名称初始化函数
初始化类型名称时使用LV_COLUMN结构体,此结构用于创建和操作列
向列表中添加数据时,我们使用LV_ITEM结构体,指定或接收列表视图项的属性
在case WM_INITDIALOG:中调用这两个函数
我们使用WM_NOTIFY消息类型来处理对于List通用控件的操作(因为该消息类型能够传递更多参数)
WM_NOTIFY中,回调函数的两个附带参数:wParam、lParam
wParam:表示控件ID
lParam:指向一个结构体
WM_COMMAND中,回调函数的参数:wParam
wParam:低两位表示控件ID
在case WM_NOTIFY中,我们可以根据这两个参数进行操作的判断
如果符合,就调用遍历Process并在Module上显示的函数
此时我们定义函数EnumModule,需要使用的参数先不确定,后面需要时我们再添加
1.首先我们定义两个数组,用来存储待会需要保存的进程名和imageBase
2.row=SendMessage(hListProcess,LVM_GETNEXTITEM,-1,LVNI_SELECTED);告诉编译器我们操作的是哪行
3.
这个代码是将我们鼠标操作的位置的内容存入我们创建的空间中
这里通过实验发现,我们想通过改变item(行数)来选择其他行数是无法实现的,
大概猜测是前面使用了SendMessage函数的缘故,编译器知道我们所选的行数
这里我们通过iSubItem来选择不同的列数 进行存储