C ++ Windows没有获取任何消息

时间:2014-06-22 05:45:03

标签: c++ windows message

我正在创建一个简单的窗口但是当我看到窗口被创建并关闭它时,不会得到WM_QUIT消息。这是一些代码:

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR cmdLine, int cmdShow)
{
    cWindowApplication app(hInstance);

    const long width = 1024L;
    const long height = 768L;

    if (app.CreateWindowApplication(width, height) == false)
    {
        MessageBox(NULL, "Unable to create OpenGL Window", "An error occurred", MB_ICONERROR | MB_OK);
        app.DestroyWindowApplication();
        return 1;
    }

    return app.MainLoop();
}

这里是CreateWindowApplication(int,int)函数:

bool cWindowApplication::CreateWindowApplication(long width, long height, bool full_screen /*= false*/)
{
    DWORD dwExStyle;    // Window Extended Style
    DWORD dwStyle;      // Window Style

    mWindowRect.left = 0L;          // Set Left Value To 0
    mWindowRect.right = width;      // Set Right Value To Requested Width
    mWindowRect.top = 0L;           // Set Top Value To 0
    mWindowRect.bottom = height;    // Set Bottom Value To Requested Height

    mFullScreen = full_screen;

    // fill out the window class structure
    const char* class_name      = "MyClass";
    mWindowClass.cbSize         = sizeof(WNDCLASSEX);
    mWindowClass.style          = CS_HREDRAW | CS_VREDRAW;
    mWindowClass.lpfnWndProc    = cWindowApplication::StaticWindowsProcessCallback;
    mWindowClass.cbClsExtra     = 0;
    mWindowClass.cbWndExtra     = 0;
    mWindowClass.hInstance      = mhInstance;
    mWindowClass.hIcon          = LoadIcon(NULL, IDI_APPLICATION);          // default icon
    mWindowClass.hCursor        = LoadCursor(NULL, IDC_ARROW);              // default arrow
    mWindowClass.hbrBackground  = NULL;                                     // don't need background
    mWindowClass.lpszMenuName   = NULL;                                     // no menu
    mWindowClass.lpszClassName  = class_name;
    mWindowClass.hIconSm        = LoadIcon(NULL, IDI_WINLOGO);              // windows logo small icon

    // register the windows class
    if (!RegisterClassEx(&mWindowClass))
    {
        return false;
    }

    if (mFullScreen == true) //If we are Full Screen, we need to change the display mode                             
    {
        DEVMODE dmScreenSettings;                           // device mode

        memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
        dmScreenSettings.dmSize = sizeof(dmScreenSettings);

        dmScreenSettings.dmPelsWidth = width;               // screen width
        dmScreenSettings.dmPelsHeight = height;             // screen height
        dmScreenSettings.dmBitsPerPel = BITS_PER_PIXEL;     // bits per pixel
        dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;

        if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
        {
            // setting display mode failed, switch to windowed
            MessageBox(NULL, "Display mode failed", NULL, MB_OK);
            mFullScreen = false;
        }
    }

    if (mFullScreen == true)                // Are We Still In Full Screen Mode?
    {
        dwExStyle = WS_EX_APPWINDOW;        // Window Extended Style
        dwStyle =   WS_POPUP;               // Windows Style
        //ShowCursor(false);                  // Hide Mouse Pointer
    }
    else
    {
        dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;   // Window Extended Style
        dwStyle = WS_OVERLAPPEDWINDOW;                    // Windows Style
    }

    AdjustWindowRectEx(&mWindowRect, dwStyle, false, dwExStyle);     // Adjust Window To True Requested Size

    // class registered, and create our window
    mHWND = CreateWindowEx(NULL,                            // extended style
        class_name,                                         // class name
        "My Windows",                           // application name
        dwStyle | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
        0, 0,                                               // x,y coordinate
        mWindowRect.right - mWindowRect.left,
        mWindowRect.bottom - mWindowRect.top,               // width, height
        NULL,                                               // handle to parent
        NULL,                                               // handle to menu
        mhInstance,                                         // application instance
        this);                                              // this pointer to call member functions

    // check if window creation failed (hwnd would equal NULL)
    if (mHWND == false)
    {
        return false;
    }

    mHDC = GetDC(mHWND);

    ShowWindow(mHWND, SW_SHOW);          // display the window
    UpdateWindow(mHWND);                 // update the window
    return true;
}

基本上在这个函数调用之后,CreateWindowEx()函数将调用如下所示的StaticWindowProcessCallback():

LRESULT cWindowApplication::StaticWindowsProcessCallback(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    cWindowApplication* win_app = NULL;

    if (msg == WM_CREATE)
    {
        //Creation event
        //Get the pointer we pass during CreateWindowApplication() call
        win_app = (cWindowApplication*)((LPCREATESTRUCT)lParam)->lpCreateParams;

        //Associate window pointer with the hwnd for the other events to access
        SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)win_app);
    }
    else
    {
        //Non-creation event
        win_app = (cWindowApplication*)GetWindowLongPtr(wnd, GWLP_USERDATA);

        if (win_app != NULL)
        {
            return DefWindowProc(wnd, msg, wParam, lParam);
        }
    }

    //call member
    return win_app->WindowsProcessCallback(wnd, msg, wParam, lParam);
}

最后,此函数的最后一行调用如下所示的成员函数WindowProcessCallback():

LRESULT cWindowApplication::WindowsProcessCallback(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_CREATE:
    {
        mHDC = GetDC(wnd);
        SetupPixelFormat();
        //Set the version that we want, in this case 3.0
        int attribs[] = { WGL_CONTEXT_MAJOR_VERSION_ARB, 3, WGL_CONTEXT_MINOR_VERSION_ARB, 0, 0 };  //zero indicates the end of the array
        //Create temporary context so we can get a pointer to the function
        HGLRC tmp_context = wglCreateContext(mHDC);
        //Make it current
        wglMakeCurrent(mHDC, tmp_context);

        PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL;
        wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB");

        if (wglCreateContextAttribsARB == NULL)
        {
            //No OpenGL 3.0, back to 2.0
            mHGLRC = tmp_context;
        }
        else
        {
            //Create OpenGL 3.0
            mHGLRC = wglCreateContextAttribsARB(mHDC, 0, attribs);
            //Delete the temp context
            wglDeleteContext(tmp_context);
        }

        //Make OpenGL 3.0
        wglMakeCurrent(mHDC, mHGLRC);
        mIsRunning = true;
    }
        break;
    case WM_QUIT:
    case WM_DESTROY:
    case WM_CLOSE:
        wglMakeCurrent(mHDC, NULL);
        wglDeleteContext(mHGLRC);
        mIsRunning = false;
        PostQuitMessage(0); //Send a WM_QUIT message
        return 0;
    default:
        break;
    }

    return DefWindowProc(wnd, msg, wParam, lParam);
}

正如您所看到的,那里有一些消息处理代码......但除了WM_CREATE之外,没有其他案例被击中。发送WM_CREATE消息后,正在调用函数MainLoop(),如下所示:

int cWindowApplication::MainLoop()
{
    while (mIsRunning == true)
    {
        ProcessWindowsMessages();
    }

    DestroyWindowApplication();
    return 0;
}

基本上,ProcessWindowsMessages()函数在窗口关闭后没有得到任何消息......我必须按停止VS来运行才能终止进程。 ProcessWindowsMessages()函数如下所示:

void cWindowApplication::ProcessWindowsMessages()
{
    MSG msg;

    if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

1 个答案:

答案 0 :(得分:2)

StaticWindowsProcessCallback中的这个逻辑向后看:

    if (win_app != NULL)
    {
        return DefWindowProc(wnd, msg, wParam, lParam);
    }

如果您没有指向窗口包装器对象的指针,则需要调用DefWindowProc。所以这应该发生if (win_app == NULL)。这是为了处理在WM_CREATE之前发送的少量消息。因此,您的代码在WM_CREATE之前处理的邮件上具有未定义的行为,并在WM_CREATE之后丢弃(通过应用默认处理)所有邮件。

但是,使用WM_NCCREATE设置链接会更好。同样,win_app也不是一个非常好的名称,可能win_obj或其他。

您也不应该在窗口过程中处理WM_QUIT,因为它不会被发送到窗口。 WM_CLOSE的默认行为应该没问题,它会调用DestroyWindow来触发WM_DESTROY

但是第一个,未能将WM_CREATE之后的任何消息转发到您的窗口过程,可能会解释您在主消息循环中缺少WM_QUIT