Проблема компоновщика с Visual Studio 2010 Pro

#c #visual-studio-2010 #directx-9

#c #visual-studio-2010 #directx-9

Вопрос:

У меня очень неприятная проблема с настройкой 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(HINSTANCEamp; inst, int cmdShow, const std::stringamp; 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 LPD3DXSPRITEamp; 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 LPD3DXFONTamp; GetFontAtIndex(ush index);
            const std::vector<LPD3DXFONT>amp; 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 LPDIRECTINPUTDEVICE8amp; 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(HINSTANCEamp; inst, int cmdShow, const std::stringamp; 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(amp;_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(amp;_d3dpp, sizeof(_d3dpp));
        SecureZeroMemory(amp;_mouseState, sizeof(_mouseState));
        SecureZeroMemory(amp;_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, amp;_d3dpp, amp;_d3ddev));
        // --- END DIRECTX9 INITIALIZATION --- //

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

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

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

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

        // create sprite object
        CheckHR(D3DXCreateSprite(_d3ddev, amp;_spriteBatch));
        // --- END INITIALIZE DIRECTINPUT --- //
        /*=================================================*/
        /*--------------END DIRECTX INITIALIZATION---------*/
        /*=================================================*/
    }
    /*=================================================*/
    /*--------------END DIRECTX CONSTRUCTOR------------*/
    /*=================================================*/
    /*=================================================*/
    /*--------------DIRECTX DESTRUCTOR-----------------*/
    /*=================================================*/
    DX9::~DX9()
    {
        // set all stack variables to NULL
        SecureZeroMemory(amp;_d3dpp, sizeof(_d3dpp));
        SecureZeroMemory(amp;_mouseState, sizeof(_mouseState));
        SecureZeroMemory(amp;_keys, sizeof(_keys));
        SecureZeroMemory(amp;_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(amp;_msg, NULL, NULL, NULL, PM_REMOVE))
        {
            TranslateMessage(amp;_msg);
            DispatchMessage(amp;_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 LPDIRECTINPUTDEVICE8amp; 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)amp;_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] amp; 0x80;
    }

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

            return false;
        }
    }
    /*=================================================*/
    /*--------------END DIRECTINPUT FUNCTIONS----------*/
    /*=================================================*/
    /*=================================================*/
    /*--------------SPRITE FUNCTIONS-------------------*/
    /*=================================================*/
    // returns the sprite interface
    const LPD3DXSPRITEamp; 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,
                               amp;newfont));

        _fonts.push_back(newfont);
    }

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

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

Это действительно ничего не делает, кроме создания и инициализации окна, DirectX и некоторых базовых функций DirectX.

Фактическая ошибка заключается в следующем:

 Error   1   error LNK2005: "public: __thiscall nsdx9::DX9::DX9(struct HINSTANCE__ * amp;,int,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const amp;,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. Если я включу ТОЛЬКО dx9.h в main.cpp , я не получаю эту ошибку. Это только в том случае, если я включаю dx9.h в любой другой файл cpp или использую любой из параметров в dx9.h в файлах cpp, которые имеют доступ к dx9.h, будучи включенными после dx9.h в main.cpp что я получаю эту ошибку. Это звучит запутанно, поэтому вот несколько примеров из других частей программы:

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 amp;amp; !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, поэтому я понятия не имею, что может быть причиной этого. если вам, ребята, нужна дополнительная информация, пожалуйста, дайте мне знать. Спасибо!

Ответ №1:

Похоже, что ваши определения DX9 методов (в отличие от определения класса) находятся в файле dx9.h заголовка, поэтому вы нарушаете правило одного определения C при включении dx9.h в несколько файлов .cpp. Чтобы решить эту проблему, переместите реализации метода в файл .cpp (например dx9.cpp ).

Комментарии:

1. Большое вам спасибо! Я никогда не знал об этом правиле.

Ответ №2:

Не включайте реализацию в файл заголовка. Это приводит к повторной компиляции реализации везде, где она включена.

например:

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

поместите это в собственный cpp

Комментарии:

1. Большое вам спасибо! Я никогда не знал об этом правиле.