2014-02-13 3 views
3

Здравствуйте, может кто-нибудь ответить мне, почему, когда я запускаю эту программу, порядок MessageBoxes составляет 1,2,4,3 вместо 1,2,3,4. На мой взгляд, программа должна завершить выполнение процедуры WM_PAINT перед запуском WM_USER + 11, почему это не так?WinApi message loop, Postmessage работает как SendMessage

// 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; 
} 
+1

Никогда, * никогда не отлаживайте код с MessageBox(). Он накачивает конвейер сообщений, что может быть очень трудно диагностировать при повторном подключении. В противном случае прямой вызов, вызов UpdateWindow() заставляет WM_PAINT отправляться раньше. Не удается обновить окно без его рисования. –

ответ

6

Некоторые заметки об этом коде:

  • Вы не должны создавать темы в WM_PAINT. Также не следует звонить MessageBox в WM_PAINT. WM_PAINT предназначен только для покраски вашего окна; никакая другая логика не должна выполняться здесь. Система оптимизирует вызовы WM_PAINT, и поведение может стать очень сложным, когда вы начинаете затягивать свой прием в этом обработчике.
  • Вы также никогда не должны посылать вызов функции, как вы, с помощью (LPTHREAD_START_ROUTINE)&thread. Если ваша функция не соответствует типу, измените прототип функции; не просто пытайтесь скрыть предупреждения компилятора.
  • Возможно, вы должны использовать _beginthread, потому что у CRT есть некоторая инициализация для выполнения.
  • Вы должны передать hWnd в качестве параметра нити, а не &hWnd. Указатель может выйти из области действия и стать недействительным. Это критическая ошибка.

Чтобы понять, что происходит, вы должны исправить эти ошибки в первую очередь.

Чтобы ответить на ваш вопрос, разные потоки не гарантируют скорость. После того, как вы отделите нить, теперь нет никаких сведений о том, что будет дальше. Они асинхронны. Возможно, код потока работает быстрее, чем ваш основной поток, возможно, наоборот.

Имейте в виду, что MessageBox имеет свой собственный внутренний контур сообщения. Таким образом, CallStack на 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), вы увидите более предсказуемое поведение.

3

WM_PAINT является одним из специальных сообщений с низким приоритетом.

WM_PAINT сообщение, WM_TIMER сообщения, и WM_QUIT сообщения, [...] сохраняется в очереди и направляется в оконной процедуру только тогда, когда очередь не содержит никаких других сообщений.

MSDN - Queued Messages.

См. Также The Old New Thing - Paint messages will come in as fast as you let them.

+0

Он не говорит о последующих вызовах WM_PAINT. Создание потока и MessageBox (3) находятся в одном вызове. – tenfour

+0

+1 Для упоминания этого менее известного факта, но я верю, что @tenfour имеет ответ. – ixe013

Смежные вопросы