windows消息机制_PostMessage和SendMessage

1.子线程中建立一个窗口

为了在后面比较这两个函数,先使用win32 windows程序中建立子线程,在子线程中建立一个窗口。

(1)新建一个 win32 windows应用程序

(2)定义子窗口的窗口响应函数

LRESULT CALLBACK SubWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     switch (message)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    case WM_LBUTTONDOWN:
        MessageBoxA(0,"","SubWndProc",0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
}

(3)定义子线程窗口函数

void CreateWndInThread(int nWidth, int nHeight)
{
    WNDCLASSEX wcex2;  
    wcex2.cbSize = sizeof(WNDCLASSEX);
    wcex2.style = CS_HREDRAW | CS_VREDRAW;
    wcex2.lpfnWndProc = SubWndProc;
    wcex2.cbClsExtra = 0;
    wcex2.cbWndExtra = 0;
    wcex2.hInstance = GetModuleHandle(nullptr);
    wcex2.hIcon = 0;
    wcex2.hCursor = LoadCursor(nullptr, IDC_ARROW);
    wcex2.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcex2.lpszMenuName = NULL;
    wcex2.lpszClassName = L"SubWindow";
    wcex2.hIconSm = 0;
    RegisterClassEx(&wcex2);
    HWND g_hWnd = CreateWindowA("SubWindow", nullptr,WS_OVERLAPPEDWINDOW, 0, 0, nWidth, nHeight, NULL, NULL, wcex2.hInstance, 0);
    ShowWindow(g_hWnd, SW_SHOW);
    UpdateWindow(g_hWnd);
    MSG msg;
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

(4)处理主线程的 WM_LBUTTONDOWN 消息

在里面开启一个子线程,调用 CreateWndInThread

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc;
    switch (message)
    {

    case WM_LBUTTONDOWN:
        {
            std::thread t(CreateWndInThread, 960, 480);
            t.detach();
        }
        break;
        //省略其他消息
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

(5)运行程序

在主窗口上鼠标左键点击,会创建一个子窗口,

然后在子窗口上鼠标左键点击,会弹出一个MessageBox。

可以发现两个窗口的消息处理互不影响。

2.PostMessage和SendMessage

PostMessage会将消息压入窗口所在线程的消息队列,然后立即返回,非阻塞

SendMessage则不经过消息队列,SendMessage可认为是直接调用了该窗口的窗口过程,阻塞

将上面的项目做如下修改:

(1)定义一个全局遍历来存储子窗体的句柄,定义子窗体自定义消息

#define WM_SUB_MSG (WM_USER+1)
HWND subWinHwnd;//子窗口

(2)修改子窗口的窗口响应函数

void CreateWndInThread(int nWidth, int nHeight)
{
    WNDCLASSEX wcex2;  
    wcex2.cbSize = sizeof(WNDCLASSEX);
    wcex2.style = CS_HREDRAW | CS_VREDRAW;
    wcex2.lpfnWndProc = SubWndProc;
    wcex2.cbClsExtra = 0;
    wcex2.cbWndExtra = 0;
    wcex2.hInstance = GetModuleHandle(nullptr);
    wcex2.hIcon = 0;
    wcex2.hCursor = LoadCursor(nullptr, IDC_ARROW);
    wcex2.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcex2.lpszMenuName = NULL;
    wcex2.lpszClassName = L"SubWindow";
    wcex2.hIconSm = 0;
    RegisterClassEx(&wcex2);
    subWinHwnd = CreateWindowA("SubWindow", nullptr,WS_OVERLAPPEDWINDOW, 0, 0, nWidth, nHeight, NULL, NULL, wcex2.hInstance, 0);
    ShowWindow(subWinHwnd, SW_SHOW);
    UpdateWindow(subWinHwnd);
    MSG msg;
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

(3)修改子线程窗口函数

LRESULT CALLBACK SubWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     switch (message)
    {
    case WM_SUB_MSG:
        MessageBoxA(0,"WM_SUB_MSG","子窗体",0);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    case WM_LBUTTONDOWN:
        MessageBoxA(0,"左键消息","子窗体",0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
}

(4)修改主窗口的窗口函数

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc;
    switch (message)
    {
    case WM_LBUTTONDOWN:
        {
            std::thread t(CreateWndInThread, 960, 480);
            t.detach();
        }
        break;
    case WM_RBUTTONDOWN:
        {
          SendMessage(subWinHwnd,WM_SUB_MSG,0,0);
          //PostMessage(subWinHwnd,WM_SUB_MSG,0,0);
          MessageBoxA(0,"右键消息","主窗体",0);
        }
        break;
    case WM_COMMAND:
        wmId    = LOWORD(wParam);
        wmEvent = HIWORD(wParam);
        // 分析菜单选择:
        switch (wmId)
        {
        case IDM_ABOUT:
            DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
            break;
        case IDM_EXIT:
            DestroyWindow(hWnd);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        break;
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        // TODO: 在此添加任意绘图代码...
        EndPaint(hWnd, &ps);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

(5)运行程序

发现使用SendMessage(subWinHwnd,WM_SUB_MSG,0,0) ,

MessageBoxA(0,"右键消息","主窗体",0) 对话框在 MessageBoxA(0,"WM_SUB_MSG","子窗体",0) 后面出现

使用PostMessage(subWinHwnd,WM_SUB_MSG,0,0)

MessageBoxA(0,"右键消息","主窗体",0) 对话框在MessageBoxA(0,"WM_SUB_MSG","子窗体",0) 前面出现

(6)完整代码链接:https://www.aliyundrive.com/s/UtrYB42wyi3

总结:

PostMessage会将消息压入窗口所在线程的消息队列,然后立即返回,非阻塞

SendMessage则不经过消息队列,SendMessage可认为是直接调用了该窗口的窗口过程,阻塞

原文地址:https://www.cnblogs.com/hosseini/p/15178064.html