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

news/2024/11/24 9:43:33/

在本专栏上一篇文章中带领大家学习了对话框的创建,并且在项目中创建出了对话框。在这一篇文章中,我将带领大家学习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 <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
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;       //发送通知消息的控件IDUINT 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结构体,我们来看看这个结构体:
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.

在写入了入口函数,并且加载了主对话框之后,我们运行,发现程序页面已经出来了:
程序页面

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;}//获取PIDlv.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 <CommCtrl.h>
#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;}//获取PIDlv.iSubItem = 1;lv.pszText = szPid;lv.cchTextMax = 0x20;SendMessage(hListProcess, LVM_GETITEMTEXT, dwRowId, (DWORD)&lv);MessageBox(NULL, szPid, TEXT("PID"), MB_OK);
}

程序效果:
程序效果

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


http://www.ppmy.cn/news/78241.html

相关文章

3.5 RDD持久化机制

一、RDD持久化 1、不采用持久化操作 查看要操作的HDFS文件 以集群模式启动Spark Shell 按照图示进行操作&#xff0c;得RDD4和RDD5 查看RDD4内容&#xff0c;会从RDD1到RDD2到RDD3到RDD4跑一趟 显示RDD5内容&#xff0c;也会从RDD1到RDD2到RDD3到RDD5跑一趟 2、采用持久化…

Flutter项目webview加载没有HTTPS证书的网页在Android和iOS设备上无法显示的解决方案

一、问题描述 Flutter项目使用谷歌官方webview库 webview_flutter&#xff0c;加载自签名证书、证书失效、无证书等HTTPS网页地址时&#xff0c;在Android或pc浏览器中提示证书失效&#xff0c;在iOS设备上为空白页&#xff0c;为了加载自签名证书的网页&#xff0c;需要饶过i…

后端SpringBoot应用向云原生K8S平台迁移

目录 一、引言二、方式1&#xff1a;在K8S上部署Spring Cloud Alibaba三、方式2&#xff1a;在K8S上部署Spring Cloud K8S3.1 第1次优化&#xff1a;移除Spring Cloud K8S DiscoveryClient 四、方式3&#xff1a;在K8S上部署SpringBoot应用4.1 第2次优化&#xff1a;移除Spring…

5月第3周榜单丨飞瓜数据B站UP主排行榜单(哔哩哔哩)发布!

飞瓜轻数发布2023年5月15日-5月21日飞瓜数据UP主排行榜&#xff08;B站平台&#xff09;&#xff0c;通过充电数、涨粉数、成长指数三个维度来体现UP主账号成长的情况&#xff0c;为用户提供B站号综合价值的数据参考&#xff0c;根据UP主成长情况用户能够快速找到运营能力强的B…

静态时序分析-时序检查

时序检查 一旦在触发器的时钟引脚上定义了时钟,便会自动推断出该触发器的建立时间和保持时间检查。时序检查通常会在多个条件下执行,通常,最差情况的慢速条件对于建立时间检查很关键,而最佳情况的快速条件对于保持时间检查很关键。 1.建立时间检查 在时钟的有效沿到达触…

Python爬虫入门案例6:scrapy的基本语法+使用scrapy进行网站数据爬取

几天前在本地终端使用pip下载scrapy遇到了很多麻烦&#xff0c;总是报错&#xff0c;花了很长时间都没有解决&#xff0c;最后发现pycharm里面自带终端&#xff01;&#xff08;狂喜&#xff09;&#xff0c;于是直接在pycharm终端里面写scrapy了 这样的好处就是每次不用切换路…

当前社会下,软件测试工程师如何提高竞争力应对变局?

当前社会大家压力都很大&#xff0c;但唯独不变的&#xff0c;笔者还是认为大家要提高自己的技能能力&#xff0c;提高自己&#xff0c;以不变应万变&#xff01;&#xff01;软件测试在工作中可以从如下方面提高自己&#xff1a; 1. 想客户之所想 在测试的过程中时刻想着用户…

设计模式 - 工厂模式

简单工厂模式 基本介绍: 简单工厂模式是属于创建型模式&#xff0c;是工厂模式的一种。简单工厂模式是由一 个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族 中最简单实用的模式简单工厂模式&#xff1a;定义了一个创建对象的类&#xff0c;由这个类来封…