2013-12-15 50 views
1

由于某种原因,在关闭此窗口后,我的程序不会退出并进入无限循环。此问题的解决方案似乎将GetMessage(&消息,handel,0,0)更改为GetMessage(&消息,NULL,0,0)。但我不明白为什么这是。有人可以解释一下吗?另外我不明白为什么我调用UpdateWindow(handel),因为窗口没有显示。Windows API不会退出

#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)是误导性的。 “请注意,无论您为wMsgFilterMin和wMsgFilterMax指定哪些值,GetMessage始终会检索WM_QUIT消息。”正如这个问题和答案显示的那样,它并不总是被检索到。但是,它是否被检索并不依赖于wMsgFilterMin和wMsgFilterMax。 – hvd

+1

@hvd:我将该语句解释为“wMsgFilterMin和wMsgFilterMax参数不影响WM_QUIT处理”,但我同意它的误导性(或者最好不明确)。 –

+0

虽然我可以很容易地看到误解,但文档是正确的。如果手动将'WM_QUIT'发布到特定窗口,那么使用HWND和过滤器的代码将检索它,即使它与过滤器不匹配。 –

0

这里来锻炼你的“搜索最MSDN的文档”能力的好机会:

首先,让我们来看看了文档WM_QUIT

表示请求终止应用程序,并在 应用程序调用PostQuitMessage函数时生成。该消息 导致GetMessage函数返回零。

...

WM_QUIT消息不与窗口关联,因此将 从来没有经历过一个窗口的窗口过程接收。它被检索 只能由GetMessagePeekMessage功能。

然后,让我们来看看了文档GetMessage()

检索从调用线程的消息队列中的消息。功能 函数调度传入的已发送消息,直到发布的消息为 可用于检索。

...

的hWnd [在,可选]类型:HWND

句柄其消息是要检索的窗口。窗口 必须属于当前线程。

如果hWnd为NULL,的GetMessage检索消息为 属于当前线程的任何窗口,并且对当前 线程的消息队列,其HWND值是NULL的任何消息(参见MSG 结构)。因此,如果hWnd为NULL,则处理窗口消息和线程 消息。

因此,要使用NULL的窗口句柄GetMessage(),不handel,因为WM_QUIT不与任何窗口相关联。

还有来自MSDN的plenty more information about how Windows programs typically handle messages


正如侧面说明,对于窗口关闭事件的消息是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:旧的新事物,虽然它是一个梦幻般的博客,但不是官方文档。此外,请注意,它只在某些情况下不会返回-1(尽管是最常见的一个,可能只是合理的)。我更喜欢编写尽可能健壮的程序,并且它不会对-1进行测试。 –

+0

你的回答称它为'GetMessage(&msg,NULL,0,0)',这正是你永远不会得到-1的返回值的特定情况。没关系,如果你想检查就没关系,我不会说你的循环是错误的,只是在这里没有必要。 – hvd

1

看看GetMessagePostQuitMessage在MSDN

如果hWndGetMessage函数的参数为​​NULL,GetMessage函数对于属于当前线程的任何窗口检索邮件,并在当前线程的消息队列中的任何消息其hwnd值为NULL

PostQuitMessage函数将WM_QUIT消息发布到线程的消息队列,而不是当前窗口。