2013-12-15 3 views
1

По какой-то причине после закрытия этого окна моя программа не выйдет и перейдет в бесконечный цикл. Решение этой проблемы, по-видимому, меняет GetMessage (& message, handel, 0, 0) на GetMessage (& сообщение, NULL, 0, 0). Однако я не понимаю, почему это так. Может кто-нибудь объяснить. Также я не понимаю, почему я называю UpdateWindow (handel), поскольку окно будет отображаться без него.Windows API wont quit

#include <iostream> 
#include <Windows.h> 

using namespace std; 

LRESULT CALLBACK EventHandler(HWND, UINT, WPARAM, LPARAM); 

int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, PSTR args, int cmd) 
{ 
    MSG message; 
    HWND handel; 
    WNDCLASS win_class; 

    win_class.style = CS_HREDRAW | CS_VREDRAW; 
    win_class.cbClsExtra = 0; 
    win_class.cbWndExtra = 0; 
    win_class.lpszClassName = "Window"; 
    win_class.hInstance = inst; 
    win_class.hbrBackground = GetSysColorBrush(COLOR_3DDKSHADOW); 
    win_class.lpszMenuName = NULL; 
    win_class.lpfnWndProc = EventHandler; 
    win_class.hCursor = LoadCursor(NULL, IDC_ARROW); 
    win_class.hIcon = LoadIcon(NULL, IDI_APPLICATION); 

    RegisterClass(&win_class); 
    handel = CreateWindow(win_class.lpszClassName, "Window", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 350, 250, NULL, NULL, inst, NULL); 
    ShowWindow(handel, cmd); 
    UpdateWindow(handel); 

    //Loop does not end. 
    while(GetMessage(&message, handel, 0, 0)) 
    { 
     cout << "LOOP" << endl; 
     DispatchMessage(&message); 
    } 
    return WM_QUIT; 
} 

LRESULT CALLBACK EventHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
    static long long count = 0; 
    count++; 
    cout << "CALL #" << count << endl; 
    if(msg == WM_DESTROY) 
    { 
     PostQuitMessage(0); 
     return 0; 
    } 
    return DefWindowProc(hwnd, msg, wParam, lParam); 
} 
+0

Вы могли бы задать вопрос более интересным, спросив, почему вы * когда-либо * передавали не-NULL-дескриптор. –

ответ

1

WM_QUIT не отправляется в любое окно, просто помещается в очередь сообщений потока, не HWND, поэтому он не совпадает с фильтром.

+0

[Документация] (http://msdn.microsoft.com/en-us/library/windows/desktop/ms644936%28v=vs.85%29.aspx) вводит в заблуждение. «Обратите внимание, что GetMessage всегда извлекает сообщения WM_QUIT, независимо от того, какие значения вы укажете для wMsgFilterMin и wMsgFilterMax». Поскольку этот вопрос и ваш ответ показывают, он не всегда извлекается. Однако, независимо от того, будет ли он получен не зависит от wMsgFilterMin и wMsgFilterMax. – hvd

+1

@hvd: Я интерпретировал это утверждение как «Параметры wMsgFilterMin и wMsgFilterMax не влияют на обработку WM_QUIT», но я согласен, что это вводит в заблуждение (или в лучшем случае неоднозначное). –

+0

Хотя я могу легко понять недоразумение, документация правильная. Если вы вручную разместили «WM_QUIT» в конкретном окне, тогда код с использованием HWND и фильтров будет извлекать его, даже если он не соответствует фильтру. –

0

Вот хорошая возможность для реализации своего «поиск-в-узел MSDN-документация» способности:

Во-первых, давайте посмотрим на документацию для WM_QUIT:

Указывает на запрос о прекращении приложения, и генерируется, когда приложение вызывает функцию PostQuitMessage. Это сообщение заставляет функцию GetMessage возвращать ноль.

...

WM_QUIT сообщение не связано с окном и, следовательно, не будет никогда не будет получено через оконную процедуру окна. Он получен только GetMessage или PeekMessage функции.

Тогда давайте искать документацию для GetMessage():

Извлекает сообщение из очереди сообщений вызывающего потока. Функция отправляет входящие отправленные сообщения до тех пор, пока сообщение не будет доступно для извлечения.

...

HWND [в, по выбору] Тип: HWND

Дескриптор окна, сообщения должны быть извлечены. Окно должно принадлежать к текущему потоку.

Если HWND является NULL, GetMessage извлекает сообщения для любого окна, которое принадлежит текущему потоку, и все сообщения по очереди сообщений текущего потока которого HWND значение NULL (см структуры MSG ). Поэтому, если hWnd NULL, обрабатываются как оконные сообщения, так и поток .

Таким образом, вы хотите использовать в качестве NULL оконной ручки для GetMessage(), не handel, поскольку WM_QUIT не связан ни с окном.

Существует plenty more information about how Windows programs typically handle messages также из MSDN.


Как примечание стороны, сообщение для закрытия окна событий WM_CLOSE, что в свою очередь вызывает ваше окно будет уничтожен по умолчанию. WM_DESTROY означает, что ваше окно уже на пути к уничтожению. Поэтому, если вы хотите перехватить событие закрытия (например, попросить вашего пользователя сохранить какие-либо изменения), вы должны обработать событие WM_CLOSE.

Кроме того, как показано в документации GetMessage(), вы должны действительно иметь свой GetMessage() петли выглядеть следующим образом:

BOOL bRet; 

while((bRet = GetMessage(&msg, hWnd, 0, 0)) != 0) 
{ 
    if (bRet == -1) 
    { 
     // handle the error and possibly exit 
    } 
    else 
    { 
     TranslateMessage(&msg); 
     DispatchMessage(&msg); 
    } 
} 

Поскольку GetMessage() действительно может вернуть 1, 0 или -1 (несмотря на то, что возвращает BOOL) ,

+0

Рекомендуемое чтение: [Когда GetMessage возвращает -1?] (Http://blogs.msdn.com/b/oldnewthing/archive/2013/03/22/10404367.aspx) (Так что нет, цикл не нужен выглядят так.) – hvd

+1

@ hvd: The Old New Thing, в то время как это фантастический блог, не является официальной документацией. Кроме того, обратите внимание, что он никогда не возвращает -1 только при определенных обстоятельствах (хотя и наиболее распространенный и, вероятно, только разумный). Я предпочитаю писать программы, которые настолько прочны, насколько это возможно, и это не мешает тестировать против -1. –

+0

Ваш ответ говорит, что он называется «GetMessage (& msg, NULL, 0, 0)», что является именно тем определённым обстоятельством, при котором вы никогда не получите возвращаемого значения -1. Это нормально, если вы все равно хотите проверить, я бы не сказал, что ваш цикл ошибочен, просто он здесь не нужен. – hvd

1

Посмотрите на GetMessage и PostQuitMessage в MSDN

Если параметр hWnd из GetMessage функции NULL, GetMessage извлекает сообщения для любого окна, которое принадлежит текущему потоку, и все сообщения по очереди сообщений текущего потока чье значение hwnd равно NULL.

Функция PostQuitMessage отправляет сообщение WM_QUIT в очередь сообщений с потоком, а не в текущее окно.