Visual Studio 2010 Pro的链接器问题

Linker issue with Visual Studio 2010 Pro

本文关键字:链接 问题 Pro Studio 2010 Visual      更新时间:2023-10-16

我有一个非常令人沮丧的问题设置DirectX 9(与问题无关…我认为)框架在VS 2010。这是我的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: %sn", 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:UsersJAREKdocumentsvisual studio 2010Projectsexampleexamplemain.obj

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

main.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;
}

game_manager.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中包含了头部警卫,所以我不知道是什么原因导致了这一点。如果你们需要更多的信息,请告诉我。谢谢!

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

不要在头文件中包含实现。这将导致在包含该实现的任何地方重新编译它。

例如:

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

把它放到它自己的cpp