infine windows消息循环-c++

infine windows message loop - c++

本文关键字:-c++ 循环 消息 windows infine      更新时间:2023-10-16

我试图创建这个窗口类,它创建并显示一个窗口。当我运行这个类时,GetMessage会继续发送WM_PAINT消息,任务管理器会向我显示仅来自进程的大约50%的CPU使用率。

main.cpp:

#include "Window.h"
int WINAPI WinMain(
    HINSTANCE /* hInstance */,
    HINSTANCE /* hPrevInstance */,
    LPSTR /* lpCmdLine */,
    int /* nCmdShow */
    )
{
    Window::GlobalInitialize();
    Window window(L"abcd", 500, 500);
    if (SUCCEEDED(window.Initialize()))
        window.RunMessageLoop();
    Window::GlobalTerminate();
    return 0;
}

窗口.h:

#ifndef WINDOW_HEADER
#define WINDOW_HEADER
#include <Windows.h>
#include <functional>
#pragma comment(lib, "d2d1.lib")
class Window;
typedef std::function<void(Window *window, UINT id, LPCWSTR message)> ErrorCallback;
class Window {
public:
#define ERROR_FAILED_HINSTANCE 1
#define ERROR_FAILED_HINSTANCE_STR L"Failed to retrieve hInstance"
#define ERROR_FAILED_REGISTER 2
#define ERROR_FAILED_REGISTER_STR L"Failed to register window class"
#define ERROR_FAILED_CREATION 3
#define ERROR_FAILED_CREATION_STR L"Failed to create window"
    typedef std::function<HRESULT(Window *window)> WEOnCreate;
    typedef std::function<HRESULT(Window *window)> WEOnDestroy;
    typedef std::function<HRESULT(Window *window)> WEOnRender;
    typedef std::function<HRESULT(Window *window, UINT width, UINT height)> WEOnResize;
    typedef std::function<HRESULT(Window *window, UINT horizontalResolution, UINT verticalResolution)> WEOnScreenResolutionChange;
    Window(LPCWSTR title, UINT width, UINT height);
    ~Window();
    HRESULT SetSize(UINT width, UINT height);
    HRESULT SetTitle(LPCWSTR title);
    inline UINT GetWidth() { return _width; }
    inline UINT GetHeight() { return _height; }
    inline LPCWSTR GetTitle() { return _title; }
    inline HWND GetHandle() { return hWnd; }
    inline void SetOnCreateCallback(WEOnCreate fun) { _onCreate = fun; }
    inline void SetOnDestroyCallback(WEOnDestroy fun) { _onDestroy = fun; }
    inline void SetOnRenderCallback(WEOnRender fun) { _onRender = fun; }
    inline void SetOnResizeCallback(WEOnResize fun) { _onResize = fun; }
    inline void SetOnScreenResolutionChangeCallback(WEOnScreenResolutionChange fun) { _onResChange = fun; }
    inline void SetExtraAllocatedSpace(void *ptr) { extra = ptr; }
    inline void *GetExtraAllocatedSpace() { return extra; }
    inline void Terminate() { if (hWnd) DestroyWindow(hWnd); }
    static inline void SetErrorCallback(ErrorCallback fun) { _errorCallback = fun; }
    HRESULT Initialize();
    void RunMessageLoop();
    static HRESULT GlobalInitialize();
    static HRESULT GlobalTerminate();
private:
    static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
    static inline void throwError(Window *window, UINT id, LPCWSTR message) {
        if (_errorCallback)
            _errorCallback(window, id, message);
    }
    WEOnCreate _onCreate;
    WEOnDestroy _onDestroy;
    WEOnRender _onRender;
    WEOnResize _onResize;
    WEOnScreenResolutionChange _onResChange;
    static ErrorCallback _errorCallback;
    static LPCWSTR szClassName;
    static HINSTANCE hInstance;
    HWND hWnd;
    int _width, _height;
    LPCWSTR _title;
    void *extra;
};
#endif

Window.cpp:

#include "Window.h"
//Initialize static variables
ErrorCallback Window::_errorCallback = nullptr;
LPCWSTR Window::szClassName = L"WindowClass";
HINSTANCE Window::hInstance;
Window::Window(LPCWSTR title = L"Window", UINT width = 640, UINT height = 480) :
_onCreate(nullptr),
_onDestroy(nullptr),
_onRender(nullptr),
_onResize(nullptr),
hWnd(NULL),
extra(NULL), 
_width(width),
_height(height),
_title(title) {}
Window::~Window() {
    if (hWnd) {
        DestroyWindow(hWnd);
        hWnd = NULL;
    }
}
HRESULT Window::GlobalInitialize() {
    // Retreive hInstance
    hInstance = GetModuleHandle(NULL);
    if (!hInstance) {
        throwError(NULL, ERROR_FAILED_HINSTANCE, ERROR_FAILED_HINSTANCE_STR);
        return E_FAIL;
    }
    // Create window class
    WNDCLASSEX wcex = {};
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = Window::WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = sizeof(LONG_PTR);
    wcex.hInstance = hInstance;
    wcex.hbrBackground = NULL;
    wcex.lpszMenuName = NULL;
    wcex.hCursor = LoadCursor(NULL, IDI_APPLICATION);
    wcex.lpszClassName = szClassName;
    if (!RegisterClassEx(&wcex)) {
        throwError(NULL, ERROR_FAILED_REGISTER, ERROR_FAILED_REGISTER_STR);
        return E_FAIL;
    }
    return S_OK;
}
HRESULT Window::GlobalTerminate() {
    if (UnregisterClass(szClassName, hInstance))
        return S_OK;
    else
        return E_FAIL;
}
void Window::RunMessageLoop() {
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}
HRESULT Window::Initialize() {
    // Create the window
    hWnd = CreateWindow(
        szClassName,
        _title,
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        _width,
        _height,
        NULL,
        NULL,
        hInstance,
        this
        );
    if (!hWnd) {
        throwError(this, ERROR_FAILED_CREATION, ERROR_FAILED_CREATION_STR);
        return E_FAIL;
    }
    // Show and render the window
    ShowWindow(hWnd, SW_SHOW);
    UpdateWindow(hWnd);
    return S_OK;
}
LRESULT CALLBACK Window::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    if (message == WM_CREATE) {
        LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam;
        Window *window = (Window *)pcs->lpCreateParams;
        ::SetWindowLongPtr(hWnd, GWLP_USERDATA, PtrToUlong(window));
        if (window->_onCreate != nullptr)
            window->_onCreate(window);

    }
    Window *pWnd = reinterpret_cast<Window *>(static_cast<LONG_PTR>(GetWindowLongPtr(hWnd, GWLP_USERDATA)));
    HRESULT hr = S_OK;
    if (!pWnd) {
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    switch (message) {
    case WM_PAINT:
    {
                     if (pWnd->_onRender)
                         hr = pWnd->_onRender(pWnd);
                     else
                         hr = S_OK;
    }
        break;
    case WM_SIZE:
    {
                    if (pWnd->_onResize)
                        hr = pWnd->_onResize(pWnd, LOWORD(lParam), HIWORD(lParam));
                    else
                        hr = S_OK;
    }
        break;
    case WM_DISPLAYCHANGE:
    {
                    if (pWnd->_onResChange)
                        hr = pWnd->_onResChange(pWnd, LOWORD(lParam), HIWORD(lParam));
                    else
                        hr = S_OK;
    }
        break;
    case WM_DESTROY:
    {
                    if (pWnd->_onDestroy && FAILED(pWnd->_onDestroy(pWnd)))
                        break;
    }
        PostQuitMessage(0);
        hWnd = NULL;
        break;
    default:
        hr = DefWindowProc(hWnd, message, wParam, lParam);
    }
    return hr;
}
HRESULT Window::SetSize(UINT width, UINT height) {
    if (hWnd)
    if (!::SetWindowPos(hWnd, 0, 0, 0, width, height, SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER))
        return E_FAIL;
    _width = width;
    _height = height;
    return S_OK;
}
HRESULT Window::SetTitle(LPCWSTR title) {
    if (hWnd)
    if (!::SetWindowText(hWnd, title))
        return E_FAIL;
    _title = title;
    return S_OK;
}

我希望有人能帮助我,因为一切看起来都很好(窗户甚至开得很好)。

首先,您似乎将窗口过程视为COM方法,但窗口过程不会返回HRESULT,而是返回LRESULT,每个消息的含义不同。

WM_PAINT的情况下,不可能返回指示"我这次不需要绘画"的值。只要窗口的一部分被标记为脏,系统就会发送WM_PAINT消息,而将脏区域标记为"已绘制"的方法是调用BeginPaintEndPaint。如果您不这样做,系统将继续认为您的窗口是脏的,并继续发送WM_PAINT消息。

您还没有显示_onRender函数的源代码,但您将WM_PAINT处理设置为可选的(即,如果没有任何调用SetOnRenderCallback,则不会注册回调),这意味着您可能没有正确处理WM_PAINT。至少,如果您不自己绘制,您应该将消息传递给DefWindowProc,以便进行默认处理。