|
[求助]关于PostThreadMessage能实现进程间通信吗?
晚上没事,想起来了用钩子来验证一下MSDN中对PostThreadMessage的说明,也算是对上面这篇帖子画上一个比较完美的句号。 由于我的进程B是非模态对话框而PostThreadMessage传递的是给线程的消息循环(并没有像SendMessae那样标明窗口句柄),因此其实传递的这个Msg.hwnd==NULL,从而导致消息循环用GetMessage,PeekMessage去给窗口投递消息(DispathMessage)的时候因为Hwnd为NULL而被无情的过滤掉导致在对话框的消息循环中无法接收到对此消息的响应。 MSDN说了用HOOK,知道了产生上述问题的原因,一秒钟的思考就想到了该用WH_GETMESSAGE HOOK来截获。关于这个HOOK,MSDN有说明,这里不罗嗦了。 在实现这个的过程中还是出现了一点小问题,经过调试最后自己得出来了一点看法,已经放在代码中了,不晓得是否正确。。。可能一切都是MessageBox惹的祸,因为这个东西实在特殊 #include<windows.h> #include "resource.h" #define WM_MYMESSAGE WM_USER+1 MSG *msg; HWND hwnd; static HHOOK hGetMessageHook; INT_PTR CALLBACK DialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ); LRESULT CALLBACK GETMESSAGEProc(int nCode,WPARAM wParam,LPARAM lParam) { if(nCode<0) return CallNextHookEx(hGetMessageHook,nCode,wParam,lParam); switch(nCode) { case HC_ACTION: msg=(PMSG)lParam; if(msg->message==WM_MYMESSAGE) { //MessageBox(NULL,TEXT("钩子检测到了来自进程A发送的消息"),TEXT("成功"),MB_OK);//特此说明一下,个人观点,至于对不对请大家多多包涵,如果这里不注释掉这句,下面必须用WM_MYMESSAGE或写成1025,刚开始没注释发现始终没成功,原因可能是这样的:MessageBox比较特殊,自己有自己的消息循环而且又是同处在一个线程消息循环中,所以它自己的消息循环也会有WH_MYMESSAGE钩子,在点击确定按钮之后,MessageBox的消息循环会改变msg的值(因为同样执行了case HC_ACTION:的代码),从而导致了msg->message不再是1025了,因此发送消息才会不成功,这是个人愚见,还望大鸟们给出一下解释或者看看分析的是否正确。。。 SendMessage(hwnd,msg->message/*1025或WM_MYMESSAGE*/,0,0); //用常规的投递消息也可以实现 //msg->hwnd=hwnd; //DispatchMessage(msg); } return 0; } return CallNextHookEx(hGetMessageHook,nCode,wParam,lParam); } int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { hGetMessageHook=SetWindowsHookEx(WH_GETMESSAGE,GETMESSAGEProc,NULL,GetCurrentThreadId()); DialogBox(hInstance,MAKEINTRESOURCE(IDD_DIALOG1),NULL,(DLGPROC)DialogProc); return 0; } INT_PTR CALLBACK DialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { static HANDLE s_hFileMap=NULL; PVOID pView=NULL; PCOPYDATASTRUCT pCopydataStruct; hwnd=hwndDlg; switch(uMsg) { case WM_INITDIALOG: return TRUE; case WM_MYMESSAGE: s_hFileMap=OpenFileMapping(FILE_MAP_READ|FILE_MAP_WRITE,0,TEXT("ShareData")); if(s_hFileMap!=NULL) { pView=MapViewOfFile(s_hFileMap,FILE_MAP_READ|FILE_MAP_WRITE,0,0,0); if(pView!=NULL) { SetDlgItemText(hwndDlg,IDC_EDIT1,(LPCWSTR)pView); UnmapViewOfFile(pView); } else { MessageBox(hwndDlg,TEXT("不能映射文件视图!"),TEXT("出错"),MB_ICONINFORMATION); } } else { MessageBox(hwndDlg,TEXT("不能打开映射"),TEXT("出错"),MB_ICONINFORMATION); } break; /*case WM_COPYDATA: { pCopydataStruct=(PCOPYDATASTRUCT)lParam; SetDlgItemText(hwndDlg,IDC_EDIT1,(LPCWSTR)pCopydataStruct->lpData); } break;*/ case WM_CLOSE: CloseHandle(s_hFileMap); UnhookWindowsHookEx(hGetMessageHook); EndDialog(hwndDlg,0); return TRUE; } return FALSE; } |
|
郁闷了,学JAVA还是学"软件测试工程师“好?
依我看,楼主心里已经有答案了。。。 |
|
[求助]关于PostThreadMessage能实现进程间通信吗?
支持!!!可以用这个办法来证明人家PostThreadMessage确实可以实现进程通信,而刚好我用的是非模态对话框,偏偏他的消息循环系统给处理掉了,因此在dispath消息给窗口过程的时候把此消息给过滤掉了(此消息是线程消息,hwnd==NULL),所以。。。。 用WH_GETMESSAGE Hook可以检测到。 |
|
[求助]关于PostThreadMessage能实现进程间通信吗?
msdn中如是说: The thread to which the message is posted retrieves the message by calling the GetMessage or PeekMessage function. The hwnd member of the returned MSG structure is NULL. Messages sent by PostThreadMessage are not associated with a window. As a general rule, messages that are not associated with a window cannot be dispatched by the DispatchMessage function. Therefore, if the recipient thread is in a modal loop (as used by MessageBox or DialogBox), the messages will be lost. To intercept thread messages while in a modal loop, use a thread-specific hook. The system only does marshalling for system messages (those in the range 0 to (WM_USER-1)). To send other messages (those >= WM_USER) to another process, you must do custom marshalling. |
|
[求助]关于PostThreadMessage能实现进程间通信吗?
用普通的创建窗口类,注册窗口类,创建窗口,更新窗口。。。消息循环这样的方式创建了一个app,然后在消息循环中判断 while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)&&(msg.hwnd!=NULL)) { TranslateMessage(&msg); DispatchMessage(&msg); } else if(msg.message==WM_MYMESSAGE) { MessageBox(NULL,TEXT("消息从进程A中传送过来了!"),TEXT("恭喜"),MB_OK); } } 这样确实就接受到了消息,说明了一点:PostThreadMessage确实可以实现进程间通信的。 上面的例子中都是基于对话框的,而对话框都看不到消息循环,恰巧postthreadmessage又是往线程消息循环中投递消息,这个消息并没有针对任何一个窗口(postthreadmessage第一个参数是线程ID),也就是说这个消息属于线程本身的,而非线程中的某个窗口的。大胆猜测;对话框的窗口过程函数中之所以没接收到这个消息,很可能是因为对话框的消息循环把不是针对窗口的消息都过滤掉了吧(在到达窗口过程之前就过滤掉了),剩下的都是窗口消息了,故窗口过程才没有接到此消息。不晓得对不对?????又如何验证呢? |
|
[求助]关于PostThreadMessage能实现进程间通信吗?
感谢回答,不过你第一句话好像说的就不太对吧?消息循环是针对线程的,并非针对窗口吧,postthreadmessage是给某个线程消息循环发消息,SendMessage的第一个参数就是给哪个窗口发,第二个参数才是消息类型,这样,某个线程从他的消息循环中取出消息的时候,MSG本身就包含了hwnd,所以完全不存在你说的那个问题吧。 自己仔细看了几个函数的MSDN,得到了一个简单的“结论”(不对,欢迎评判): 1 BOOL PostThreadMessage( DWORD idThread, UINT Msg, WPARAM wParam, LPARAM lParam ); The PostThreadMessage function posts a message to the message queue of the specified thread. It returns without waiting for the thread to process the message. 说了,是给消息队列的某个线程。 2 DWORD GetWindowThreadProcessId( HWND hWnd, LPDWORD lpdwProcessId ); The GetWindowThreadProcessId function retrieves the identifier of the thread that created the specified window and, optionally, the identifier of the process that created the window. 参照一下参数返回信息。 Parameters hWnd [in] Handle to the window. lpdwProcessId [out] Pointer to a variable that receives the process identifier. If this parameter is not NULL, GetWindowThreadProcessId copies the identifier of the process to the variable; otherwise, it does not. Return Value The return value is the identifier of the thread that created the window. 说的不知道算不算得上清楚:如果是进程创建的窗口,则返回信息保存在第二个参数中,返回的是进程ID,返回值:线程ID。 我写的例子是这样的:两个进程A,B,A是一个非模态对话框(包含一个edit,一个button),B也是一个非模态对话框(包含一个edit),实现目的:当点击A中的button,把A中edit的内容发送给B中的edit中。 实现手段:内存映射方法,创建一个文件映射对象先映射到进程A的地址空间,然后把进程A中edit的内容得到,放到返回的视图地址中,然后在进程B中,同样也把这个文件内核对象映射到B的地址空间中,然后等待A发送给B的消息,当B接受到某个消息的时候执行操作:读取地址空间中视图的内容,放置到B的edit中。 问题:现在就卡在了发送消息这里,当然用SendMessage完全OK的,这里我也用PostThreadMessage进行了测试,发现始终是没实现此功能。 A.代码 #define WM_MYMESSAGE WM_USER+1 case WM_COMMAND: { switch(LOWORD(wParam)) { case IDC_BUTTON1: GetDlgItemText(hwndDlg,IDC_EDIT1,szEditText,MAX_PATH); //用WM_COPYDATA消息实现 //MessageBox(hwndDlg,szEditText,TEXT("B"),MB_OK); /*hwndDestination=FindWindow(NULL,TEXT("IPC_B")); copydatastruct.dwData=NULL; copydatastruct.cbData=sizeof(szEditText); copydatastruct.lpData=szEditText; SendMessage(hwndDestination,WM_COPYDATA,(WPARAM)hwndDlg,(LPARAM)©datastruct);*/ //用内存映射实现如下 if(s_hFileMap!=NULL) { if(GetLastError()==ERROR_ALREADY_EXISTS) { MessageBox(hwndDlg,TEXT("映射对象已经存在!"),TEXT("出错"),MB_ICONINFORMATION); } else { pView=MapViewOfFile(s_hFileMap,FILE_MAP_READ|FILE_MAP_WRITE,0,0,0); if(pView!=NULL) { //pView=szEditText; lstrcpy((LPWSTR)pView,szEditText); UnmapViewOfFile(pView); hwndDestination=FindWindow(NULL,TEXT("IPC_B")); dwThreadID=GetWindowThreadProcessId(hwndDestination,NULL); bRet=PostThreadMessage(dwThreadID,WM_MYMESSAGE,0,0); bError=GetLastError(); //bRet=SendMessage(hwndDestination,WM_MYMESSAGE,0,0); if(!bRet) { MessageBox(hwndDlg,TEXT("发送消息失败!"),TEXT("错误"),MB_ICONINFORMATION); } } else { MessageBox(hwndDlg,TEXT("不能映射文件视图!"),TEXT("出错"),MB_ICONINFORMATION); } } } else { MessageBox(hwndDlg,TEXT("不能创建映射"),TEXT("出错"),MB_ICONINFORMATION); } return 0; B代码: #define WM_MYMESSAGE WM_USER+1 case WM_MYMESSAGE: s_hFileMap=OpenFileMapping(FILE_MAP_READ|FILE_MAP_WRITE,0,TEXT("ShareData")); if(s_hFileMap!=NULL) { pView=MapViewOfFile(s_hFileMap,FILE_MAP_READ|FILE_MAP_WRITE,0,0,0); if(pView!=NULL) { SetDlgItemText(hwndDlg,IDC_EDIT1,(LPCWSTR)pView); UnmapViewOfFile(pView); } else { MessageBox(hwndDlg,TEXT("不能映射文件视图!"),TEXT("出错"),MB_ICONINFORMATION); } } else { MessageBox(hwndDlg,TEXT("不能打开映射"),TEXT("出错"),MB_ICONINFORMATION); } break; 使用的自定义消息,关键代码在这里: hwndDestination=FindWindow(NULL,TEXT("IPC_B")); dwThreadID=GetWindowThreadProcessId(hwndDestination,NULL); bRet=PostThreadMessage(dwThreadID,WM_MYMESSAGE,0,0); 1.找到进程B的窗口句柄 2 得到创建此窗口的进程?还是线程?ID(MSDN上面说的这里怎么理解?) 3 向那个线程的消息循环中投递消息 看起来好像没有任何问题吧?但是实际运行情况确让人垂头丧气。。。各位大侠们给点意见?看看是这个函数真的实现不了进程通信?还是我的这个例子中存在漏洞或是问题? |
|
[求助]小弟在写计算程序的时候遇到的一个问题
看看浮点数的存储方式就明白了 |
|
[讨论]用GDI+加载动态GIF中遇到的问题讨论。
运行效果图示例: |
|
[讨论]用GDI+加载动态GIF中遇到的问题讨论。
非常感谢6楼的回答,按照你的回答已经成功解决了。同样也感谢7楼地思路。贴一下代码吧,免得论坛中的人以后遇到类似的问题可以少走弯路 //定义2个ID #define TIMER_FIR 1 #define TIMER_SEC 2 //核心工作 case WM_CREATE: SetTimer(hWnd,TIMER_FIR,0,NULL); break; case WM_TIMER: { switch(wParam) { case TIMER_FIR: { hdc=GetDC(hWnd); image=new Image(L"123.gif"); count=0; count=image->GetFrameDimensionsCount(); pDimensionIDs=(GUID*)new GUID[count]; image->GetFrameDimensionsList(pDimensionIDs,count); StringFromGUID2(pDimensionIDs[0],strGuid,39); frameCount=image->GetFrameCount(&pDimensionIDs[0]); delete []pDimensionIDs; size=image->GetPropertyItemSize(PropertyTagFrameDelay); //PropertyItem* pItem=NULL; // pItem=(PropertyItem*)malloc(size); pItem=(PropertyItem*)new PropertyItem[size]; image->GetPropertyItem(PropertyTagFrameDelay,size,pItem); fcount=0; Guid=FrameDimensionTime; Graphics graphics(hdc); graphics.DrawImage(image,0,0); image->SelectActiveFrame(&Guid,fcount++); if(fcount==frameCount) fcount=0; lPause=((long*)pItem->value)[fcount]*10; //ReleaseDC(hWnd,hdc); KillTimer (hWnd, TIMER_FIR) ; SetTimer(hWnd,TIMER_SEC,lPause,NULL); InvalidateRect (hWnd, NULL, FALSE) ; break; } case TIMER_SEC: { image->SelectActiveFrame(&Guid,fcount++); if(fcount==frameCount) fcount=0; lPause=((long*)pItem->value)[fcount]*10; KillTimer(hWnd,TIMER_SEC); SetTimer(hWnd,TIMER_SEC,lPause,NULL); InvalidateRect (hWnd, NULL, FALSE) ; } } } |
|
[讨论]用GDI+加载动态GIF中遇到的问题讨论。
把循环绘图改成定时器这样应该还是不太对的,因为gif是多帧图像,每个帧与每个帧之间的时间间隔是不一样的,用定时器无从下手吧 |
|
[讨论]用GDI+加载动态GIF中遇到的问题讨论。
按照你说的,做了如下改变: hThread=(HANDLE)_beginthread(showimage,0,0); //showimage(hdc); WaitForSingleObject(hThread,INFINITE); EndPaint(hWnd, &ps); 运行发现跟上述的第一个问题一样,程序窗口失去焦点图片就不会动了,不知道我有没有理解你的意思啊你是这个意思吗 |
|
[求助]请各位给小弟一个SDK(非MFC)写的漂亮点的界面的例子?
我不是说你的,是说pudn跟vckbase里面的。 |
|
[求助]请各位给小弟一个SDK(非MFC)写的漂亮点的界面的例子?
都是MFC的,不是C+WINSDK的。 |
|
|
操作理由
RANk
{{ user_info.golds == '' ? 0 : user_info.golds }}
雪币
{{ experience }}
课程经验
{{ score }}
学习收益
{{study_duration_fmt}}
学习时长
基本信息
荣誉称号:
{{ honorary_title }}
能力排名:
No.{{ rank_num }}
等 级:
LV{{ rank_lv-100 }}
活跃值:
在线值:
浏览人数:{{ visits }}
最近活跃:{{ last_active_time }}
注册时间:{{ user_info.create_date_jsonfmt }}
勋章
兑换勋章
证书
证书查询 >
能力值