繁体   English   中英

Window Framework Win32 API 中的异常

[英]Exception in Window Framework Win32 API

我是 Win32 API 的新手,想创建一个窗口。 我有一个类(如下),但在return p_this->HandleMessages(msg, wParam, lParam);行出现异常return p_this->HandleMessages(msg, wParam, lParam); .

Window.h(我在一些 msdn 网站上得到了这个并在某种程度上进行了修改):

#include "BaseWin.h"

template<class D_CLASS>
class Window
    :public BaseWin
{
public:
    int returnValue;
private:
    static constexpr LPCSTR className = "Best Window in the UNIVERSE!";
public:
    // declare this fn in the inherited class and use as wnd proc
    virtual LRESULT HandleMessages(UINT msg, WPARAM wParam, LPARAM lParam) = 0;


    static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
        D_CLASS* p_this = nullptr;
        if (msg == WM_NCCREATE) {
            CREATESTRUCT* create = (CREATESTRUCT*)lParam;
            p_this = (D_CLASS*)create->lpCreateParams;
            SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)p_this);
        }
        else
            p_this = (D_CLASS*)GetWindowLongPtr(hwnd, GWLP_USERDATA);

        if (p_this)
            return p_this->HandleMessages(msg, wParam, lParam); // exception here
        else
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }

    Window(HWND parent, LPCSTR title, int id, const Point& pos, const Size& _size,
        int styles = WS_OVERLAPPEDWINDOW, int retVal = 0x45, int stylesEx = 0
    )
        :BaseWin(parent, pos, _size, id), returnValue(retVal)
    {
        WNDCLASSEX wc = { 0 };

        wc.cbSize = sizeof(wc);
        wc.style = CS_OWNDC;
        wc.lpfnWndProc = D_CLASS::WndProc;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hInstance = GetModuleHandle(nullptr);
        wc.hIcon = nullptr;
        wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
        wc.hbrBackground = nullptr;
        wc.lpszMenuName = nullptr;
        wc.lpszClassName = className;
        wc.hIconSm = nullptr;

        RegisterClassEx(&wc);

        HMENU _id = nullptr;
        if (!((styles & WS_CHILD) != WS_CHILD || id == -1))
            _id = (HMENU)ID;

        hWnd = CreateWindowEx(
            stylesEx,
            className, title,
            styles,
            Position.x, Position.y, size.x, size.y,
            parent, _id, GetModuleHandle(nullptr), this
        );

    }
    
    ~Window()
    {
        UnregisterClass(className, GetModuleHandle(nullptr));
        Destroy();
    }
};

我正在使用 Visual Studio,每当到达该行时,就会放置一个断点,没有详细信息可以推断出原因(它是: main.exe has encountered a breakpoint )。

主.cpp:

#include "Window.h"
#include "Button.h"

class MainWindow
    :public Window<MainWindow>
{
private:
    HMENU menuBar;
    HMENU menuIt;

    enum
    {
        BTN_KILL,
        M_QUIT,
        M_ADD_LOG
    };
public:
    MainWindow()
        :Window<MainWindow>(nullptr, "Useless Manger", -1, Point(CW_USEDEFAULT, CW_USEDEFAULT), Size(640, 480), normWinStyle)
    {
        Button* btn = new Button(hWnd, BTN_KILL, "Kill Me", Point(), Size(300, 100));

        menuBar = CreateMenu();
        menuIt = CreateMenu();
        AppendMenu(menuIt, MF_ENABLED, M_ADD_LOG, "Add Log");
        AppendMenu(menuBar, MF_ENABLED | MF_STRING, M_QUIT, "Quit");
        AppendMenu(menuBar, MF_POPUP, (UINT_PTR)menuIt, "Add");

        SetMenu(hWnd, menuBar);
    }


    LRESULT HandleMessages(UINT msg, WPARAM wParam, LPARAM lParam)
    {
        switch (msg)
        {
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
            EndPaint(hWnd, &ps);
            break;
        }
        case WM_COMMAND:
            if (LOWORD(wParam) == BTN_KILL)
            {
                PostQuitMessage(this->returnValue);
                break;
            }
        }

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


int CALLBACK WinMain(
    HINSTANCE hInst,
    HINSTANCE h_p_Inst,
    LPSTR     nCmdLine,
    int       nCmdShow)
{
    MainWindow* window = new MainWindow();
    window->Show();

    MSG msg;

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

    return msg.wParam;
}

BaswWin.h是一个持有当前HWNDpositionsizeID等的类,其中包含一些函数,如Show()

我该如何解决?

MainWindow::HandleMessages在超类Window<T>完全构造之前被调用。 Window<T>完全构造之前, Window<T>::HandleMessages条目指的是特殊函数女巫报告调用了纯函数。 完全构造Window<T> ,此条目将替换为MainWindow::HandleMessages 在 C++ 中调用虚函数时仍然构造超类需要特别注意。

您可以将Window<T>::HandleMessage替换为不纯的实现。

virtual LRESULT HandleMessages(UINT msg, WPARAM wParam, LPARAM lParam)
{
    return DefWindowProc(hWnd, msg, wparam, lparam);
}

尽早初始化hWnd ,因为可以在CreateWindowEx返回之前调用WndProc

static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    D_CLASS* p_this = nullptr;
    if (msg == WM_NCCREATE) {
        CREATESTRUCT* create = (CREATESTRUCT*)lParam;
        p_this = (D_CLASS*)create->lpCreateParams;
        // initialize early
        p_this->hWnd = hwnd;
        SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)p_this);
    }
    else
        p_this = (D_CLASS*)GetWindowLongPtr(hwnd, GWLP_USERDATA);

    if (p_this)
    // if you don't initialize early, skip when hWnd == nullptr
    // if (p_this && p_this->hWnd)
        return p_this->HandleMessages(msg, wParam, lParam);
    else
        return DefWindowProc(hwnd, msg, wParam, lParam);
}

MainWindow类已经被销毁时,您可能也会错过WM_DESTROY消息,但WM_DESTROY将在Window<T>::~Window<T>

调用PostQuitMessage(this->returnValue); MainWindow::~MainWindow可以解决这个问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM