深入学习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

通用控件使用步骤

  1. 包含头文件和库文件:
#include <commctrl.h>
#pragma comment(lib,"comctl32.lib")
  1. 初始化通用控件:
INITCOMMONCONTROLSEX icex;
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_WIN95_CLASSES;
InitCommonControlsEx(&icex);
  1. 初始化列名信息(以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);
    
    // 添加更多列...
}
  1. 向控件添加数据:
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);  // 关闭句柄,线程仍在运行

线程控制

  1. 挂起线程:
::SuspendThread(hThread);
  1. 恢复线程:
::ResumeThread(hThread);
  1. 终止线程:
// 方式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);

等待函数

  1. WaitForSingleObject:
DWORD WaitForSingleObject(
    HANDLE hHandle,      // 内核对象的句柄
    DWORD dwMilliseconds // 等待时间(毫秒)INFINITE表示无限等待
);
  1. 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);

进程创建

进程创建步骤:

  1. 创建内核对象
  2. 分配4GB虚拟空间
  3. 创建进程的主线程

使用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;

总结

  1. 标准控件:Windows内置的基本控件,无需额外初始化
  2. 通用控件:需要加载comctl32.dll并初始化,功能更丰富
  3. 多线程编程
    • 使用CreateThread创建线程
    • 通过临界区、互斥体、事件和信号量实现线程同步与互斥
    • 使用WaitForSingleObject和WaitForMultipleObjects管理线程执行
  4. 进程创建:使用CreateProcess创建新进程,可控制进程属性和启动参数

掌握这些Win32编程核心概念和技术,可以开发出功能强大、性能优越的Windows应用程序。

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 通用控件使用步骤 包含头文件和库文件: 初始化通用控件: 初始化列名信息(以ListView为例): 向控件添加数据: WM_ NOTIFY消息 WM_ NOTIFY消息与WM_ COMMAND类似,都是由子窗口向父窗口发送的消息,但可以包含更丰富的信息。 参数解析 NMHDR结构体: 消息处理示例 多线程编程 线程基础 一个进程中至少有一个线程。线程由Windows内核负责创建与管理: 线程句柄:相当于令牌,用于使用线程对象 线程ID:唯一的标识符,系统进行线程调度时使用 创建线程 示例: 线程控制 挂起线程: 恢复线程: 终止线程: 线程CONTEXT对象 CONTEXT结构体包含特定处理器的寄存器数据,用于保存和恢复线程状态: 获取和设置线程CONTEXT: 线程安全与临界区 线程安全的本质是多个线程操作同一块资源时的同步控制。 使用临界区: 等待函数 WaitForSingleObject: WaitForMultipleObjects: 互斥体 互斥体是内核对象,可用于跨进程线程控制: 事件对象 事件对象用于线程同步: 信号量 信号量用于控制资源访问数量: 进程创建 进程创建步骤: 创建内核对象 分配4GB虚拟空间 创建进程的主线程 使用CreateProcess创建进程: 进程信息结构体: 总结 标准控件 :Windows内置的基本控件,无需额外初始化 通用控件 :需要加载comctl32.dll并初始化,功能更丰富 多线程编程 : 使用CreateThread创建线程 通过临界区、互斥体、事件和信号量实现线程同步与互斥 使用WaitForSingleObject和WaitForMultipleObjects管理线程执行 进程创建 :使用CreateProcess创建新进程,可控制进程属性和启动参数 掌握这些Win32编程核心概念和技术,可以开发出功能强大、性能优越的Windows应用程序。