DirectX 11 引擎在第三次代码改进后突然 运行 了,我不知道为什么

DirectX 11 engine is not running suddenly after third code improvement and I don't know why

我正在学习使用 DirectX 11 引擎的 C++ 游戏教程。在前两部分中,我的代码没有问题,但在第三部分(创建交换链)中,DirectX window 决定不显示,让我使用控制台。我真的不知道如何描述代码,所以我将插入所有 类、头文件等。 main.cpp:

#include "AppWindow.h"



int main()
{
    AppWindow app;
    if (app.Init())
    {
        while (app.isRun())
        {
            app.brodcast();
        }




    }



    return 0;
}

AppWindow.cpp:

#include "AppWindow.h"

void AppWindow::onCreate()
{
    GraphicsEngine::get()->init();
    m_swap_chain = GraphicsEngine::get()->crreateSwapChain();

    RECT rc = this->getClientWindowRect();
    m_swap_chain->init(this->m_hwnd, rc.right-rc.left, rc.bottom-rc.top);





}

void AppWindow::onUpdate()
{
}

void AppWindow::onDestroy()
{
    Window::onDestroy();
    GraphicsEngine::get()->release();
}

AppWindow.h:

#pragma once
#include "Window.h"
#include "GraphicsEngine.h"
#include "SwapChain.h"


class AppWindow: public Window
{
public:
    // Inherited via Window
    virtual void onCreate() override;
    virtual void onUpdate() override;
    virtual void onDestroy() override;
private:
    SwapChain * m_swap_chain;
};

Window.cpp:

#include "Window.h"


Window* window = nullptr;




LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
    switch (msg)
    {
    case WM_CREATE:
    {
        //Event fired when the window will be created
        //collected here...
        Window* window = (Window*)((LPCREATESTRUCT)lparam)->lpCreateParams;
        //...and then stored here for later look up
        SetWindowLongPtr(hwnd, GWL_USERDATA, (LONG_PTR)window);
        window->setHWND(hwnd);
        window->onCreate();
        break;
    }

    case WM_DESTROY:
    {
        //Event fired when the window will be destroyed
        window->onDestroy();
        ::PostQuitMessage(0);
        break;
    }


    default:
        return ::DefWindowProc(hwnd, msg, wparam, lparam);



    }

    return NULL;
}


bool Window::Init()
{
    WNDCLASSEX wc;
    wc.cbClsExtra = NULL;
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.cbWndExtra = NULL;
    wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    wc.hInstance = NULL;
    wc.lpszClassName = "MyWindowClass";
    wc.lpszMenuName = "";
    wc.style = NULL;
    wc.lpfnWndProc = &WndProc;

    if (!::RegisterClassEx(&wc)) //if the registration of the class will fail, the function will return false
        return false;
    if (!window)
        window = this;
    //creation of the window
    m_hwnd=::CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, "MyWindowClass", "DirectX Application", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 1024, 768, NULL, NULL, NULL, NULL);

    //if the creation fails then the method will return false
    if (!m_hwnd)
        return false;

    //show up the window
    ::ShowWindow(m_hwnd, SW_SHOW);
    ::UpdateWindow(m_hwnd);


    //set this flag to  true to indicate that the window is initialized and running
    m_is_run = true;

    return true;
}

bool Window::brodcast()
{
    MSG msg;

    while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);


    }

    window->onUpdate();

    Sleep(0);

    return true;
}

bool Window::Release()
{
    //destroy the window
    if (!::DestroyWindow(m_hwnd))
        return false;


    return true;
}

void Window::onDestroy()
{
    m_is_run = false;
}

bool Window::isRun()
{
    return m_is_run;
}

RECT Window::getClientWindowRect()
{
    RECT rc;
    ::GetClientRect(this->m_hwnd, &rc);
    return rc;
}

void Window::setHWND(HWND hwnd)
{
    this->m_hwnd = hwnd;
}

Window.h:

#pragma once
#include <windows.h>





class Window
{
public:
    //Initialize the window
    bool Init();
    bool brodcast();
    //Release the window
    bool Release();
    bool isRun();

    RECT getClientWindowRect();
    void setHWND(HWND hwnd);

    //EVENTS
    virtual void onCreate()=0;
    virtual void onUpdate()=0;
    virtual void onDestroy()=0;

protected:
    HWND m_hwnd;
    bool m_is_run;
};

GraphicsEngine.cpp:

#include "GraphicsEngine.h"
#include <d3d11.h>
#include "SwapChain.h"


bool GraphicsEngine::init()
{
    D3D_DRIVER_TYPE driver_types[] =
    {
        D3D_DRIVER_TYPE_HARDWARE,
        D3D_DRIVER_TYPE_WARP,
        D3D_DRIVER_TYPE_REFERENCE
    };
    UINT num_driver_types = ARRAYSIZE(driver_types);

    D3D_FEATURE_LEVEL feature_levels[]=
    {
        D3D_FEATURE_LEVEL_11_0
    };
    UINT num_feature_levels = ARRAYSIZE(feature_levels);

    HRESULT res = 0;
    for (UINT driver_type_index = 0; driver_type_index < num_driver_types;)
    {
        res = D3D11CreateDevice(NULL, driver_types[driver_type_index], NULL, NULL, feature_levels, 
            num_feature_levels, D3D10_1_SDK_VERSION, &m_d3d_device, &m_feature_level, &m_imm_context);

        if (SUCCEEDED(res))
            break;

        ++driver_type_index;
    }

    if (FAILED(res))
    {
        return false;
    }

    m_d3d_device->QueryInterface(__uuidof(IDXGIDevice), (void**)&m_dxgi_device);
    m_dxgi_device->GetParent(__uuidof(IDXGIAdapter), (void**)&m_dxgi_adapter);
    m_dxgi_adapter->GetParent(__uuidof(IDXGIFactory), (void**)&m_dxgi_factory);
    return true;
}

bool GraphicsEngine::release()
{
    m_dxgi_device->Release();
    m_dxgi_adapter->Release();
    m_dxgi_factory->Release();
    m_imm_context->Release();
    m_d3d_device->Release();

    return true;
}

GraphicsEngine * GraphicsEngine::get()
{
    static GraphicsEngine engine;
    return &engine;
}

SwapChain * GraphicsEngine::crreateSwapChain()
{
    return new SwapChain();
}

GraphicsEngine.h

#pragma once
#include <d3d11.h>

class SwapChain;

class GraphicsEngine
{
public:
    //initialize graphics engine and DirectX 11 device
    bool init();
    //release all the resources loaded
    bool release();

    static GraphicsEngine* get();

    SwapChain* crreateSwapChain();
private:
    ID3D11Device * m_d3d_device;
    D3D_FEATURE_LEVEL m_feature_level;
    ID3D11DeviceContext * m_imm_context;
    IDXGIDevice * m_dxgi_device;
    IDXGIAdapter * m_dxgi_adapter;
    IDXGIFactory * m_dxgi_factory;
    friend class SwapChain;

};

SwapChain.cpp:

#include "SwapChain.h"
#include "GraphicsEngine.h"

bool SwapChain::init(HWND hwnd, UINT width, UINT height)
{
    ID3D11Device *device = GraphicsEngine::get()->m_d3d_device;

    DXGI_SWAP_CHAIN_DESC desc;
    ZeroMemory(&desc, sizeof(desc));
    desc.BufferCount = 1;
    desc.BufferDesc.Width = width;
    desc.BufferDesc.Height = height;
    desc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
    desc.BufferDesc.RefreshRate.Numerator = 60;
    desc.BufferDesc.RefreshRate.Denominator = 1;
    desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    desc.OutputWindow = hwnd;
    desc.SampleDesc.Count = 1;
    desc.SampleDesc.Quality = 0;
    desc.Windowed = TRUE;

    //Create the SwapChain for the window initialized by the HWND paramater
    HRESULT hr = GraphicsEngine::get()->m_dxgi_factory->CreateSwapChain(device, &desc, &m_swap_chain);

    if (FAILED(hr))
    {
        return false;
    }



    return true;
}

bool SwapChain::release()
{
    m_swap_chain->Release();
    delete this;
    return true;
}

SwapChain.h:

#pragma once
#include <d3d11.h>
class SwapChain
{
public:
    //Initialize a SwapChain for a window
    bool init(HWND hwnd, UINT width, UINT height);
    //release the SwapChain
    bool release();
private:
    IDXGISwapChain* m_swap_chain;
};

在 window.cpp 中我得到一个异常->m_hwnd = hwnd;

问题出在这行代码中:

Window* window = (Window*)((LPCREATESTRUCT)lparam)->lpCreateParams;

传入的lparam是空值,使window成为空指针,最终导致访问错误

如何解决?

调用CreateWindowEx时,需要在最后的void*参数中传递一个指向Windowclass的指针。

//creation of the window
m_hwnd = ::CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, "MyWindowClass", "DirectX Application", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 1024, 768, NULL, NULL, NULL, window);

注意:(您可能遇到的问题)

If the Direct3D 11.1 runtime is present on the computer and pFeatureLevels is set to NULL, this function won't create a D3D_FEATURE_LEVEL_11_1 device. To create a D3D_FEATURE_LEVEL_11_1 device, you must explicitly provide a D3D_FEATURE_LEVEL array that includes D3D_FEATURE_LEVEL_11_1. If you provide a D3D_FEATURE_LEVEL array that contains D3D_FEATURE_LEVEL_11_1 on a computer that doesn't have the Direct3D 11.1 runtime installed, this function immediately fails with E_INVALIDARG.

参考:D3D11CreateDevice function

您可能需要在 D3D11CreateDevice 中使用 D3D11_SDK_VERSION 而不是 D3D10_1_SDK_VERSION

参考:How To: Get the Device Feature Level