featherless biped
featherless biped

Reputation: 173

C++ CRITICAL_SECTION object in .dll gives unresolved external symbol error

I'm currently developing a game that comes in two parts: the engine is in a .dll and the actual game code is part of an .exe. The engine, among other header files, contains one that manages all components, ranging from Win32 specific objects and pointers to D3D11. These components are included in a class that allows them to be accessed globally via a function that returns a reference to it. Furthermore, for every item it manages there are two functions that allow the component to be set or to be returned. I also added a thread protection using a critical section. So, in State.h I have:

#if defined(NF3D_NONCLIENT_BUILD)
        #define NF3D_API __declspec(dllexport)
    #else
        #if defined(__MINGW32__)
            #define NF3D_API NF3D_API
        #else
            #define NF3D_API __declspec(dllimport)
        #endif
    #endif
...
#endif

...

extern NF3D_API CRITICAL_SECTION CriticalSection;

class NF3D_API NF3DLock
{
public:
#pragma prefast( suppress:26166, "Thread safeness is enabeled." )
    FORCEINLINE _Acquires_lock_(CriticalSection) NF3DLock(void)  { EnterCriticalSection(&CriticalSection); }
#pragma prefast( suppress:26165, "Thread safeness is enabeled." )
    FORCEINLINE _Releases_lock_(CriticalSection) ~NF3DLock(void) { LeaveCriticalSection(&CriticalSection); }
};

class NF3D_API STATE
{
public:
    ...
    inline void SetMember(int val) { NF3DLock Lock; Elements.Member = val; }
    inline int GetMember(void) { NF3DLock Lock; return Elements.Member; }

private:
    struct ELEMENTS
    {
        int Member;
    } Elements;
}

FORCEINLINE NF3D_API STATE* NF3DGetEngineState(void);

In State.cpp I initialise and delete the critical section but also:

CRITICAL_SECTION CriticalSection;

...

FORCEINLINE NF3D_API STATE* NF3DGetEngineState(void)
{
    static STATE s_State;
    return &s_State;
}

Calling 'NF3DGetEngineState' inside the .dll causes no problems and the compilation runs perfectly, but if I use this function outside the engine, inside the application I get a linker error in the .exe:

2>Main.obj : error LNK2001: unresolved external symbol "struct _RTL_CRITICAL_SECTION NewFrontiers3D::CriticalSection" (?CriticalSection@NewFrontiers3D@@3U_RTL_CRITICAL_SECTION@@A)

The engine is included in a namespace called 'NewFrontiers3D'. This error intrigued me even more when I declared 'extern NF3D_API CRITICAL_SECTION CriticalSection' as static, as it compiled fine but gave an access violation exception when entering the critical section in the constructor of NF3DLock. Also, if I remove 'EnterCriticalSection' and LeaveCriticalSection' the linker errors disappear. I don't know what is happening and why is it happening and that's why I'm addressing this question to anybody who might be able to help me.

Upvotes: 0

Views: 783

Answers (1)

Algirdas Preidžius
Algirdas Preidžius

Reputation: 1767

Update:

From the line:

#define NF3D_API __declspec(dllexport)

it looks like you are always exporting, and never importing (which you should do when the header is included from external projects).

For example, compile your code using defining NM3D_API_EXPORTS macro (if I am not mistaken: -d option.

And, then, in the header define NM3D_API in the following way:

#ifdef NM3D_API_EXPORTS
#define NM3D_API __declspec(dllexport)
#else
#define NM3D_API __declspec(dllimport)
#endif

Original Post:

Include's work in a very dumb way. They take whole contents of the file you are including, and paste them over the include statement.

This is why, when you are trying to include this header to a different project, that project doesn't know about your declaration in previous .dll. Since it was done in a different file, about which your other project knows nothing about.

Upvotes: 2

Related Questions