【问题标题】:C++ Windows Not Getting Any MessagesC++ Windows 没有收到任何消息
【发布时间】:2014-06-22 05:45:02
【问题描述】:

我正在创建一个简单的窗口,但是当我看到正在创建的窗口并关闭它时,没有收到 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);
    }
}

【问题讨论】:

  • 可能是因为您应该能够使用调试器找到它,如果您知道它应该如何表现的话。当您引入第三方代码时,请确保您理解它。
  • 如果是这样的话,这个网站就没有必要了。
  • 您可能会阅读一些常见问题解答。该站点不应该用于调试帮助。您的问题的问题是,即使将来有人遇到完全相同的问题,他们也无法找到您的问题和我的解决方案。 (不是你的错;我也想不出一个好的标题或搜索词)
  • 好的,我会尽力的。当您连续几天尝试调试但仍然不知道出了什么问题时,这很难。
  • 无论如何,很高兴它现在可以工作了。

标签: c++ windows message


【解决方案1】:

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

【讨论】:

  • 谢谢你,这解释了一切。我正在查看其他来源的代码,他们有 if(!win_app) ...我翻译错误。
猜你喜欢
  • 2018-11-21
  • 1970-01-01
  • 2018-04-09
  • 1970-01-01
  • 1970-01-01
  • 2017-04-01
  • 2016-06-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多