代码之家  ›  专栏  ›  技术社区  ›  user3306559

WinApi消息循环,Postmessage与SendMessage类似

  •  3
  • user3306559  · 技术社区  · 10 年前

    你好,有人能回答我为什么当我运行这个程序时,MessageBox的顺序是1,2,4,3而不是1,2,3,4。在我看来,程序应该在启动WM_USER+11之前结束执行WM_PAINT过程,为什么不是呢?

    // Win32Project6.cpp : Defines the entry point for the application.
    //
    
    #include "stdafx.h"
    #include "Win32Project6.h"
    
    #define MAX_LOADSTRING 100
    
    // Global Variables:
    HINSTANCE hInst;                                // current instance
    TCHAR szTitle[MAX_LOADSTRING];                  // The title bar text
    TCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name
    
    // Forward declarations of functions included in this code module:
    ATOM                MyRegisterClass(HINSTANCE hInstance);
    BOOL                InitInstance(HINSTANCE, int);
    LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
    INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);
    
    
    DWORD thread(LPVOID lpdwThreadParam);
    
    int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
                         _In_opt_ HINSTANCE hPrevInstance,
                         _In_ LPTSTR    lpCmdLine,
                         _In_ int       nCmdShow)
    {
        UNREFERENCED_PARAMETER(hPrevInstance);
        UNREFERENCED_PARAMETER(lpCmdLine);
    
        // TODO: Place code here.
        MSG msg;
        HACCEL hAccelTable;
    
        // Initialize global strings
        LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
        LoadString(hInstance, IDC_WIN32PROJECT6, szWindowClass, MAX_LOADSTRING);
        MyRegisterClass(hInstance);
    
        // Perform application initialization:
        if (!InitInstance (hInstance, nCmdShow))
        {
            return FALSE;
        }
    
        hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32PROJECT6));
    
        // Main message loop:
        while (GetMessage(&msg, NULL, 0, 0))
        {
            if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
    
        return (int) msg.wParam;
    }
    
    
    
    //
    //  FUNCTION: MyRegisterClass()
    //
    //  PURPOSE: Registers the window class.
    //
    ATOM MyRegisterClass(HINSTANCE hInstance)
    {
        WNDCLASSEX wcex;
    
        wcex.cbSize = sizeof(WNDCLASSEX);
    
        wcex.style          = CS_HREDRAW | CS_VREDRAW;
        wcex.lpfnWndProc    = WndProc;
        wcex.cbClsExtra     = 0;
        wcex.cbWndExtra     = 0;
        wcex.hInstance      = hInstance;
        wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WIN32PROJECT6));
        wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
        wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
        wcex.lpszMenuName   = MAKEINTRESOURCE(IDC_WIN32PROJECT6);
        wcex.lpszClassName  = szWindowClass;
        wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
    
        return RegisterClassEx(&wcex);
    }
    
    //
    //   FUNCTION: InitInstance(HINSTANCE, int)
    //
    //   PURPOSE: Saves instance handle and creates main window
    //
    //   COMMENTS:
    //
    //        In this function, we save the instance handle in a global variable and
    //        create and display the main program window.
    //
    BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
    {
       HWND hWnd;
    
       hInst = hInstance; // Store instance handle in our global variable
    
       hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
          CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
    
       if (!hWnd)
       {
          return FALSE;
       }
    //   PostMessage(hWnd, WM_USER + 11, 0, 0);
       MessageBox(0,"1","Message",0);
       MessageBox(0, "2", "Message", 0);
       ShowWindow(hWnd, nCmdShow);
       UpdateWindow(hWnd);
    
       return TRUE;
    }
    
    //
    //  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
    //
    //  PURPOSE:  Processes messages for the main window.
    //
    //  WM_COMMAND  - process the application menu
    //  WM_PAINT    - Paint the main window
    //  WM_DESTROY  - post a quit message and return
    //
    //
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        int wmId, wmEvent;
        PAINTSTRUCT ps;
        HDC hdc;
    
        switch (message)
        {
        case WM_COMMAND:
            wmId    = LOWORD(wParam);
            wmEvent = HIWORD(wParam);
            // Parse the menu selections:
            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_USER+11:
            MessageBox(hWnd,"4","Message",0);
            break;
        case WM_PAINT:
            hdc = BeginPaint(hWnd, &ps);
            CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&thread, &hWnd, 0, 0);
            MessageBox(hWnd, "3", "Message", 0);
            // TODO: Add any drawing code here...
            EndPaint(hWnd, &ps);
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        return 0;
    }
    
    // Message handler for about box.
    INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
    {
        UNREFERENCED_PARAMETER(lParam);
        switch (message)
        {
        case WM_INITDIALOG:
            return (INT_PTR)TRUE;
    
        case WM_COMMAND:
            if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
            {
                EndDialog(hDlg, LOWORD(wParam));
                return (INT_PTR)TRUE;
            }
            break;
        }
        return (INT_PTR)FALSE;
    }
    
    
    DWORD thread(LPVOID lpdwThreadParam)
    {
    
        PostMessage(*(HWND*)(lpdwThreadParam), WM_USER + 11, 0, 0);
    
        return 0;
    }
    
    2 回复  |  直到 10 年前
        1
  •  6
  •   tenfour    10 年前

    关于此代码的一些注意事项:

    • 不应在中创建线程 WM_PAINT 。你也不应该打电话 MessageBox 在里面 WM_打印 . WM_打印 只是用来画你的窗户;这里不应执行其他逻辑。系统优化 WM_打印 当你开始在这个处理程序中逾期逗留时,电话和行为会变得非常棘手。
    • 您也不应该像使用 (LPTHREAD_START_ROUTINE)&thread 。如果函数类型不正确,请更改函数原型;不要试图隐藏编译器的警告。
    • 你应该使用 _beginthread ,因为CRT需要执行一些初始化。
    • 你应该通过 hWnd 作为线程参数,而不是 &hWnd 。指针可能超出范围并变得无效。这是一个关键错误。

    要真正了解发生了什么,您应该首先修复这些错误。

    为了回答您的问题,不同的线程无法保证速度。在你分割了一个线程之后,现在还不知道接下来会发生什么。它们是异步的。也许线程代码比主线程运行得更快,反之亦然。

    请记住 对话框 具有自己的内部消息循环。所以调用堆栈位于 WM_USER+11 (MessageBox4)将看起来像这样:

    MessageBox (4)
    WndProc (WM_USER+11)
    DispatchMessage
    MessageBox (3), before it's actually shown
    WndProc (WM_PAINT)
    DispatchMessage
    WinMain
    

    因此,您可以看到,如果线程足够快地发布消息,它将在 MessageBox(3) 将显示。

    我的猜测是,如果您使用更轻的调试技术( OutputDebugString 例如),您将观察到更可预测的行为。

        2
  •  3
  •   Paul    10 年前

    WM_PAINT 是一种特殊的低优先级消息。

    这个 WM_打印 消息 WM_TIMER 消息,以及 WM_QUIT 消息,[…]保留在队列中,仅当队列中不包含其他消息时才转发到窗口过程。

    MSDN - Queued Messages .

    另请参见 The Old New Thing - Paint messages will come in as fast as you let them .