簡體   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