2016-04-26 6 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; 
} 

私はそれが近くにある全て(押圧閉じるボタンが何もしていない)doesntの

case WM_CLOSE: 
    PostQuitMessage(0); 
    break; 

1より多くのケースを追加した場合。その他のヒントは非常に高く評価されています。

+0

[DestroyWindowはウィンドウを破棄します..](http://stackoverflow.com/a/16749227/2142994)これは役に立ちますか? –

答えて

4

あなたのメッセージループは、2つの理由のため、間違っている:あなたは二回GetMessage()を呼び出している

  1. 。それをしないでください!あなたがするなら何が起こるか考えてみましょう。 ||の左側にあるGetMessage()コールがWM_QUIT(これ以降は参照できません)を検出すると、0を返します。これにより、||は右側のGetMessage()をコールします。 WM_QUITを呼び出し、後で新しいメッセージが到着するまでループをブロックします。あなたは一度だけループ繰り返しあたりGetMessage()を呼び出し、その後、必要に応じて、戻り値に基づいて行動する必要があります

    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. しかし、あなたはまたHWNDdon't do that!)でメッセージをフィルタリングしている、そしてそれが唯一のあるメッセージを返します。指定されたHWNDPostMessage()で投稿されました。 PostQuitMessage()は、そのWM_QUITメッセージをHWNDではなく、呼び出し元のスレッドの入力キューに送信します。したがって、フィルタリングではWM_QUITというメッセージは表示されません。 WM_QUITがループを解除するには、HWNDでフィルタリングを停止するか、少なくともフィルタリングされていない呼び出しを定期的に行う必要があります。

メッセージのループは、このようになります。この場合にthere is no need to handle -1 from GetMessage()!

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

注:これは、標準メッセージループです。

0

アプリを閉じるには、ウィンドウを破棄する必要があります。通常、それは、次のいずれかの方法で行われています:

  1. をごWM_CLOSEハンドラ呼び出しDestroyWindowを持っています。
  2. あなたのことをやった後にDefWindowProcメッセージを処理させてください。

WndProcは多少一般のものです。特にあなたがDestroyWindowを呼び出すかDefWindowProcがそれをやらせなければならないことを言っている、https://msdn.microsoft.com/en-us/library/windows/desktop/ms632617(v=vs.85).aspxを参照してください、WM_CLOSEの詳細について

{  
    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); 
} 

:私は通常、彼らのように書かれて参照してください。

+0

あなたは 'WndProc'がウィンドウで実行されたアクションの後に' switch'ディスパッチ動作を含むべきであることを意味しますか?どのようにボタンなどを置くべきですか?それで? –

+0

私が思い出しているように、ボタン操作のものは 'WM_COMMAND'ハンドラに入れます。 –

+0

申し訳ありません、私は初心者です。私はそれがどのように動作するのか理解できません。私がそれらを 'WM_COMMAND'ケースに入れると、それはプログラムには現れません。だから私は 'WM_COMMAND'ケースを何とかして強制する必要がありますか?さらに、プログラムによってWndProcが呼び出される方法は?そして、メッセージがOSからGetMessageにどのように来るのですか?そして、WM_PAINTに含めるべきものは何ですか? –