需求如下: 当配置文件发生改变时,广播配置信息给所有的进程,通知其重装配置.
1. WM_COPYDATA传递消息
windows下最简单进程通信方式,利用WM_COPYDATA事件, 该事件能够传递一指针来携带消息.
// 查找标题为Sample的窗口,向其发送一字符串 HWND hWnd = FindWindowW(NULL, "Sample"); if (hWnd != NULL) { this->setWindowTitle("dialog_send"); char szMsg[512]; strcpy(szMsg,"hello world"); COPYDATASTRUCT cpd; cpd.dwData = 0; cpd.cbData = strlen(szMsg); cpd.lpData = szMsg; // 同步发送消息 SendMessageW(hWnd, WM_COPYDATA, NULL, (LPARAM)&cpd); }
这里就有一个问题,WM_COPYDATA消息,只能使用 SendMessage (同步发送消息,必须等待消息被处理完成才返回), 不能使用PostMessage(异步), 这样远远达不到实时要求. 测试了一下,发现大部分消息都只能采样同步方式发送, WM_CLEAR / WM_NOTIFYFORMAT / WM_USER / WM_DEVICECHANGE 等消息可以通过异步发送.
在不同进程之间传递一指针,各个进程其对应指针地址不同, 不可能取到相应字符串的值. 实际上WM_COPYDATA内部实现也用到共享内存, 那我们采用 windows消息通知 + 共享内存 来实现通知重装配置功能.
2. windows 广播消息
/** * windows 下提供了强大的广播消息函数,可以向网络驱动,应用程序,安装的驱动,系统级设备及组件发送消息 */ DWORD bsm_app=BSM_APPLICATIONS; // 向所有应用程序发送消息 BroadcastSystemMessage(BSF_POSTMESSAGE,&bsm_app,WM_NOTIFYFORMAT,NULL,NULL);
3. windows下共享内存
服务端:
#include <windows.h> #include <stdio.h> #define MY_MEMORY_ID "kettas" int main(int argc,char **argv) { /** * 创建命名为kettas的共享内存 * dwMaximumSizeLow 映射对象低位最大尺寸设置为0时, xp下创建失败,这里设置为1024 */ HANDLE lhShareMemory = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,1024,MY_MEMORY_ID); if (lhShareMemory !=NULL) { printf("信息:共享数据打开失败"); return 1; } LPVOID buff; buff = MapViewOfFile(lhShareMemory,FILE_MAP_WRITE,0,0,0); // 获取映射对象地址 // strcpy(strBuffer,"hello kettas"); // 写入数据 char *str="Hello world"; CopyMemory((PVOID)buff,str,strlen(str)); // 写入数据 UnmapViewOfFile((PVOID)buff); getchar(); return 0; }
客户端:
#include <windows.h> #include <stdio.h> #define MY_MEMORY_ID "kettas" int main(int argc,char **argv) { HANDLE handleFile; handleFile= OpenFileMapping(FILE_MAP_ALL_ACCESS,false,MY_MEMORY_ID); //打开共享文件 if (handleFile==NULL) { printf("共享数据打开失败\n"); return 1; } char * str = NULL; str=(char *) MapViewOfFile(handleFile,FILE_MAP_ALL_ACCESS,0,0,0); // 获取共享对象数据 printf("结果:%s",str); UnmapViewOfFile(str); CloseHandle(handleFile); getchar(); return 0; }
当配置发生改变时, 服务端将数据写入共享内存,然后广播通知其它进程去共享内存中获取相应数据. 对于QT控制台程序,利用上往篇讲的, 新建一窗口后隐藏即可
/** * @brief 获取广播消息 * @parm MRev 消息回调函数 */ void GetNoticeMessage( MRev mRev ) { if(mRev==NULL) { printf("错误:回调函数为空\n"); return; } // 全局指针赋值 GRevHandler=mRev; #ifdef WIN32 hinstance = (HINSTANCE)GetModuleHandle(NULL); if (!InitApplication(hinstance)) { printf("错误:注册窗口失败\n"); return; } if (!InitInstance(hinstance, SW_HIDE)) // 隐藏窗口 { printf("错误:新建窗口失败\n"); return; } #elif __unix // 安装消息 InstallMessage(); #endif }