为什么这段代码(几乎与 MSDN 中的代码相同)不起作用?

Why wont this code, almost identical to one from MSDN, won't work?

本文关键字:代码 不起作用 MSDN 段代码 为什么      更新时间:2023-10-16

我已经留下了一些//评论来帮助你浏览这个问题

我有Main.cpp

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nShowCmd)
{
    Game game;
    game.Initialize(hInst);
    game.MainMenu();
    while(GetMessage(&msg,NULL,0,0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return 0;
}

Game.h

#pragma once
#define WIN32_LEAN_AND_MEAN
/*Various includes*/
template<class Interface>
inline void SafeRelease(Interface** ppInterfaceToRelease)
{
    if (*ppInterfaceToRelease != NULL)
    {
        (*ppInterfaceToRelease)->Release();
        (*ppInterfaceToRelease) = NULL;
    }
}

class Game{
public:
    Game();
    ~Game();
    HRESULT Initialize(HINSTANCE);
    void MainMenu();
    void OnResize(UINT width, UINT height);
    void OnRender();
private:
    static LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
private:
    HWND m_hWnd;
    ID2D1Factory* pD2DFactory;
    ID2D1HwndRenderTarget* pRT;
};

和Game.cpp

#include "Game.h"
#include <comdef.h>
Game::Game() :
    pD2DFactory(NULL),
    pRT(NULL)
{
}
Game::~Game()
{
    SafeRelease(&pD2DFactory);
    SafeRelease(&pRT);
}
HRESULT Game::Initialize(HINSTANCE hInst)
{
    HRESULT hr;
    // Create factory
    hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pD2DFactory);
    // Create a window class
    WNDCLASSEX wClass;
    ZeroMemory(&wClass,sizeof(WNDCLASSEX));
    wClass.cbClsExtra=NULL;
    wClass.cbSize=sizeof(WNDCLASSEX);
    wClass.cbWndExtra=NULL;
    wClass.hbrBackground=(HBRUSH)COLOR_WINDOW;
    wClass.hCursor=LoadCursor(NULL,IDC_ARROW);
    wClass.hIcon=NULL;
    wClass.hIconSm=NULL;
    wClass.hInstance=hInst;
    wClass.lpfnWndProc=Game::WinProc;
    wClass.lpszClassName="Window Class";
    wClass.lpszMenuName=NULL;
    wClass.style=CS_HREDRAW|CS_VREDRAW;
    m_hWnd=CreateWindowEx(NULL,
            "Window Class",
            "Game", // Replace with gameName
            WS_OVERLAPPEDWINDOW|WS_MAXIMIZE,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            NULL,
            NULL,
            hInst,
            NULL);
    RECT rc;
    GetClientRect(m_hWnd,&rc);
    // Creates render target
    if(SUCCEEDED(hr))
    {
        pD2DFactory->CreateHwndRenderTarget(
        D2D1::RenderTargetProperties(),
        D2D1::HwndRenderTargetProperties(
                                        m_hWnd,
                                        D2D1::SizeU(
                                                rc.right - rc.left,
                                                rc.bottom - rc.top)),
                                        &pRT);
    }
    ShowWindow(m_hWnd,SW_MAXIMIZE); //When my program gets there, WinProc gets called with the WM_PAINT message. The problem then happens.
    UpdateWindow(m_hWnd);
    return hr;
}
void Game::OnRender()
{
    // The following code will eventually be deleted. It is left for test purpose only.
    HRESULT hr;
    RECT rc;
    GetClientRect(m_hWnd,&rc); // The error happens when my program gets to this line of code.
    ID2D1SolidColorBrush* pBlackBrush = NULL;
            pRT->CreateSolidColorBrush(
                D2D1::ColorF(D2D1::ColorF::White),
                &pBlackBrush);
            pRT->BeginDraw();
            pRT->DrawRectangle(
                D2D1::RectF(
                    rc.left + 100.0f,
                    rc.top + 100.0f,
                    rc.right - 100.0f,
                    rc.bottom - 100.0f),
                    pBlackBrush);
            hr = pRT->EndDraw();
}
LRESULT Game::WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    if(msg==WM_CREATE)
    {
        LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam;
            Game* pGame = (Game*)pcs->lpCreateParams;
            ::SetWindowLongPtrW(
                hWnd,
                GWLP_USERDATA,
                PtrToUlong(pGame)
                );
    }
    else
    {
        Game* pGame = reinterpret_cast<Game*>(static_cast<LONG_PTR>(
            ::GetWindowLongPtrW(
                hWnd,
                GWLP_USERDATA
                )));
        switch(msg)
        {
        case WM_PAINT:
            {
                pGame->OnRender();
                ValidateRect(hWnd, NULL);
            }
            break;
        case WM_SIZE:
            {
                UINT width = LOWORD(lParam);
                UINT height = HIWORD(lParam);
                pGame->OnResize(width, height); //OnResize is called here
            }
            break;
        case WM_DISPLAYCHANGE:
            {
                InvalidateRect(hWnd, NULL, FALSE);
            }
            break;
        case WM_DESTROY:
            {
                //SafeRelease(p2D2Factory);
                PostQuitMessage(0);
                return 0;
            }
            break;
        }
    }
        return DefWindowProc(hWnd,msg,wParam,lParam);
}

这是我收到的异常:

在Arena Clash client.exe中0x001f1666的未处理异常:0xC0000005:访问违反读取位置0x00000000.

我删除了一些代码,使其更容易阅读。我得到一个未处理的异常。由于我不明白的原因,m_hWnd似乎没有价值。

我花了好几个小时试图找到解决办法。实际上几乎是一整天。我真的需要帮助。

实际上,我想要的是重新绘制我的图像在调整大小和类似的变化

您将lpParam参数(即最后一个)传递NULL给CreateWindowEx

然后,在WinProc中,你说

Game* pGame = (Game*)pcs->lpCreateParams;
::SetWindowLongPtrW(
            hWnd,
            GWLP_USERDATA,
            PtrToUlong(pGame)
            );

所以你也会将用户数据指针设置为NULL。

您应该将this传递给CreateWindowEx