CLR Windows 窗体中的 LNK2005 错误 [英] LNK2005 Error in CLR Windows Form

查看:27
本文介绍了CLR Windows 窗体中的 LNK2005 错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个 Windows CLR 表单,以便为我作为控制台程序处理的一些代码创建 GUI 交互.

当我在代码的控制台部分包含标题时,我的两个标题都可以很好地协同工作,但是当我尝试将它们包含在表单中时,它们会导致以下结果:><块引用>

librarytest.obj:错误 LNK2005:_SeqWait 已在 Gesture_Elicitor.obj 中定义

librarytest.obj : error LNK2005: _KillDLL 已经在 Gesture_Elicitor.obj 中定义

librarytest.obj : error LNK2005: _SetSinFreq2 已经在 Gesture_Elicitor.obj 中定义

librarytest.obj : error LNK2005: _ConnectDirect 已经在 Gesture_Elicitor.obj 中定义

librarytest.obj : error LNK2005: _GetDevice 已经在 Gesture_Elicitor.obj 中定义

librarytest.obj : error LNK2005: _SetSinFreq_Fine2 已经在 Gesture_Elicitor.obj 中定义

librarytest.obj : error LNK2005: _Connect 已经在 Gesture_Elicitor.obj 中定义

librarytest.obj : error LNK2005: _TacOnTimeForTAction 已经在 Gesture_Elicitor.obj 中定义

librarytest.obj : error LNK2005: _SetSinFreq1 已经在 Gesture_Elicitor.obj 中定义

librarytest.obj : error LNK2005: _GetLastEAIError 已经在 Gesture_Elicitor.obj 中定义

librarytest.obj : error LNK2005: _SetGain 已经在 Gesture_Elicitor.obj 中定义

librarytest.obj : error LNK2005: _Disconnect 已经在 Gesture_Elicitor.obj 中定义

librarytest.obj : error LNK2005: _ReadFWVer 已经在 Gesture_Elicitor.obj 中定义

librarytest.obj : error LNK2005: _SetSinFreq_Fine1 已经在 Gesture_Elicitor.obj 中定义

librarytest.obj : error LNK2005: _SetSigSrc 已经在 Gesture_Elicitor.obj 中定义

librarytest.obj : error LNK2005: _ClosePort 已经在 Gesture_Elicitor.obj 中定义

librarytest.obj : error LNK2005: _ShowDebugInfo 已在 Gesture_Elicitor.obj 中定义

librarytest.obj : error LNK2005: _OpenPort 已经在 Gesture_Elicitor.obj 中定义

librarytest.obj : error LNK2005: _DiscoverDevices 已经在 Gesture_Elicitor.obj 中定义

librarytest.obj : error LNK2005: _TacOnTime 已经在 Gesture_Elicitor.obj 中定义

librarytest.obj : error LNK2005: _PulseOnTime 已经在 Gesture_Elicitor.obj 中定义

librarytest.obj : error LNK2005: _tactorhandle 已经在 Gesture_Elicitor.obj 中定义

....

有趣的问题是,我的头文件之一(wiimote.h",来自 WiiYourself 项目)可以正常工作,如果它是唯一包含的.问题在于tactor_cHeader.h",它连接到它的 .dll .有问题的缩写代码如下:

#ifndef TACTOR_H_#define TACTOR_H_使用命名空间标准;#include ...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;内联 int InitTactorDLL(){tactorhandle = LoadLibrary(Tactor_DLL.dll");如果(tactorhandle == 0)返回-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");}#万一

那么这个标题与我的表单不兼容是怎么回事?

解决方案

抱歉回复晚了.

问题很简单,您的头文件中有变量定义.通常,头文件应该只包含声明.检查 [SO]:定义之间有什么区别和声明? 看看两者之间的区别.

要修复,您应该移动这些:

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

进入真正需要它们的 .c 源文件,或者使它们 extern([MS.Docs]:extern (C++).

背景:

C (C++) 代码构建为 可移植可执行代码(这里我指的是 .exe.dll 文件).有关详细信息,请查看 [MS.Docs]:窥视 PE:Win32 可移植可执行文件格式之旅:

  1. 预处理

    • 预处理器完成(cl.exe:[MS.Docs]:编译器选项按字母顺序列出),这也是编译器(检查下一阶段);这是默认的静默阶段(您可以通过指定 /E/EP/P 标志来查看其输出)
    • 对于每个源(.c.cpp.cxxc++、...)文件,它处理所有预处理指令([MS.Docs]:预处理器指令)(例如:#define#if#include、...);结果仍然是一个 .c (.cpp, ...) 文件(与原始文件不同,通常明显更大),也称为编译翻译单元
    • 当遇到 #include 指令时,包含指令的行(每行代码只包含一个文件)将简单地替换为 (.h 甚至 .c (.cpp, ...)) 文件.请注意,这是递归完成的(如果包含的文件本身包含 #include 指令,它们也会被扩展,依此类推).原始源文件比预处理的小很多,这是预处理器存在的原因之一
  2. 编译

    • 编译器完成(检查前一阶段)
    • 上一阶段生成的每个翻译单元都从C(C++)代码(人类可读)转换为机器代码(CPU可读")或 COFF 格式([MS.Docs]:PE 格式).这是对象(.obj)文件(它的内容是胡言乱语 - 至少在第一次st可见),可以在VC 项目的中间目录
    • 注意,对于项目中包含的每个源文件,在这个阶段之后都会有一个对应的.obj文件
  3. 链接

    • 链接器完成(link.exe:[MS.Docs]:链接器选项)
    • 将上一阶段的所有目标文件合并在一起(包括一堆内容类似于.obj.lib文件文件的,但这些只能间接使用 - 在构建 应用程序 时)加上一些额外的操作(例如添加 PE 部分和标题、重新定位一些代码、删除未使用的代码,...)项目的最终工件(exedll)

注意:这是 Win 特定的,对于 Nix 阶段(几乎)相同,工具不同.

您的代码中发生了什么:

  • 文件tactor.h(我假设这是它的名字,基于开头的包含守卫)包含一堆变量定义;我以 HINSTANCE tactorhandle 为例
  • 文件 librarytest.cGesture_Elicitor.c(它们的名字来自链接器错误)都 #include(直接或间接)tractor.h
  • 阶段 1tractor.h 将在两个 .c 文件中(独立地)扩展.所以,两个翻译单元都有tactorhandle变量
  • 阶段 2,上一步中的 2 个翻译单元被编译并转换为目标文件,因为它们的代码在语法上是正确的
  • 阶段 3,当组合 2 个目标文件时,链接器看到tactorhandle存在于两个,然后吐出上面的错误

注意事项:

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?

解决方案

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++)).

Backgorund:

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 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) tractor.h
  • At Phase 1, tractor.h will be expanded in both the .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:

这篇关于CLR Windows 窗体中的 LNK2005 错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆