1、个人感觉:
1.1、MSDN中(https://msdn.microsoft.com/en-us/library/ms684242.aspx),说:
“
dwWakeMask [in]
The input types for which an input event object handle will be added to the array of object handles.
”
ZC: 也就是说,会在 "event object handle"数组的最后 加入一个 事件对象句柄,这个 事件对象句柄 专门用于响应消息的。这里 我将它称为 "消息事件对象句柄"(它对应的对象就称为"消息事件对象")
1.1、MSDN中(https://msdn.microsoft.com/en-us/library/ms684242.aspx),说:
“
The QS_ALLPOSTMESSAGE and QS_POSTMESSAGE flags differ in when they are cleared. QS_POSTMESSAGE is cleared when you call GetMessage or PeekMessage, whether or not you are filtering messages. QS_ALLPOSTMESSAGE is cleared when you call GetMessage or PeekMessage without filtering messages (wMsgFilterMin and wMsgFilterMax are 0). This can be useful when you call PeekMessage multiple times to get messages in different ranges.
”
文中多次提到 "cleared",这里指 "消息事件对象"的状态。
ZC: 我做的测试结果:
QS_ALLPOSTMESSAGE : 只要消息不取走,"消息事件对象"就一直是 有信号的状态(不管是否过滤消息(GetMessage和PeekMessage函数的wMsgFilterMin和wMsgFilterMax参数))。消息被取走后,"消息事件对象" 才会变成 无信号状态。
QS_POSTMESSAGE:就算消息不取走,"消息事件对象" 还是会被设置成 无信号状态。未取走的消息还保留在消息队列中。
2、
3、Delphi
3.1、界面:
3.2、代码:
procedure TfrmMain.btnPost1000Click(Sender: TObject); var hWnd1 :HWND; begin hWnd1 := StrToInt('$'+Trim(edtHWnd.Text)); PostMessage(hWnd1, WM_USER+1000, 0, 0); end; procedure TfrmMain.btnPost1001Click(Sender: TObject); var hWnd1 :HWND; begin hWnd1 := StrToInt('$'+Trim(edtHWnd.Text)); PostMessage(hWnd1, WM_USER+1001, 0, 0); end; procedure TfrmMain.btnSend1001Click(Sender: TObject); var hWnd1 :HWND; begin hWnd1 := StrToInt('$'+Trim(edtHWnd.Text)); SendMessage(hWnd1, WM_USER+1001, 0, 0); end; procedure TfrmMain.btnPostCloseClick(Sender: TObject); var hWnd1 :HWND; begin hWnd1 := StrToInt('$'+Trim(edtHWnd.Text)); SendMessage(hWnd1, WM_CLOSE, 0, 0); end; procedure TfrmMain.btnSetEventClick(Sender: TObject); var hEvent :Cardinal; iErr :integer; begin hEvent := OpenEvent(EVENT_ALL_ACCESS, false, '__VC_MsgWaitForMultipleObjects_TEST_20180105__'); iErr := GetLastError; Memo1.Lines.Add('OpenEvent return : '+IntToStr(hEvent)+', GetLastError : '+inttostr(iErr)); SetEvent(hEvent); CloseHandle(hEvent); end; procedure TfrmMain.btnPost1100Click(Sender: TObject); var hWnd1 :HWND; begin hWnd1 := StrToInt('$'+Trim(edtHWnd.Text)); PostMessage(hWnd1, WM_USER+1100, 0, 0); end; procedure TfrmMain.btnSend1100Click(Sender: TObject); var hWnd1 :HWND; begin hWnd1 := StrToInt('$'+Trim(edtHWnd.Text)); SendMessage(hWnd1, WM_USER+1100, 0, 0); end;
4、VC6 测试代码:
#include <windows.h> #include <io.h> #include <fcntl.h> #include <stdio.h> HINSTANCE g_hInstance = 0; HWND g_hWnd = 0; LRESULT CALLBACK ProcWindow(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); void InitConsoleWindow() { AllocConsole(); HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); int hCrt = _open_osfhandle((long)handle,_O_TEXT); FILE * hf = _fdopen( hCrt, "w" ); *stdout = *hf; } //////////// //////////// //////////// //////////// //////////// //////////// int WINAPI WinMain( HINSTANCE _hInstance, // 当前 hInstance句柄 HINSTANCE _hPrevInstance, // 之前的 hInstance句柄 LPSTR _lpCmdLine, // 命令行 int _nCmdShow // 显示状态 ) { g_hInstance = _hInstance; // 程序(.exe)的图标貌似默认是 资源文件中 的第一个图标?? WNDCLASS wndcls = {0}; wndcls.style = CS_HREDRAW | CS_VREDRAW; wndcls.lpfnWndProc = ProcWindow; wndcls.cbClsExtra = 0; wndcls.cbWndExtra = 0; wndcls.hInstance = _hInstance; wndcls.hIcon = LoadIcon(NULL, IDI_ERROR); // 窗口图标 wndcls.hCursor = LoadCursor(NULL, IDC_CROSS); wndcls.hbrBackground= (HBRUSH)GetStockObject(WHITE_BRUSH); // 背景画刷 wndcls.lpszMenuName = NULL; wndcls.lpszClassName= "zc20110929"; // 注册窗口类 RegisterClass(&wndcls); g_hWnd = CreateWindowEx( NULL, //WS_EX_CLIENTEDGE, wndcls.lpszClassName, "ZC Window", WS_OVERLAPPEDWINDOW, 100, 100, 400, 300, NULL, NULL, //g_hMenu, _hInstance, NULL); ShowWindow(g_hWnd, SW_SHOWNORMAL); UpdateWindow(g_hWnd); MSG msg; while(GetMessage(&msg, 0, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } HANDLE g_hEvent = NULL; //#define PM_QS_POSTMESSAGE ((QS_POSTMESSAGE | QS_HOTKEY | QS_TIMER) << 16) #define PM_QS_POSTMESSAGE ((QS_POSTMESSAGE) << 16) int g_iInc = 0; LRESULT CALLBACK ProcWindow( HWND _hWnd, // 窗口句柄 UINT _uMsg, // 消息ID(identifier) WPARAM _wParam, LPARAM _lParam) { switch (_uMsg) { case WM_USER+1000: { printf("Before MsgWaitForMultipleObjects . "); //DWORD dwRtn = MsgWaitForMultipleObjects(1, &g_hEvent, false, INFINITE, QS_SENDMESSAGE); while (1) { DWORD dwRtn = MsgWaitForMultipleObjects(1, &g_hEvent, false, INFINITE, QS_SENDMESSAGE | QS_POSTMESSAGE); if (dwRtn == 0) break; printf("MsgWaitForMultipleObjects return %d ", dwRtn); /*MSG msg; ::GetMessage(&msg, _hWnd, 2024, 2026); printf("GetMessage get message : %d ", msg.message);*/ MSG msg; //dwRtn = ::PeekMessage(&msg, _hWnd, 2024, 2026, PM_REMOVE | PM_QS_POSTMESSAGE);// PM_QS_POSTMESSAGE //dwRtn = ::PeekMessage(&msg, _hWnd, 2024, 2026, PM_QS_POSTMESSAGE);// PM_QS_POSTMESSAGE //printf("PeekMessage get message(1) : %d, %d ", msg.message, dwRtn); dwRtn = ::PeekMessage(&msg, _hWnd, 0, 0, PM_NOREMOVE | PM_QS_POSTMESSAGE); printf("PeekMessage get message(2) : %d, %d ", msg.message, dwRtn); if (msg.message == WM_CLOSE) break; if (g_iInc == 30) { ::GetMessage(&msg, _hWnd, 2000, 2500); printf("GetMessage get message : %d ", msg.message); } g_iInc ++; printf(" ==> %d ", g_iInc); if (g_iInc >= 50) {//* // system("pause"); ::GetMessage(&msg, _hWnd, 0, 0); printf("GetMessage get message : %d ", msg.message); // ::MessageBox(0, "Text", "caption", 0); //*/ break; } } /* DWORD WINAPI MsgWaitForMultipleObjects( _In_ DWORD nCount, _In_ const HANDLE *pHandles, _In_ BOOL bWaitAll, _In_ DWORD dwMilliseconds, _In_ DWORD dwWakeMask );*/ printf("After MsgWaitForMultipleObjects . "); return 0; } case WM_USER+1001: { printf("WM_USER+1001 "); return 0; } case WM_USER+1100: { printf("WM_USER+1100 "); return 0; } case WM_CREATE: { InitConsoleWindow(); printf("WM_CREATE "); g_hEvent = ::CreateEvent(NULL, false, false, "__VC_MsgWaitForMultipleObjects_TEST_20180105__"); printf("HWND : %d , 0x%X ", _hWnd, _hWnd); return 0; } case WM_PAINT: { char buf[256] = {0}; sprintf(buf, "HWND : %d , 0x%08X", _hWnd, _hWnd); HDC hDc; PAINTSTRUCT ps; hDc = BeginPaint(_hWnd, &ps); TextOut(hDc, 0, 0, buf, strlen(buf)); EndPaint(_hWnd, &ps); return 0; // break; } case WM_CLOSE: case WM_DESTROY: { DestroyWindow(_hWnd); PostQuitMessage(0); return 0; } } return DefWindowProc(_hWnd, _uMsg, _wParam, _lParam); }
5、