深入学习Win32(二)
字数 1234 2025-08-07 08:22:29
Win32编程深入教程:标准控件、通用控件与多线程编程
标准控件
Windows标准控件总是可用的,包括:
- Static
- Group Box
- Button
- Check Box
- Radio Button
- Edit
- ComboBox
- ListBox
通用控件
Windows通用控件代码包含在Comctrl32.dll中,包括:
- Animation
- ComboBoxEx
- Date_and_Time_Picker
- 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
- ToolTip
- Trackbar
- TreeView
- Up_and_Down
通用控件使用步骤
- 包含头文件和库文件:
#include <commctrl.h>
#pragma comment(lib,"comctl32.lib")
- 初始化通用控件:
INITCOMMONCONTROLSEX icex;
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_WIN95_CLASSES;
InitCommonControlsEx(&icex);
- 初始化列名信息(以ListView为例):
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);
// 添加列
lv.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
lv.pszText = TEXT("进程");
lv.cx = 150;
lv.iSubItem = 0;
SendMessage(hListProcess, LVM_INSERTCOLUMN, 0, (DWORD)&lv);
// 添加更多列...
}
- 向控件添加数据:
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;
SendMessage(hListProcess, LVM_INSERTITEM, 0, (DWORD)&vitem);
// 添加更多数据...
}
WM_NOTIFY消息
WM_NOTIFY消息与WM_COMMAND类似,都是由子窗口向父窗口发送的消息,但可以包含更丰富的信息。
参数解析
WM_NOTIFY
idCtrl = (int)wParam; // 控件ID
pnmh = (LPNMHDR)lParam; // 指向NMHDR结构体
NMHDR结构体:
typedef struct tagNMHDR {
HWND hwndFrom; // 发送通知消息的控制窗口句柄
UINT idFrom; // 发送通知消息的控制ID值
UINT code; // 通知码,如LVM_SELCHANGED
} NMHDR;
消息处理示例
case WM_NOTIFY: {
NMHDR* pNMHDR = (NMHDR*)lParam;
if (wParam == IDC_LIST_PROCESS && pNMHDR->code == NM_CLICK) {
EnumModules(GetDlgItem(hDlg, IDC_LIST_PROCESS), wParam, lParam);
}
break;
}
多线程编程
线程基础
一个进程中至少有一个线程。线程由Windows内核负责创建与管理:
- 线程句柄:相当于令牌,用于使用线程对象
- 线程ID:唯一的标识符,系统进行线程调度时使用
创建线程
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes, // 安全属性,通常为NULL
SIZE_T dwStackSize, // 线程堆栈大小
LPTHREAD_START_ROUTINE lpStartAddress, // 线程函数地址
LPVOID lpParameter, // 线程函数参数
DWORD dwCreationFlags, // 0:立即调度;CREATE_SUSPENDED:创建后挂起
LPDWORD lpThreadId // 线程ID(out类型参数)
);
示例:
HANDLE hThread = ::CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
::CloseHandle(hThread); // 关闭句柄,线程仍在运行
线程控制
- 挂起线程:
::SuspendThread(hThread);
- 恢复线程:
::ResumeThread(hThread);
- 终止线程:
// 方式1:在线程函数中调用
::ExitThread(DWORD dwExitCode);
// 方式2:线程函数返回
return 0;
// 方式3:从外部终止线程
::TerminateThread(hThread, 2);
::WaitForSingleObject(hThread, INFINITE); // 等待线程结束
线程CONTEXT对象
CONTEXT结构体包含特定处理器的寄存器数据,用于保存和恢复线程状态:
typedef struct _CONTEXT {
DWORD ContextFlags; // 要获取的寄存器类型
DWORD Dr0; // 调试寄存器
// ... 其他寄存器
} CONTEXT;
获取和设置线程CONTEXT:
// 挂起线程
SuspendThread(hThread);
CONTEXT context;
context.ContextFlags = CONTEXT_CONTROL;
BOOL ok = ::GetThreadContext(hThread, &context);
// 修改CONTEXT
context.Eip = 0x401000;
// 设置CONTEXT
SetThreadContext(hThread, &context);
// 恢复线程
ResumeThread(hThread);
线程安全与临界区
线程安全的本质是多个线程操作同一块资源时的同步控制。
使用临界区:
// 创建临界区
CRITICAL_SECTION cs;
// 初始化临界区
InitializeCriticalSection(&cs);
// 使用临界区
EnterCriticalSection(&cs);
// 访问共享资源
LeaveCriticalSection(&cs);
// 销毁临界区
DeleteCriticalSection(&cs);
等待函数
- WaitForSingleObject:
DWORD WaitForSingleObject(
HANDLE hHandle, // 内核对象的句柄
DWORD dwMilliseconds // 等待时间(毫秒),INFINITE表示无限等待
);
- WaitForMultipleObjects:
DWORD WaitForMultipleObjects(
DWORD nCount, // 内核对象数量
CONST HANDLE *lpHandles, // 内核对象数组
BOOL bWaitAll, // TRUE:等待所有对象;FALSE:等待任一对象
DWORD dwMilliseconds // 超时时间
);
互斥体
互斥体是内核对象,可用于跨进程线程控制:
// 创建互斥体
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes, // 安全属性
BOOL bInitialOwner, // 初始拥有者
LPCTSTR lpName // 互斥体名称
);
// 进入互斥区
WaitForSingleObject(g_hMutex, INFINITE);
// 离开互斥区
ReleaseMutex(g_hMutex);
// 关闭互斥体句柄
CloseHandle(g_hMutex);
事件对象
事件对象用于线程同步:
// 创建事件
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes, // 安全属性
BOOL bManualReset, // TRUE:手动复位;FALSE:自动复位
BOOL bInitialState, // 初始状态(TRUE:已通知;FALSE:未通知)
LPCTSTR lpName // 事件名称
);
// 设置事件为已通知状态
SetEvent(hEvent);
// 重置事件为未通知状态
ResetEvent(hEvent);
信号量
信号量用于控制资源访问数量:
// 创建信号量
HANDLE CreateSemaphore(
LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, // 安全属性
LONG lInitialCount, // 初始资源数量
LONG lMaximumCount, // 最大资源数量
LPCTSTR lpName // 信号量名称
);
// 等待信号量
WaitForSingleObject(hSemaphore, INFINITE);
// 释放信号量
ReleaseSemaphore(hSemaphore, 1, NULL);
进程创建
进程创建步骤:
- 创建内核对象
- 分配4GB虚拟空间
- 创建进程的主线程
使用CreateProcess创建进程:
BOOL CreateProcess(
PCTSTR pszApplicationName, // 应用程序名
PTSTR pszCommandLine, // 命令行参数
PSECURITY_ATTRIBUTES psaProcess, // 进程安全属性
PSECURITY_ATTRIBUTES psaThread, // 线程安全属性
BOOL bInheritHandles, // 是否继承句柄
DWORD fdwCreate, // 创建标志
PVOID pvEnvironment, // 环境变量
PCTSTR pszCurDir, // 当前目录
PSTARTUPINFO psiStartInfo, // 启动信息
PPROCESS_INFORMATION ppiProcInfo // 进程信息
);
进程信息结构体:
typedef struct _PROCESS_INFORMATION {
HANDLE hProcess; // 进程句柄
HANDLE hThread; // 主线程句柄
DWORD dwProcessId; // 进程ID
DWORD dwThreadId; // 线程ID
} PROCESS_INFORMATION;
总结
- 标准控件:Windows内置的基本控件,无需额外初始化
- 通用控件:需要加载comctl32.dll并初始化,功能更丰富
- 多线程编程:
- 使用CreateThread创建线程
- 通过临界区、互斥体、事件和信号量实现线程同步与互斥
- 使用WaitForSingleObject和WaitForMultipleObjects管理线程执行
- 进程创建:使用CreateProcess创建新进程,可控制进程属性和启动参数
掌握这些Win32编程核心概念和技术,可以开发出功能强大、性能优越的Windows应用程序。