Error LNK2005 en formulario de CLR Windows

Estoy trabajando en el desarrollo de un formulario CLR de Windows para crear una interacción de GUI para algún código que he manejado como un progtwig de consola.

Cuando incluyo el encabezado en la parte de la consola del código, mis dos encabezados funcionan bien juntos, pero cuando trato de incluirlos en el formulario , resultan en lo siguiente:

librarytest.obj: error LNK2005: _SeqWait ya se ha definido en Gesture_Elicitor.obj

librarytest.obj: error LNK2005: _KillDLL ya se ha definido en Gesture_Elicitor.obj

librarytest.obj: error LNK2005: _SetSinFreq2 ya definido en Gesture_Elicitor.obj

librarytest.obj: error LNK2005: _ConnectDirect ya definido en Gesture_Elicitor.obj

librarytest.obj: error LNK2005: _GetDevice ya definido en Gesture_Elicitor.obj

librarytest.obj: error LNK2005: _SetSinFreq_Fine2 ya definido en Gesture_Elicitor.obj

librarytest.obj: error LNK2005: _Connect ya definido en Gesture_Elicitor.obj

librarytest.obj: error LNK2005: _TacOnTimeForTAction ya definido en Gesture_Elicitor.obj

librarytest.obj: error LNK2005: _SetSinFreq1 ya definido en Gesture_Elicitor.obj

librarytest.obj: error LNK2005: _GetLastEAIError ya se ha definido en Gesture_Elicitor.obj

librarytest.obj: error LNK2005: _SetGain ya se ha definido en Gesture_Elicitor.obj

librarytest.obj: error LNK2005: _Disconnect ya definido en Gesture_Elicitor.obj

librarytest.obj: error LNK2005: _ReadFWVer ya definido en Gesture_Elicitor.obj

librarytest.obj: error LNK2005: _SetSinFreq_Fine1 ya definido en Gesture_Elicitor.obj

librarytest.obj: error LNK2005: _SetSigSrc ya se ha definido en Gesture_Elicitor.obj

librarytest.obj: error LNK2005: _ClosePort ya definido en Gesture_Elicitor.obj

librarytest.obj: error LNK2005: _ShowDebugInfo ya definido en Gesture_Elicitor.obj

librarytest.obj: error LNK2005: _OpenPort ya definido en Gesture_Elicitor.obj

librarytest.obj: error LNK2005: _DiscoverDevices ya definido en Gesture_Elicitor.obj

librarytest.obj: error LNK2005: _TacOnTime ya definido en Gesture_Elicitor.obj

librarytest.obj: error LNK2005: _PulseOnTime ya se ha definido en Gesture_Elicitor.obj

librarytest.obj: error LNK2005: _tactorhandle ya se ha definido en Gesture_Elicitor.obj

….

El problema interesante es que uno de mis encabezados (“wiimote.h”, del proyecto WiiYourself) funciona bien si es el único incluido. El problema radica en “tactor_cHeader.h”, que se conecta a su .dll. El código abreviado en cuestión es el siguiente:

#ifndef TACTOR_H_ #define TACTOR_H_ using namespace std; #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; 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 

Entonces, ¿qué pasa con este encabezado que no está jugando bien con mi formulario?

Lo siento por la respuesta tardía.

El problema es simple, tienes definiciones de variables dentro de tu archivo de encabezado. En general, un archivo de encabezado solo debe contener declaraciones . Verifique [SO]: ¿Cuál es la diferencia entre una definición y una statement? para ver la diferencia entre los dos.

Para solucionarlo , debes mover estos:

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

en el archivo fuente .c que realmente los necesita, o hacer que sean extern ( [MSDN]: Usar extern para Especificar vinculación ).

Backgorund :

Hay tres fases al comstackr el código C en el código Ejecutable portátil (aquí me refiero a los archivos .exe y .dll ). Para obtener más información, consulte [MSDN]: Peering Inside the PE: un recorrido por el formato de archivo ejecutable portátil Win32 :

  1. Preproceso

    • Hecho por el preprocesador ( cl.exe : [MSDN]: Opciones del comstackdor enumeradas alfabéticamente ) que también es el comstackdor (consulte la siguiente fase); esto es por defecto una fase silenciosa (puede ver su salida especificando /E , /EP o /P indicadores)
    • Para cada archivo de origen ( .c ), maneja todas las directivas de preprocesamiento ( [MSDN]: Directivas de preprocesador ) (por ejemplo: #define , #if , #include , …); el resultado sigue siendo un archivo .c (diferente del original, generalmente, significativamente más grande) también llamado comstackción o unidad de traducción
    • Cuando se encuentra una directiva #include , la línea que contiene la directiva (solo hay un archivo incluido por línea de código) simplemente se reemplaza por el contenido del archivo ( .h o incluso .c ) incluido. Tenga en cuenta que esto se hace recursivamente (si el archivo incluido contiene instrucciones #include , también se expanden, y así sucesivamente). El archivo de origen original es mucho más pequeño que el preprocesado, que es uno de los motivos de existencia del preprocesador
  2. Comstackr

    • Hecho por el comstackdor (ver fase anterior)
    • Cada unidad de traducción generada en la fase anterior se convierte de código C (legible para personas) a código máquina ( CPU “legible”) o formato COFF ( [MSDN]: formato PE ). Este es el archivo de objeto (.obj) (su contenido es un galimatías, al menos en la primera vista), que se puede ver en el directorio intermediario del proyecto de VC.
    • Tenga en cuenta que para cada archivo fuente incluido en el proyecto, después de esta fase habrá un archivo .obj correspondiente
  3. Enlazar

    • Hecho por el vinculador ( link.exe : [MSDN]: Opciones de vinculador )
    • Todos los archivos objeto de la fase anterior se fusionan (con un grupo de archivos .lib cuyo contenido es similar a los archivos .obj , pero solo se pueden usar de forma indirecta, al comstackr una aplicación ) más algunas operaciones adicionales (por ejemplo, agregar el archivo PE secciones y encabezados, reubicar parte del código, eliminar el código no utilizado, …) en el artefacto final del proyecto (el exe o el dll )

Nota : esto es específico de Win , para Ux las fases son (casi) iguales, las herramientas difieren.

Qué sucede en tu código:

  • El archivo tactor.h (supongo que este es su nombre, basado en el protector de inclusión al principio) contiene un conjunto de definiciones de variables; Estoy tomando HINSTANCE tactorhandle como un ejemplo
  • Archivos librarytest.c y Gesture_Elicitor.c (obtuvieron sus nombres del error del enlazador) ambos #include (directa o indirectamente) tractor.h
  • En Phase1 , tractor.h se expandirá en ambos archivos .c (de forma independiente). Entonces, ambas unidades de traducción tendrán variable tactorhandle
  • En Phase2 , las 2 unidades de traducción del paso anterior se comstackn y se convierten en archivos de objeto , ya que su código es sintácticamente correcto
  • En Phase3 , al combinar los 2 archivos objeto , el enlazador ve que tactorhandle está presente en ambos, y luego escupe los errores de arriba

Notas :

  • También puede especificar /FORCE:MULTIPLE opción /FORCE:MULTIPLE al vinculador (agregándolo a Propiedades del proyecto de VC -> Enlazador -> Línea de comando -> Opciones adicionales ), pero tenga en cuenta que esto puede arrojar resultados inesperados (ni siquiera trabajo para proyectos comstackdos /clr )
  • Dado que el proyecto incluye .dll y funciones de importación / exportación, también puede marcar [SO]: error del enlazador al invocar una función C desde código C ++ en un proyecto VS2010 diferente (respuesta de @ CristiFati) , para ver los errores que pueden aparecer al usar esto . dll