Question

I have left some //Comments to help you navigate through the issue

I have 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;

};

And 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);
}

This is the exception I receive:

Unhandled exception at 0x001f1666 in Arena Clash client.exe: 0xC0000005: Access violation reading location 0x00000000.

I removed some code to make it easier to read. What happens is I get an unhandled exception. For reasons I don't understand, m_hWnd seems to have no value.

I've tried to find the solution for hours. Almost for all day actually. I really need help.

Actually, what I want is to redraw my image upon resize and similar changes.

Was it helpful?

Solution

You're passing NULL for the lpParam parameter (i.e. the last one) to CreateWindowEx.

Then, in WinProc, you say

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

So you'll set the user data pointer to NULL, as well.

You should pass thisto CreateWindowEx instead.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top