LNK2005 Error in CLR Windows Form
Asked Answered
T

1

1

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?

Telford answered 12/1, 2016 at 16:30 Comment(2)
Can you also post the code (and the file name) where SeqWait, SetSinFreq2, KillDLL are defined?Abixah
I edited the original document to match your request @Abixah . Does that help?Telford
A
4

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.Docs]: 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.Docs]: Peering Inside the PE: A Tour of the Win32 Portable Executable File Format:

1. Preprocess

  • Done by the preprocessor (cl.exe: [MS.Docs]: Compiler Options Listed Alphabetically) which is also the compiler (check next phase); this is by default a silent phase (you can see its output by specifying /E, /EP or /P flags)

  • For every source (.c, .cpp, .cxx, c++, ...) file, it handles all the preprocessing directives ([MS.Docs]: Preprocessor Directives) (e.g.: #define, #if, #include, ...); the result is still a .c (.cpp, ...) file (different than the original, usually, significantly larger) also called compilation unit or translation unit

  • When an #include directive is encountered, the line that contains the directive (there's only one file included per line of code) is simply replaced by the contents of the (.h or even .c (.cpp, ...)) file included. Note that this is done recursively (if the file included itself contains #include directives they are expanded as well, and so on). The original source file is much smaller than the preprocessed one, which is one of the preprocessor existence reasons

2. Compile

  • Done by the compiler (check previous phase)

  • Every translation unit generated at previous phase is converted from C (C++) code (human readable) to machine code (CPU "readable") or COFF format ([MS.Docs]: PE Format). This is the object (.obj) file (its content is gibberish - at least at 1st sight), that can be seen in the VC project's intermediary directory

  • Note that for each source file included in the project, after this phase there will be a corresponding .obj file

3. Link

  • Done by the linker (link.exe: [MS.Docs]: Linker Options)

  • All the object files from the previous phase are merged together (with a bunch of .lib files whose content is similar to .obj file's, but those can only be used indirectly - when building an App) plus some additional operations (e.g. adding the PE sections and headers, relocating some of the code, removing unused code, ...) into the final artifact of the project (the exe or the dll)

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

What happens in your code:

  • The file tactor.h (I'm assuming this is its name, based on the include guard at the beginning) contains a bunch of variable definitions; I'm taking HINSTANCE tactorhandle as an example

  • Files librarytest.c and Gesture_Elicitor.c (got their names from the linker error) both #include (directly or indirectly) tactor.h

  • At Phase #1., tactor.h will be expanded in both .c files (independently). So, both translation units will have tactorhandle variable

  • At Phase #2., the 2 translation units from previous step are compiled and turned into object files, since their code is syntactically correct

  • At Phase #3., when combining the 2 object files, the linker sees that tactorhandle is present in both of them, and then spits the errors above

Notes:

Abixah answered 13/1, 2016 at 21:28 Comment(2)
Thank you for such a thoughtful, informative response. It's a great help to better understand the context of my error.Telford
The most important thing: Did it help you solving your problem?Abixah

© 2022 - 2024 — McMap. All rights reserved.