visual-studio-2010visual-c++

LNK2005 Error in CLR Windows Form


I'm working on developing a Windows CLR form to create GUI interaction for some code I've been handling as a console program.

When I include the header in the console portion of the code, both of my headers play fine together, but when I try to include them in the form, they result in the following:

librarytest.obj: error LNK2005: _SeqWait already defined in Gesture_Elicitor.obj

librarytest.obj : error LNK2005: _KillDLL already defined in Gesture_Elicitor.obj

librarytest.obj : error LNK2005: _SetSinFreq2 already defined in Gesture_Elicitor.obj

librarytest.obj : error LNK2005: _ConnectDirect already defined in Gesture_Elicitor.obj

librarytest.obj : error LNK2005: _GetDevice already defined in Gesture_Elicitor.obj

librarytest.obj : error LNK2005: _SetSinFreq_Fine2 already defined in Gesture_Elicitor.obj

librarytest.obj : error LNK2005: _Connect already defined in Gesture_Elicitor.obj

librarytest.obj : error LNK2005: _TacOnTimeForTAction already defined in Gesture_Elicitor.obj

librarytest.obj : error LNK2005: _SetSinFreq1 already defined in Gesture_Elicitor.obj

librarytest.obj : error LNK2005: _GetLastEAIError already defined in Gesture_Elicitor.obj

librarytest.obj : error LNK2005: _SetGain already defined in Gesture_Elicitor.obj

librarytest.obj : error LNK2005: _Disconnect already defined in Gesture_Elicitor.obj

librarytest.obj : error LNK2005: _ReadFWVer already defined in Gesture_Elicitor.obj

librarytest.obj : error LNK2005: _SetSinFreq_Fine1 already defined in Gesture_Elicitor.obj

librarytest.obj : error LNK2005: _SetSigSrc already defined in Gesture_Elicitor.obj

librarytest.obj : error LNK2005: _ClosePort already defined in Gesture_Elicitor.obj

librarytest.obj : error LNK2005: _ShowDebugInfo already defined in Gesture_Elicitor.obj

librarytest.obj : error LNK2005: _OpenPort already defined in Gesture_Elicitor.obj

librarytest.obj : error LNK2005: _DiscoverDevices already defined in Gesture_Elicitor.obj

librarytest.obj : error LNK2005: _TacOnTime already defined in Gesture_Elicitor.obj

librarytest.obj : error LNK2005: _PulseOnTime already defined in Gesture_Elicitor.obj

librarytest.obj : error LNK2005: _tactorhandle already defined in Gesture_Elicitor.obj

....

The interesting problem is that one of my headers ("wiimote.h", from the WiiYourself project) works fine if its the only one included. The problem lies with "tactor_cHeader.h", which connects to its .dll . The abbreviated code in question is as follows:

#ifndef TACTOR_H_
#define TACTOR_H_

using namespace std;

#include <windows.h>

...

typedef int (*ConnectDirectPtr)(char*name, int type);
typedef int (*TacOnTimePtr)(int cidx, int board, int tacNum, int durMilli, bool returnifprocessing);
typedef int (*SetFreqPtr)(int cidx, int board, int freq, bool returnifprocessing);
typedef int (*KillDLLptr)();
typedef int (*SeqWaitPtr)(int cidx, int board, int waitTime, bool returnifprocessing);
...

ConnectDirectPtr ConnectDirect;
TacOnTimePtr TacOnTimeForTaction;
SetFreqPtr SetSinFreq1;
SetFreqPtr SetSinFreq2;
KillDLLptr KillDLL;
SeqWaitPtr SeqWait;
...

HINSTANCE tactorhandle = NULL;

inline int InitTactorDLL()
{
    tactorhandle = LoadLibrary("Tactor_DLL.dll");
    if (tactorhandle == 0)
        return -1;
    SeqWait = (SeqWaitPtr)GetProcAddress(tactorhandle, "SeqWait");
    ConnectDirect = (ConnectDirectPtr)GetProcAddress(tactorhandle, "ConnectDirect");
    TacOnTime = (TacOnTimePtr)GetProcAddress(tactorhandle, "TacOnTime");
    SetSinFreq1 = (SetFreqPtr)GetProcAddress(tactorhandle, "SetSinFreq1");
    SetSinFreq2 = (SetFreqPtr)GetProcAddress(tactorhandle, "SetSinFreq2");
    KillDLL = (KillDLLptr)GetProcAddress(tactorhandle, "KillDLL");
}

#endif

So what is it about this header that isn't playing nice with my form?


Solution

  • Sorry for the late reply.

    The problem is simple, you have variable definitions inside your header file. Generally, a header file should only contain declarations. Check [SO]: What is the difference between a definition and a declaration? to see the difference between the two.

    To fix, you should move these:

    ConnectDirectPtr ConnectDirect;
    TacOnTimePtr TacOnTimeForTaction;
    SetFreqPtr SetSinFreq1;
    SetFreqPtr SetSinFreq2;
    KillDLLptr KillDLL;
    SeqWaitPtr SeqWait;
    //...
    
    HINSTANCE tactorhandle = NULL;
    

    into the .c source file that really needs them, or make them extern ([MS.Learn]: extern (C++)).

    Background

    There are 3 phases when building C (C++) code into Portable Executable code (here I'm referring to .exe and .dll files). For more info, check [MS.Learn]: Peering Inside the PE: A Tour of the Win32 Portable Executable File Format:

    1. Preprocess

    2. Compile

    3. Link

    Note: this is Win specific, for Nix the phases are (almost) the same, tools differ.

    What happens in your code:

    Notes: