进程间消息发送异常:PostMessage等报错,SendMessage无响应
解决进程间WM_COPYDATA发送问题:ERROR_MESSAGE_SYNC_ONLY及SendMessage无响应
先帮你拆解一下问题的核心原因,再一步步修复:
1. 为什么PostMessage/SendNotifyMessage触发ERROR_MESSAGE_SYNC_ONLY?
这是正常现象。你用的HWND_MESSAGE是消息-only窗口的父窗口,这类窗口的设计初衷就是只接收同步消息(SendMessage),异步消息(PostMessage、SendNotifyMessage)会被系统直接拒绝,所以报错是符合预期的,不用在这两个函数上浪费时间,专注解决SendMessage的问题即可。
2. SendMessage返回0且GetLastError返回ERROR_ENVVAR_NOT_FOUND的原因
你的代码有两个关键问题:
- 接收端没有注册自定义窗口类,直接用不存在的
"Message"类创建窗口,导致窗口创建失败(hWnd为NULL),发送端根本找不到目标窗口。 - 接收端的消息循环没有正确分发消息,即使窗口创建成功,
WM_COPYDATA也不会被处理。
修复步骤及完整代码
接收端(进程0)修复
首先必须注册自定义窗口类,并在窗口过程中处理WM_COPYDATA消息,同时使用标准消息循环:
#include <windows.h> #include <stdio.h> // 窗口过程,处理WM_COPYDATA消息 LRESULT CALLBACK MessageWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_COPYDATA: { COPYDATASTRUCT* pData = (COPYDATASTRUCT*)lParam; if (pData->dwData == 0 && pData->cbData > 0) { printf("Received message: %s\n", (char*)pData->lpData); } return TRUE; // 必须返回TRUE表示处理成功 } case WM_DESTROY: PostQuitMessage(0); return 0; default: return DefWindowProcA(hWnd, uMsg, wParam, lParam); } } int main() { // 注册窗口类 WNDCLASSEXA wc = {0}; wc.cbSize = sizeof(WNDCLASSEXA); wc.lpfnWndProc = MessageWindowProc; wc.hInstance = GetModuleHandleA(NULL); wc.lpszClassName = "Message"; // 自定义类名,和发送端匹配 if (!RegisterClassExA(&wc)) { printf("Failed to register window class! Error: %d\n", GetLastError()); return 1; } // 创建消息-only窗口 HWND hWnd = CreateWindowExA( 0, "Message", // 用刚才注册的类名 "serverwindow", // 窗口标题,和发送端匹配 0, 0, 0, 0, 0, HWND_MESSAGE, // 消息-only窗口的父窗口 NULL, GetModuleHandleA(NULL), NULL ); if (!hWnd) { printf("Failed to create window! Error: %d\n", GetLastError()); return 1; } printf("Server window created, waiting for messages...\n"); // 标准消息循环 MSG msg; while (GetMessage(&msg, NULL, 0, 0) > 0) { TranslateMessage(&msg); DispatchMessage(&msg); // 必须调用这个,窗口过程才会执行 } return 0; }
发送端(进程1)修复
增加窗口句柄有效性检查,确保找到目标窗口后再发送消息:
#include <windows.h> #include <stdio.h> int main() { // 查找消息-only窗口 HWND hWndTarget = FindWindowExA( HWND_MESSAGE, NULL, "Message", // 匹配接收端的类名 "serverwindow" // 匹配接收端的窗口标题 ); if (!hWndTarget) { printf("Failed to find target window! Error: %d\n", GetLastError()); return 1; } // 构造WM_COPYDATA数据 const char* data = "localhost"; COPYDATASTRUCT cds = { .dwData = 0, .cbData = strlen(data) + 1, // 包含末尾的\0 .lpData = (void*)data }; // 发送消息 LRESULT result = SendMessageA(hWndTarget, WM_COPYDATA, (WPARAM)GetConsoleWindow(), (LPARAM)&cds); if (result == FALSE) { printf("SendMessage failed! Error: %d\n", GetLastError()); } else { printf("Message sent successfully!\n"); } return 0; }
关键修复点说明
- 注册窗口类:Windows没有默认的
"Message"窗口类,必须自行注册并指定窗口过程,否则CreateWindowExA会失败。 - 处理WM_COPYDATA:这个消息必须在窗口过程中处理,且返回
TRUE表示成功接收,否则系统会认为消息未被处理。 - 标准消息循环:原来的
Sleep(500)+PeekMessage没有调用DispatchMessage,导致窗口过程永远不会被触发,消息无法被处理。 - 窗口句柄检查:发送端必须确保找到有效的目标窗口,否则
SendMessage传入NULL会返回0,同时可能出现奇怪的错误码(比如ERROR_ENVVAR_NOT_FOUND)。
内容的提问来源于stack exchange,提问作者AnArrayOfFunctions
相关产品推荐
相关产品推荐

