2016-04-26 51 views
0

我有超级简单的WinApi程序。关闭按钮不会破坏程序的进程。应该添加什么?WinApi任务查杀

#include <windows.h> 
#include <stdlib.h> 
#include <string.h> 
#include <tchar.h> 


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

HINSTANCE hINSTANCE; 

int WINAPI WinMain(HINSTANCE hInstance, 
       HINSTANCE hPrevInstance, 
       LPSTR lpstr, 
       int nCmdShow) { 

// VARIABLES 
    TCHAR className[] = _T("win32api"); 
    TCHAR windowName[] = _T("Protected Window"); 

    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(NULL, IDI_INFORMATION); 
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW); 
    wcex.hbrBackground = (HBRUSH)COLOR_BACKGROUND; 
    wcex.lpszMenuName = NULL; 
    wcex.lpszClassName = className; 
    wcex.hIconSm = LoadIcon(NULL, IDI_SHIELD); 

    if (!RegisterClassEx(&wcex)) { 
     MessageBox(NULL, _T("Cannot register window"), _T("Error"), MB_OK | MB_ICONERROR); 
     return 0; 
    } 

    HWND hWnd = CreateWindow(className, 
           windowName, 
           WS_OVERLAPPEDWINDOW, 
           CW_USEDEFAULT, 
           CW_USEDEFAULT, 
           300, 
           300, 
           NULL, 
           NULL, 
           hInstance, 
           NULL); 

    if (!hWnd) { 
     MessageBox(hWnd, _T("Call to register windows isn't working"), _T("Error"), NULL); 
     return 1; 
    } 

    hINSTANCE = hInstance; 
    ShowWindow(hWnd, nCmdShow); 
    UpdateWindow(hWnd); 

    MSG msg; 

    while (GetMessage(&msg, hWnd, 0, 0) != 0 || GetMessage(&msg, hWnd, 0, 0) != -1) { 
     TranslateMessage(&msg); 
     DispatchMessage(&msg); 
    } 

    return (int)msg.lParam; 
} 

LRESULT CALLBACK WndProc(HWND hWnd, UINT uInt, WPARAM wParam, LPARAM lParam) { 
    PAINTSTRUCT ps; 
    HDC hdc; 
    switch (uInt) { 
    case WM_PAINT: 
     hdc = BeginPaint(hWnd, &ps); 
     TextOut(hdc, 10, 20, _T("Text sample right here boyz."), _tcsclen(_T("Text sample right here boyz."))); 
     EndPaint(hWnd, &ps); 
     break; 
    case WM_DESTROY: 
     PostQuitMessage(0); 
     break; 
    default: 
     return DefWindowProc(hWnd, uInt, wParam, lParam); 
     break; 
    } 

    return 0; 
} 

如果我添加更多的情况

case WM_CLOSE: 
    PostQuitMessage(0); 
    break; 

它不关闭所有(按关闭按钮没有做任何事情)。任何其他提示都非常感谢。

+0

[DestroyWindow破坏窗口..](http://stackoverflow.com/a/16749227/2142994)这有帮助吗? –

回答

4

你的消息循环是错误的,原因有二:

  1. 您呼叫GetMessage()两次。不要这样做!想想如果你这样做会发生什么。如果||左侧的GetMessage()呼叫检测到WM_QUIT(它不能,请参阅下面的内容),它将返回0.这将导致||在右侧调用GetMessage(),忽略WM_QUIT,并阻止该循环,直到稍后收到新消息。你应该叫GetMessage()每循环迭代一次,然后根据需要在返回值作用:通过HWNDdon't do that!

    BOOL bRet; 
    
    do 
    { 
        bRet = GetMessage(&msg, hWnd, 0, 0); 
        if (bRet == 0) break; 
        if (bRet == -1) 
        { 
         // handle the error and possibly exit 
        } 
        else 
        { 
         TranslateMessage(&msg); 
         DispatchMessage(&msg); 
        } 
    } 
    while (1); 
    
  2. 但是,你也过滤消息,因此它只会返回的消息通过PostMessage()发布到指定的HWNDPostQuitMessage()将其WM_QUIT消息发布到调用线程本身的输入队列,而不是HWND。所以过滤将永远不会看到WM_QUIT消息。为了让WM_QUIT打破循环,您需要完全停止过滤HWND,或者至少定期进行未经过滤的呼叫。

您的消息循环应该看起来像这样。这是标准消息循环:

while (GetMessage(&msg, NULL, 0, 0)) { 
    TranslateMessage(&msg); 
    DispatchMessage(&msg); 
} 

注意,在这种情况下,there is no need to handle -1 from GetMessage()!

0

要关闭应用程序,您需要销毁该窗口。通常这是通过以下两种方式之一完成的:

  1. 您的WM_CLOSE处理程序调用DestroyWindow
  2. 在您做完事情后,DefWindowProc是否会处理该消息。

你的WndProc有点不同寻常。我经常看到他们写为:

{  
    switch(msg) 
    { 
     case WM_CLOSE: 
      // prompt user, clean stuff up, etc. 
      break; 

     case WM_DESTROY: 
      PostQuitMessage(0); 
      break; 

     // Other cases here. Most will fall out of the switch so that 
     // DefWindowProc can handle them (for other system notifications). 
     // Only return from the case if you really don't want anybody else 
     // to handle the message. 
    } 

    return DefWindowProcW(hwnd, msg, wParam, lParam); 
} 

对于细节上WM_CLOSE,看到https://msdn.microsoft.com/en-us/library/windows/desktop/ms632617(v=vs.85).aspx,具体说,你必须调用DestroyWindow或让DefWindowProc做到这一点。

+0

你的意思是'WndProc'应该只包含'开关'在用窗口执行操作之后描述行为?我应该如何放置按钮等然后? –

+0

我记得,你把按钮处理的东西放在'WM_COMMAND'处理程序中。 –

+0

对不起,我只是一个初学者。我无法理解它是如何工作的。如果我把它们放在'WM_COMMAND'的情况下,那么它不会出现在程序中。所以我需要强制'WM_COMMAND'案件以某种方式工作?还有,WndProc如何被该程序调用?以及消息如何从操作系统发送到GetMessage?而WM_PAINT应该包含什么? –