1

我在 VS 2010 中设置 DirectX 9(与问题无关。我认为)框架时遇到了一个非常令人沮丧的问题。这是我的 DirectX 框架:

#ifndef _DX9_H_
#define _DX9_H_

// window includes
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>

// required for ush typedef and window properties to setup backbuffer
#include "sys_params.h"

// directx9 includes
#define DIRECTINPUT_VERSION 0x0800
#include <d3dx9.h>
#include <dinput.h>
#include <DxErr.h>
#include <vector>
#include <iterator>

// directx9 libraries
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")
#pragma comment(lib, "dinput8.lib")
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "dxerr.lib")

namespace nsdx9
{
    using nssysprms::ush;

    #define CheckHR(hr) CheckForDXError(__FILE__, __LINE__, hr)

    class DX9
    {
        public:
            DX9(HINSTANCE& inst, int cmdShow, const std::string& title, ush wndwidth, ush wndheight, short wndx, short wndy);
            ~DX9();

            // windows message processor
            UINT ProcessMessages();

            // --- DIRECTX GAME FUNCTIONS --- //
            // input functions
            void InputUpdate();
            BYTE KeyHeld(ush key);
            bool KeyPressed(ush key);

            // sprite functions
            const LPD3DXSPRITE& GetSpriteInterface();
            void SpriteBeginDraw(DWORD flags = D3DXSPRITE_ALPHABLEND);
            void SpriteEndDraw();

            // font functions
            void MakeFont(int height, int width, UINT weight = FW_DONTCARE, LPCSTR face = "Calibri", bool italic = false);
            const LPD3DXFONT& GetFontAtIndex(ush index);
            const std::vector<LPD3DXFONT>& GetFontVector();
            // --- END DIRECTX GAME FUNCTIONS --- //

        private:
            // --- WINDOW FUNCTIONS/VARIABLES --- //
            WNDCLASSEX _wc;
            HWND _hwnd;
            MSG _msg;

            HINSTANCE _inst;
            std::string _title;

            static LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wprm, LPARAM lprm);
            // --- END WINDOW FUNCTIONS/VARIABLES --- //

            // --- DIRECTX FUNCTIONS/VARIABLES --- //
            // D3D interfaces
            LPDIRECT3D9 _d3d;
            LPDIRECT3DDEVICE9 _d3ddev;
            D3DPRESENT_PARAMETERS _d3dpp;

            // directinput interfaces
            LPDIRECTINPUT8 _dInput;
            LPDIRECTINPUTDEVICE8 _diMouse;
            LPDIRECTINPUTDEVICE8 _diKeyboard;

            DIMOUSESTATE _mouseState;
            BYTE _keys[256];
            bool _keyStates[256];
            bool _keyboardStateChanged;

            void AcquireInputDevice(const LPDIRECTINPUTDEVICE8& dev);

            // sprite interfaces
            LPD3DXSPRITE _spriteBatch;

            // font vector
            std::vector<LPD3DXFONT> _fonts;

            // hresult checker, for debugging only
            void CheckForDXError(const char *file, int line, HRESULT hr);
            // --- END DIRECTX FUNCTIONS/VARIABLES --- //
    };

    /*=================================================*/
    /*--------------DIRECTX CONSTRUCTOR----------------*/
    /*=================================================*/
    DX9::DX9(HINSTANCE& inst, int cmdShow, const std::string& title, ush wndwidth, ush wndheight, short wndx, short wndy)
    {
        /*=================================================*/
        /*--------------WINDOW INITIALIZATION--------------*/
        /*=================================================*/
        _title = title;
        _inst = inst;

        // init window class struct
        _wc.cbClsExtra = NULL;
        _wc.cbSize = sizeof(WNDCLASSEX);
        _wc.cbWndExtra = NULL;
        _wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
        _wc.hCursor = LoadCursor(NULL, IDC_ARROW);
        _wc.hIcon = NULL;
        _wc.hIconSm = NULL;
        _wc.hInstance = inst;
        _wc.lpfnWndProc = (WNDPROC)WinProc;
        _wc.lpszClassName = title.c_str();
        _wc.lpszMenuName = NULL;
        _wc.style = CS_HREDRAW | CS_VREDRAW;
        RegisterClassEx(&_wc);

        // create handle to the window
        _hwnd = CreateWindow(title.c_str(),
                             title.c_str(),
                             WS_OVERLAPPEDWINDOW, 
                             wndx,
                             wndy,
                             wndwidth,
                             wndheight,
                             NULL,
                             NULL,
                             inst,
                             NULL);

        // required to make the window show up
        ShowWindow(_hwnd, cmdShow);
        UpdateWindow(_hwnd);
        /*=================================================*/
        /*--------------END WINDOW INITIALIZATION----------*/
        /*=================================================*/
        /*=================================================*/
        /*--------------DIRECTX INITIALIZATION-------------*/
        /*=================================================*/
        // --- INITIALIZE DIRECTX9 VARIABLES --- //
        SecureZeroMemory(&_d3dpp, sizeof(_d3dpp));
        SecureZeroMemory(&_mouseState, sizeof(_mouseState));
        SecureZeroMemory(&_keys, sizeof(_keys));

        for (int i = 0; i < 256; i++)
        {
            _keyStates[i] = true;
        }

        _d3d = NULL;
        _d3ddev = NULL;
        _dInput = NULL;
        _diMouse = NULL;
        _diKeyboard = NULL;
        _keyboardStateChanged = false;
        _spriteBatch = NULL;
        // --- END INITIALIZE DIRECTX9 VARIABLES --- //

        // --- DIRECTX9 INITIALIZATION --- //
        _d3d = Direct3DCreate9(D3D_SDK_VERSION);

        if (!_d3d)
        {
            OutputDebugString("Error: Failed to create Direct3D.\n");
        }

        // set d3d present parameters
        _d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
        _d3dpp.BackBufferCount = 1;
        _d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
        _d3dpp.BackBufferHeight = nssysprms::WND_HEIGHT;
        _d3dpp.BackBufferWidth = nssysprms::WND_WIDTH;
        _d3dpp.EnableAutoDepthStencil = 1;
        _d3dpp.Flags = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
        //_d3dpp.FullScreen_RefreshRateInHz
        _d3dpp.hDeviceWindow = _hwnd;
        //_d3dpp.MultiSampleQuality
        //_d3dpp.MultiSampleType
        _d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
        _d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
        _d3dpp.Windowed = nssysprms::isWindowed;

        // create d3d device
        CheckHR(_d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, _hwnd, D3DCREATE_MIXED_VERTEXPROCESSING, &_d3dpp, &_d3ddev));
        // --- END DIRECTX9 INITIALIZATION --- //

        // --- INITIALIZE DIRECTINPUT --- //
        CheckHR(DirectInput8Create(inst, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&_dInput, NULL));

        // create mouse and keyboard
        CheckHR(_dInput->CreateDevice(GUID_SysKeyboard, &_diKeyboard, NULL));
        CheckHR(_dInput->CreateDevice(GUID_SysMouse, &_diMouse, NULL));

        // initialize keyboard
        CheckHR(_diKeyboard->SetDataFormat(&c_dfDIKeyboard));
        CheckHR(_diKeyboard->SetCooperativeLevel(_hwnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND));
        AcquireInputDevice(_diKeyboard);

        // initialize mouse
        CheckHR(_diMouse->SetDataFormat(&c_dfDIMouse));
        CheckHR(_diMouse->SetCooperativeLevel(_hwnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND));
        AcquireInputDevice(_diMouse);

        // create sprite object
        CheckHR(D3DXCreateSprite(_d3ddev, &_spriteBatch));
        // --- END INITIALIZE DIRECTINPUT --- //
        /*=================================================*/
        /*--------------END DIRECTX INITIALIZATION---------*/
        /*=================================================*/
    }
    /*=================================================*/
    /*--------------END DIRECTX CONSTRUCTOR------------*/
    /*=================================================*/
    /*=================================================*/
    /*--------------DIRECTX DESTRUCTOR-----------------*/
    /*=================================================*/
    DX9::~DX9()
    {
        // set all stack variables to NULL
        SecureZeroMemory(&_d3dpp, sizeof(_d3dpp));
        SecureZeroMemory(&_mouseState, sizeof(_mouseState));
        SecureZeroMemory(&_keys, sizeof(_keys));
        SecureZeroMemory(&_keyStates, sizeof(_keyStates));

        // free all the D3D interfaces from memory
        if (!_fonts.empty())
        {
            for (std::vector<LPD3DXFONT>::iterator it = _fonts.begin(); it != _fonts.end(); it++)
            {
                // SOLVEPROBLEM figure out why this doesn't work
                //*it->OnLostDevice();
            }

            _fonts.erase(_fonts.begin(), _fonts.end() - 1);
        }

        if (_spriteBatch != NULL)
        {
            _spriteBatch->Release();
            _spriteBatch = NULL;
        }

        if (_diKeyboard != NULL)
        {
            _diKeyboard->Release();
            _diKeyboard = NULL;
        }

        if (_diMouse != NULL)
        {
            _diMouse->Release();
            _diMouse = NULL;
        }

        if (_d3ddev != NULL)
        {
            _d3ddev->Release();
            _d3ddev = NULL;
        }

        if (_d3d != NULL)
        {
            _d3d->Release();
            _d3d = NULL;
        }

        // free the window class from memory
        UnregisterClass(_title.c_str(), _inst);
    }
    /*=================================================*/
    /*--------------END DIRECTX DESTRUCTOR-------------*/
    /*=================================================*/
    /*=================================================*/
    /*--------------HRESULT ERROR CHECK----------------*/
    /*=================================================*/
    void DX9::CheckForDXError(const char *file, int line, HRESULT hr)
    {
        if (SUCCEEDED(hr))
        {
            return;
        }

        // Get the direct X error and description
        char desc[1024];
        sprintf_s(desc,"(DX) %s - %s", DXGetErrorString(hr), DXGetErrorDescription(hr));

        // Output the file and line number in the correct format + the above DX error
        char buf[2048];
        sprintf_s(buf,"%s(%d) : Error: %s\n", file, line, desc);
        OutputDebugString(buf);
    }
    /*=================================================*/
    /*--------------END HRESULT ERROR CHECK------------*/
    /*=================================================*/
    /*=================================================*/
    /*--------------MESSAGE PROCESSOR------------------*/
    /*=================================================*/
    UINT DX9::ProcessMessages()
    {
        if (PeekMessage(&_msg, NULL, NULL, NULL, PM_REMOVE))
        {
            TranslateMessage(&_msg);
            DispatchMessage(&_msg);
        }

        return _msg.message;
    }
    /*=================================================*/
    /*--------------END MESSAGE PROCESSOR--------------*/
    /*=================================================*/
    /*=================================================*/
    /*--------------MESSAGE HANDLER--------------------*/
    /*=================================================*/
    LRESULT CALLBACK DX9::WinProc(HWND hwnd, UINT msg, WPARAM wprm, LPARAM lprm)
    {
        switch (msg)
        {
            case WM_DESTROY:
                PostQuitMessage(0);
                break;
        }

        return DefWindowProc(hwnd, msg, wprm, lprm);
    }
    /*=================================================*/
    /*--------------END MESSAGE HANDLER----------------*/
    /*=================================================*/
    /*=================================================*/
    /*--------------DIRECTINPUT FUNCTIONS--------------*/
    /*=================================================*/
    // for init only, helper function to initially acquire the
    // mouse and keyboard
    void DX9::AcquireInputDevice(const LPDIRECTINPUTDEVICE8& dev)
    {
        // loop and attempt to acquire the device until success
        while (FAILED(dev->Acquire()))
        {
            dev->Acquire();
        }
    }

    // update the state of the mouse and keyboard
    void DX9::InputUpdate()
    {
        _diKeyboard->GetDeviceState(sizeof(_keys), (LPVOID)_keys);
        _diMouse->GetDeviceState(sizeof(_mouseState), (LPVOID)&_mouseState);

        // after directinput has been updated, check to see if any keys are no,
        // longer pressed, and reset the keystate array at that key's index if,
        // this is the case
        // keystates true = key is available for key press
        if (_keyboardStateChanged)
        {
            for (int i = 0; i < 256; i++)
            {
                if (!KeyHeld(i))
                {
                    _keyStates[i] = true;
                }
            }
        }

        _keyboardStateChanged = false;
    }

    // captures a key being held down
    BYTE DX9::KeyHeld(ush key)
    {
        return _keys[key] & 0x80;
    }

    // captures a single key press
    bool DX9::KeyPressed(ush key)
    {
        if (KeyHeld(key) && _keyStates[key])
        {
            _keyStates[key] = false;
            return true;
        }
        else
        {
            if (!KeyHeld(key) && !_keyStates[key])
            {
                _keyboardStateChanged = true;
            }

            return false;
        }
    }
    /*=================================================*/
    /*--------------END DIRECTINPUT FUNCTIONS----------*/
    /*=================================================*/
    /*=================================================*/
    /*--------------SPRITE FUNCTIONS-------------------*/
    /*=================================================*/
    // returns the sprite interface
    const LPD3DXSPRITE& DX9::GetSpriteInterface()
    {
        return _spriteBatch;
    }

    // begin drawing with the sprite batch
    void DX9::SpriteBeginDraw(DWORD flags)
    {
        _spriteBatch->Begin(flags);
    }

    // end sprite batch drawing
    void DX9::SpriteEndDraw()
    {
        _spriteBatch->End();
    }
    /*=================================================*/
    /*--------------END SPRITE FUNCTIONS---------------*/
    /*=================================================*/
    /*=================================================*/
    /*--------------FONT FUNCTIONS---------------------*/
    /*=================================================*/
    // create a font
    void DX9::MakeFont(int height, int width, UINT weight, LPCSTR face, bool italic)
    {
        LPD3DXFONT newfont;

        CheckHR(D3DXCreateFont(_d3ddev,
                               height,
                               width,
                               weight,
                               0,
                               italic,
                               DEFAULT_CHARSET,
                               OUT_DEFAULT_PRECIS, 
                               CLEARTYPE_QUALITY,
                               DEFAULT_PITCH | FF_DONTCARE,
                               face,
                               &newfont));

        _fonts.push_back(newfont);
    }

    // gets a font at the specified index
    const LPD3DXFONT& DX9::GetFontAtIndex(ush index)
    {
        return _fonts[index];
    }

    const std::vector<LPD3DXFONT>& DX9::GetFontVector()
    {
        return _fonts;
    }
    /*=================================================*/
    /*--------------END FONT FUNCTIONS-----------------*/
    /*=================================================*/
}
#endif

除了创建和初始化一个窗口、DirectX 和一些基本的 DirectX 函数之外,这实际上并没有做任何事情。

实际的错误是这样的:

Error   1   error LNK2005: "public: __thiscall nsdx9::DX9::DX9(struct HINSTANCE__ * &,int,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,unsigned short,unsigned short,short,short)" (??0DX9@nsdx9@@QAE@AAPAUHINSTANCE__@@HABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@GGFF@Z) already defined in game_manager.obj C:\Users\JAREK\documents\visual studio 2010\Projects\example\example\main.obj

dx9.h 中的每个函数都会重复此错误。如果我只在 main.cpp 中包含 dx9.h,我不会收到此错误。只有当我在任何其他 cpp 文件中包含 dx9.h,或者在可以访问 dx9.h 的 cpp 文件中使用 dx9.h 中的任何参数时,我才能得到这个错误。这听起来令人困惑,所以这里有一些来自程序其他部分的示例:

主.cpp:

#include "sys_params.h"
#include "dx9.h"
#include "game_manager.h"

int WINAPI WinMain (HINSTANCE inst, HINSTANCE pinst, LPSTR cmdLine, int cmdShow)
{
    // state of the program
    bool appEnd = false;

    // create and initialize the window and directx9
    nsdx9::DX9* _dx9 = new nsdx9::DX9(inst, cmdShow, nssysprms::GAME_TITLE,
                                      nssysprms::WND_WIDTH, nssysprms::WND_HEIGHT,
                                      nssysprms::WND_POS_X, nssysprms::WND_POS_Y);

    // create and initialize the game manager
    Game_Manager* _mngr = new Game_Manager(_dx9);

    // Windows message handler
    // also the entry point for the main game loop
    while (_dx9->ProcessMessages() != WM_QUIT && !appEnd)
    {
        if (!_mngr->Game_Run())
        {
            appEnd = true;
        }
    }

    // clean up everything
    delete _mngr;
    delete _dx9;

    return 0;
}

游戏管理器.h:

#ifndef _GAME_MANAGER_H_
#define _GAME_MANAGER_H_

#include <stack>
#include <vector>
#include "dx9.h"
#include "screen.h"
#include "message_handler.h"

class Game_Manager
{
    public:
        Game_Manager(nsdx9::DX9* dx9);
        ~Game_Manager();
        bool Game_Run();

    private:
        nsdx9::DX9* _dx9;
        std::stack<Screen*> _screens;
        Message_Handler* _msg_hnd;

        // *** DECLARE SCREENS HERE *** //

        void InitFonts();
        void InitScreens();
};
#endif

这应该是真正导致问题的原因。问题源自 main.cpp 到 game_manager.h。我尝试过的任何方法都没有为我解决问题。我在 dx9.h 中包含了标题保护,所以我不知道是什么原因造成的。如果你们需要更多信息,请告诉我。谢谢!

4

2 回答 2

1

您对DX9方法的定义(而不仅仅是类定义)似乎在dx9.h头文件中 - 因此当您包含dx9.h在多个 .cpp 文件中时,您违反了 C++ 的单一定义规则。为了解决这个问题,将方法实现移动到一个 .cpp 文件中(例如dx9.cpp)。

于 2011-10-26T23:40:10.873 回答
0

不要在头文件中包含实现。这会导致在包含它的任何地方再次编译实现。

例如:

/*=================================================*/
/*--------------DIRECTX CONSTRUCTOR----------------*/
/*=================================================*/
DX9::DX9(HINSTANCE& inst, int cmdShow, const std::string& title, ush wndwidth, ush wndheight, short wndx, short wndy)
    {
    ....  et al

把它放在它自己的cpp中

于 2011-10-26T23:39:25.920 回答