Windows相关
消息队列
PostMessage
- 将消息异步发送到指定窗口的消息队列
目标窗口可以是同一进程或不同进程的窗口 - 只要发送方持有目标窗口的有效句柄(
HWND
),即可跨进程发送消息 - 场景:
例如通知其他进程的窗口更新界面或执行特定操作
例如结合WM_COPYDATA
消息传递小型数据块(最大约64KB
)
- 将消息异步发送到指定窗口的消息队列
1 2 3 4 5 6 |
// 发送方(跨进程) COPYDATASTRUCT cds; cds.dwData = 1; // 自定义标识 cds.cbData = sizeof(data); // 数据大小 cds.lpData = &data; // 数据指针 PostMessage(hTargetWnd, WM_COPYDATA, (WPARAM)hSenderWnd, (LPARAM)&cds); |
PostThreadMessage
- 将消息异步发送到指定线程的消息队列。目标线程无需关联窗口,但必须已创建消息队列
- 需知道目标线程的 线程
ID
(DWORD
),且目标线程已调用过消息循环函数(如GetMessage
) - 场景:
后台线程通信:与无窗口的后台线程交互(如日志线程、工作线程)
自定义消息协议:定义线程专用的消息类型(需注册自定义消息)
1 2 3 4 5 6 7 8 9 10 11 |
// 发送方(跨进程) DWORD dwTargetThreadId = ...; // 通过共享内存或其他IPC获取目标线程ID PostThreadMessage(dwTargetThreadId, WM_MY_THREAD_MSG, 0, 0); // 接收方线程(需运行消息循环) MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { if (msg.message == WM_MY_THREAD_MSG) { // 处理消息 } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// 发送端(需接收窗口句柄) COPYDATASTRUCT cpd; cpd.dwData = 1; // 自定义标识 cpd.cbData = strlen("Test Message") + 1; cpd.lpData = (void*)"Test Message"; SendMessage(hWndReceiver, WM_COPYDATA, (WPARAM)hWndSender, (LPARAM)&cpd); // 接收端(窗口过程函数中处理) case WM_COPYDATA: { COPYDATASTRUCT* pcds = (COPYDATASTRUCT*)lParam; char* msg = (char*)pcds->lpData; MessageBox(NULL, msg, "Received", MB_OK); break; } |
信号量
- 作用
- 协调多进程对共享资源的访问
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
// 进程A(资源生产者) #include <Windows.h> #include <stdio.h> #define SEM_NAME "Global\\MySemaphore" int main() { // 创建初始值为0、最大值为3的命名信号量 HANDLE hSem = CreateSemaphore(NULL, 0, 3, SEM_NAME); if (hSem == NULL) { printf("CreateSemaphore error: %d\n", GetLastError()); return 1; } // 模拟生产资源 for (int i = 1; i <= 5; ++i) { Sleep(1000); ReleaseSemaphore(hSem, 1, NULL); // 每次释放1个资源 printf("Produced resource %d\n", i); } CloseHandle(hSem); return 0; } // 进程B(资源消费者) #include <Windows.h> #include <stdio.h> int main() { HANDLE hSem = OpenSemaphore(SYNCHRONIZE | SEMAPHORE_MODIFY_STATE, FALSE, SEM_NAME); if (hSem == NULL) { printf("OpenSemaphore error: %d\n", GetLastError()); return 1; } while (1) { WaitForSingleObject(hSem, INFINITE); // 等待资源 printf("Consumed resource\n"); // 处理资源... } CloseHandle(hSem); return 0; } |
互斥量
- 作用
- 协调多进程对共享资源的访问
1 2 3 4 |
// 创建命名互斥量 HANDLE hMutex = CreateMutex(NULL, FALSE, L"Global\\MyMutex"); WaitForSingleObject(hMutex, INFINITE); // 等待锁 ReleaseMutex(hMutex); // 释放锁 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
// 进程A(写入端) #include <Windows.h> #include <stdio.h> #define MUTEX_NAME "Global\\MyMutex" int main() { HANDLE hMutex = CreateMutex(NULL, FALSE, MUTEX_NAME); if (hMutex == NULL) { printf("CreateMutex error: %d\n", GetLastError()); return 1; } WaitForSingleObject(hMutex, INFINITE); // 获取锁 printf("Process A entered critical section\n"); // 执行需要互斥的操作... Sleep(3000); ReleaseMutex(hMutex); // 释放锁 printf("Process A released mutex\n"); CloseHandle(hMutex); return 0; } // 进程B(读取端) #include <Windows.h> #include <stdio.h> int main() { HANDLE hMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, MUTEX_NAME); if (hMutex == NULL) { printf("OpenMutex error: %d\n", GetLastError()); return 1; } WaitForSingleObject(hMutex, INFINITE); // 等待锁 printf("Process B entered critical section\n"); // 读取共享数据... Sleep(1000); ReleaseMutex(hMutex); printf("Process B released mutex\n"); CloseHandle(hMutex); return 0; } |
剪贴板
1 2 3 4 5 6 |
OpenClipboard(hWnd); HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, size); memcpy(GlobalLock(hMem), data, size); GlobalUnlock(hMem); SetClipboardData(CF_TEXT, hMem); CloseClipboard(); |
基于内存共享的IPC
文件映射
- 原理
- 将物理文件或虚拟内存映射到多个进程的地址空间,实现数据共享
1 2 3 4 5 6 7 8 9 10 11 12 |
HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // 物理文件句柄(设为虚拟内存) NULL, // 安全属性 PAGE_READWRITE, // 读写权限 0, // 高32位文件大小 BUF_SIZE, // 低32位文件大小 L"Global\\MySharedMem");// 共享内存名(需唯一) LPSTR pBuf = (LPSTR)MapViewOfFile( hMapFile, // 映射对象句柄 FILE_MAP_ALL_ACCESS, // 访问权限 0, 0, BUF_SIZE); // 偏移量和大小 |
- 特点
- 高性能:适用于大数据量传输(如音视频流)
- 需同步机制(如互斥量)避免读写冲突
- 命名共享内存(
Global\\
前缀)支持跨会话访问
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
// 进程A(写入端) #include <windows.h> #define BUF_SIZE 1024 const char* szName = "Global\\MySharedMemory"; // 需管理员权限或去除"Global\\" int main() { // 创建共享内存对象 HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // 使用系统分页文件 NULL, // 默认安全属性 PAGE_READWRITE, // 读写权限 0, BUF_SIZE, szName); // 内存大小和名称 char* pBuf = (char*)MapViewOfFile( hMapFile, // 映射对象句柄 FILE_MAP_ALL_ACCESS, // 读写权限 0, 0, BUF_SIZE); // 偏移量和映射大小 strcpy(pBuf, "Hello from Process A"); // 写入数据 UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; } // 进程B(读取端) // 相同方式打开共享内存后读取: printf("Received: %s", pBuf); // 输出进程A写入的内容 |
堆共享
- 原理
- 通过
HeapCreate
创建共享堆,其他进程通过HeapOpen
访问
- 通过
1 2 3 4 |
// 进程A创建堆 HANDLE hHeap = HeapCreate(HEAP_SHARED, 0, 1024); // 进程B打开堆 HANDLE hHeap = HeapOpen(HEAP_SHARED, FALSE, L"MySharedHeap"); |
- 场景
- 小规模结构化数据共享,需手动管理内存分配
基于消息传递的IPC
邮件槽(Mailslots)
- 原理
- 单向通信机制,支持一对多消息广播
1 2 3 4 5 6 7 8 9 10 11 12 |
// 服务器端创建邮件槽 HANDLE hMailslot = CreateMailslot( L"\\\\.\\mailslot\\MySlot", // 名称格式 0, // 最大消息长度(0=无限制) MAILSLOT_WAIT_FOREVER, // 读取超时 NULL); // 安全属性 // 客户端写入消息 HANDLE hFile = CreateFile( L"\\\\*\\mailslot\\MySlot", // 服务器名(*表示本机) GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); WriteFile(hFile, data, size, &bytesWritten, NULL); |
- 特点
- 支持跨网络通信(需指定服务器名)
- 消息可能丢失(无确认机制)
1 2 3 4 5 6 7 8 9 10 11 12 |
// 服务端(接收) HANDLE hMailslot = CreateMailslot( "\\\\.\\mailslot\\sample", // 名称 0, MAILSLOT_WAIT_FOREVER, NULL); // 无超时 ReadFile(hMailslot, buffer, sizeof(buffer), &bytesRead, NULL); // 客户端(发送) HANDLE hMailslot = CreateFile( "\\\\.\\mailslot\\sample", GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); WriteFile(hMailslot, "Broadcast Msg", 14, &bytesWritten, NULL); |
WM_COPYDATA消息
- 原理
- 通过
SendMessage
发送WM_COPYDATA
消息,传递只读数据块
- 通过
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// 发送方 COPYDATASTRUCT cds; cds.dwData = 1; // 用户定义标识 cds.cbData = sizeof(data); // 数据大小 cds.lpData = &data; // 数据指针 SendMessage(hWndReceiver, WM_COPYDATA, (WPARAM)hWndSender, (LPARAM)&cds); // 接收方(窗口过程) case WM_COPYDATA: { COPYDATASTRUCT* pcds = (COPYDATASTRUCT*)lParam; // 处理pcds->lpData指向的数据 return TRUE; } |
- 限制
- 仅适用于同一用户会话内的窗口通信
- 数据最大约64KB(受
SendMessage
限制)
基于管道(Pipes)的IPC
匿名管道(Anonymous Pipes)
- 原理
- 单向通信,通常用于父子进程间重定向输入输出
- 限制
- 仅支持本地机器上的进程通信
1 2 3 4 5 6 7 8 9 |
HANDLE hReadPipe, hWritePipe; SECURITY_ATTRIBUTES sa = { sizeof(sa), NULL, TRUE }; CreatePipe(&hReadPipe, &hWritePipe, &sa, 0); // 子进程继承句柄(通过STARTUPINFO) STARTUPINFO si = { sizeof(si) }; si.hStdOutput = hWritePipe; si.dwFlags = STARTF_USESTDHANDLES; CreateProcess(..., &si, ...); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// 服务器端(进程A) HANDLE hPipe = CreateNamedPipe( "\\\\.\\pipe\\MyPipe", // 管道名称 PIPE_ACCESS_DUPLEX, // 双向通信 PIPE_TYPE_MESSAGE | PIPE_WAIT, // 消息模式+阻塞 1, // 最大实例数 1024, 1024, 0, NULL); // 输入/输出缓冲区大小 ConnectNamedPipe(hPipe, NULL); // 等待客户端连接 char buffer[1024]; DWORD bytesRead; ReadFile(hPipe, buffer, sizeof(buffer), &bytesRead, NULL); // 读取数据 // 客户端(进程B) HANDLE hPipe = CreateFile( "\\\\.\\pipe\\MyPipe", // 管道名称 GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); WriteFile(hPipe, "Hello from B", 13, NULL, NULL); // 发送数据 |
命名管道(Named Pipes)
- 原理
- 双向通信,支持多客户端连接和异步操作
- 特点
- 支持跨网络通信(
UNC
路径) - 提供安全描述符控制访问权限
- 支持跨网络通信(
- 服务端
1 2 3 4 5 6 7 8 9 10 |
HANDLE hPipe = CreateNamedPipe( L"\\\\.\\pipe\\MyPipe", // 管道名称 PIPE_ACCESS_DUPLEX, // 双向访问 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, // 最大实例数 4096, 4096, // 输入/输出缓冲区大小 0, NULL); // 超时和安全属性 ConnectNamedPipe(hPipe, NULL); // 等待客户端连接 ReadFile(hPipe, buffer, sizeof(buffer), &bytesRead, NULL); |
- 客户端
1 2 3 4 5 |
HANDLE hPipe = CreateFile( L"\\\\.\\pipe\\MyPipe", // 管道名称 GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); WriteFile(hPipe, data, size, &bytesWritten, NULL); |
基于网络的IPC
套接字(Sockets)
- 原理
- 使用
TCP/UDP
协议实现跨机器进程通信
- 使用
- 优势
- 跨平台兼容性(
Windows/Linux/Mac
) - 支持复杂网络拓扑(如
NAT
穿透)
- 跨平台兼容性(
- 示例技术:
- 本地环回地址(
127.0.0.1
)用于本机进程通信 HTTP/WebSocket
:适用于与Web
应用交互
- 本地环回地址(
RPC(Remote Procedure Call)
- 原理
- 通过
IDL
(接口定义语言)生成存根代码,实现远程函数调用
- 通过
- 开发流程
- 编写
IDL
文件定义接口 - 使用
MIDL
编译器生成代理/存根代码 - 服务器实现接口,客户端调用远程方法
- 编写
- 特点
- 支持自动数据类型封送(
Marshaling
) - 集成Windows安全模型(如
Kerberos
认证)
- 支持自动数据类型封送(
本文为原创文章,版权归Aet所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ Socket基础:TCP篇10/16
- ♥ Windbg关于死锁的简单调试分析总结09/13
- ♥ WindowsETW进程监控相关03/17
- ♥ Windows Dll自卸载相关10/19
- ♥ C++_多线程相关03/12
- ♥ Soui五05/30