我正在开发一个Windows CLR表单,以便为我作为控制台程序处理的一些代码创建GUI交互。
当我在代码的控制台部分中包含标题时,我的两个标题一起播放得很好,但是当我尝试将它们包含在表单中时,它们会产生以下结果:
librarytest.obj:错误LNK2005:_SeqWait已在Gesture_Elicitor.obj中定义
librarytest.obj:错误LNK2005:_KillDLL已在Gesture_Elicitor.obj中定义
librarytest.obj:错误LNK2005:_SetSinFreq2已在Gesture_Elicitor.obj中定义
librarytest.obj:错误LNK2005:_ConnectDirect已在Gesture_Elicitor.obj中定义
librarytest.obj:错误LNK2005:_GetDevice已在Gesture_Elicitor.obj中定义
librarytest.obj:错误LNK2005:_SetSinFreq_Fine2已在Gesture_Elicitor.obj中定义
librarytest.obj:错误LNK2005:_Connect已在Gesture_Elicitor.obj中定义
librarytest.obj:错误LNK2005:_TacOnTimeForTAction已在Gesture_Elicitor.obj中定义
librarytest.obj:错误LNK2005:_SetSinFreq1已在Gesture_Elicitor.obj中定义
librarytest.obj:错误LNK2005:_GetLastEAIError已在Gesture_Elicitor.obj中定义
librarytest.obj:错误LNK2005:_SetGain已在Gesture_Elicitor.obj中定义
librarytest.obj:错误LNK2005:_Disconnect已在Gesture_Elicitor.obj中定义
librarytest.obj:错误LNK2005:_ReadFWVer已在Gesture_Elicitor.obj中定义
librarytest.obj:错误LNK2005:_SetSinFreq_Fine1已在Gesture_Elicitor.obj中定义
librarytest.obj:错误LNK2005:_SetSigSrc已在Gesture_Elicitor.obj中定义
librarytest.obj:错误LNK2005:_ClosePort已在Gesture_Elicitor.obj中定义
librarytest.obj:错误LNK2005:_ShowDebugInfo已在Gesture_Elicitor.obj中定义
librarytest.obj:错误LNK2005:_OpenPort已在Gesture_Elicitor.obj中定义
librarytest.obj:错误LNK2005:已在Gesture_Elicitor.obj中定义_DiscoverDevices
librarytest.obj:错误LNK2005:_TacOnTime已在Gesture_Elicitor.obj中定义
librarytest.obj:错误LNK2005:_PulseOnTime已在Gesture_Elicitor.obj中定义
librarytest.obj:错误LNK2005:_tactorhandle已在Gesture_Elicitor.obj中定义
...
有趣的问题是,我的一个标题(" wiimote.h",来自WiiYourself项目)如果包含唯一的标题就可以正常工作。问题出在" tactor_cHeader.h",它连接到它的.dll。有问题的缩写代码如下:
#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
那么这个标题对于我的表单来说不是很好吗?
答案 0 :(得分:1)
很抱歉迟到的回复。
问题很简单,您在头文件中有变量定义。通常,头文件只应包含声明。检查[SO]: What is the difference between a definition and a declaration?以查看两者之间的差异。
要修复,您应该移动它们:
ConnectDirectPtr ConnectDirect;
TacOnTimePtr TacOnTimeForTaction;
SetFreqPtr SetSinFreq1;
SetFreqPtr SetSinFreq2;
KillDLLptr KillDLL;
SeqWaitPtr SeqWait;
//...
HINSTANCE tactorhandle = NULL;
进入真正需要它们的 .c 源文件,或者使它们成为extern
([MSDN]: Using extern to Specify Linkage)。
<强> Backgorund 强>:
将 C 代码构建到可移植可执行代码中有三个阶段(这里我指的是 .exe 和。 dll 文件)。有关详情,请查看[MSDN]: Peering Inside the PE: A Tour of the Win32 Portable Executable File Format:
<强>预处理强>
/E
,/EP
或/P
标志来查看其输出)#define
,{{ 1}},#if
,...);结果仍然是 .c 文件(不同于原始文件,通常是非常大),也称为编译或翻译单元 #include
指令时,包含指令的行(每行代码只包含一个文件)只是被( .h 或甚至包括 .c )文件。请注意,这是递归(如果包含的文件本身包含#include
指令,它们也会被扩展,依此类推)。原始源文件比预处理源文件小得多,这是预处理器存在的原因之一<强>编译强>
链接强>
注意:这是 Win 特定的,对于 Ux ,阶段(几乎)相同,工具不同。
您的代码中会发生什么:
#include
为例HINSTANCE tactorhandle
(直接或间接)拖拉机。 ħ #include
变量tactorhandle
,然后吐出上面的错误备注强>:
tactorhandle
选项(通过将其添加到 VC 项目属性 - &gt;链接器 - &gt;命令行 - &gt;其他选项),但请记住,这可能会产生意外结果(它甚至不适用于/FORCE:MULTIPLE
已编译的项目)