visual-studio-2010 visual-c++

visual studio 2010 - Error LNK2005 en formulario CLR de Windows



visual-studio-2010 visual-c++ (1)

Lo siento por la respuesta tardía.

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

Para solucionarlo , debe 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 hacerlos extern ( [MS.Docs]: extern (C ++) ).

Fondo :

Hay 3 fases cuando se construye código C ( C ++ ) en código ejecutable portátil (aquí me refiero a los archivos .exe y .dll ). Para obtener más información, consulte [MS.Docs]: Peering Inside the PE: A Tour of the Win32 Portable Executable File Format :

  1. Preproceso

    • Hecho por el preprocesador ( cl.exe : [MS.Docs]: Opciones del compilador enumeradas alfabéticamente ) que también es el compilador (verifique la siguiente fase); esta es por defecto una fase silenciosa (puede ver su salida especificando los indicadores / E , / EP o / P )
    • Para cada archivo fuente ( .c , .cpp , .cxx , c ++ , ...), maneja todas las directivas de preprocesamiento ( [MS.Docs]: directivas de preprocesador ) (por ejemplo: #define , #if , #include ,. ..); el resultado sigue siendo un archivo .c ( .cpp , ...) (diferente del original, generalmente, significativamente más grande) también llamado unidad de compilación o traducción
    • Cuando se encuentra una directiva #include , la línea que contiene la directiva (solo se incluye un archivo por línea de código) simplemente se reemplaza por el contenido del archivo ( .h o incluso .c ( .cpp , ...)) incluido. Tenga en cuenta que esto se hace de forma recursiva (si el archivo incluido en sí contiene directivas #include , también se expanden, etc.). El archivo fuente original es mucho más pequeño que el preprocesado, que es una de las razones de existencia del preprocesador
  2. Compilar

    • Hecho por el compilador (verifique la fase anterior)
    • Cada unidad de traducción generada en la fase anterior se convierte de código C ( C ++ ) (legible por humanos) a código de máquina ( CPU "legible") o formato COFF ( [MS.Docs]: formato PE ). Este es el archivo de objeto (.obj) (su contenido es galimatías, al menos a primera vista), que se puede ver en el directorio intermediario del proyecto 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 : [MS.Docs]: Opciones del vinculador )
    • Todos los archivos de objetos de la fase anterior se fusionan (con un montón de archivos .lib cuyo contenido es similar al de los archivos .obj , pero solo se pueden usar indirectamente, al crear una aplicación ) más algunas operaciones adicionales (por ejemplo, agregar el PE secciones y encabezados, reubicando parte del código, eliminando el código no utilizado, ...) en el artefacto final del proyecto (el exe o el dll )

Nota : esto es específico de Win , para Nix las fases son (casi) las mismas, 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 montón de definiciones variables; Estoy tomando HINSTANCE tactorhandle como ejemplo
  • Archivos librarytest.c y Gesture_Elicitor.c (obtuvieron sus nombres del error del enlazador) ambos #include (directa o indirectamente) tractor.h
  • En la Fase 1 , tractor.h se expandirá en ambos archivos .c (independientemente). Entonces, ambas unidades de traducción tendrán una variable tactorhandle
  • En la Fase 2 , las 2 unidades de traducción del paso anterior se compilan y se convierten en archivos de objetos , ya que su código es sintácticamente correcto
  • En la Fase 3 , cuando se combinan los 2 archivos de objetos , el vinculador ve que tactorhandle está presente en ambos, y luego escupe los errores anteriores

Notas :

Estoy trabajando en el desarrollo de un formulario CLR de Windows para crear interacción GUI para algunos códigos que he estado manejando como un programa 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 definido en Gesture_Elicitor.obj

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

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

librarytest.obj: error LNK2005: _ConnectDirect ya está 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 definido en Gesture_Elicitor.obj

librarytest.obj: error LNK2005: _SetGain ya está 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 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 definido en Gesture_Elicitor.obj

librarytest.obj: error LNK2005: _tactorhandle ya 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 <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

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