Fremde VisualC DLL in C++Builder einbinden



  • Hallo, ich soll in mein Projekt eine DLL einbinden und habe damit etwas meine Schwierigkeiten. Erhalten habe ich

    • eine Header-Datei
    • zwei DLLs GPD.dll und GPD64.dll
    • zwei Libs die GPDR.lib und GPDR64.lib

    Ich habe die Headerdatei und die GPDR.lib in mein Projekt über den Projektmanager hinzugefügt und einfach mal compiliert. Da erhalte ich die Fehlermeldung die LIB contains invalid OMF record, type 0x21 (possibly COFF)

    Also mal schlau gemacht und es scheint mehrere Wege zu geben aus einer COFF eine OMF zu machen.

    implib.exe -a GPDR_BCB.lib GPD.dll
    

    Dies erzeugt mir eine 3 KB Datei. Die Original LIB ist aber ca 500 KB groß. Das kann es nicht sein.

    COFF2OMF.exe GPD.dll GPDR_BCB.lib
    

    Das erzeugt nur einen Fehler

    COFF to OMF Converter Version 1.0.0.74 Copyright (c) 1999, 2000 Inprise Corporation
    ERROR: COFF error: GPD.dll
      (coffread.cpp, 1502) : invalid machine type detected
    

    Wenn man die LIB konvertieren will

    COFF2OMF.exe GPDR.lib GPDR_BCB.lib
    

    kommt da nur eine 1KB Datei raus.

    objconv.exe -fomf GPDR.lib GPDR_BCB.lib
    Input library: GPDR.lib, Format: COFF32, Output: GPDR_BCB.lib, Format: OMF32
    

    Das erzeugt eine halb so große LIB wie das Original. Allerdings sagt Stackoverflow das es wohl erheblich kleiner sein kann https://stackoverflow.com/questions/3114339/converting-coff-lib-file-to-omf-format
    Die Ausgabe hat allerdings auch viele Warnungen wie:

    Warning 1060: Different alignments specified for same segment, %s. Using highest alignment.rdata
    Supressing further warning messages
    315 Debug sections removed
      5 Exception sections removed
    

    Auch das kann wohl kaum richtig so sein. Mehr Möglichkeiten finde ich aktuell leider nicht. Ich habe die Version von 3. in das Projekt einfach mal eingebunden, indem ich es über den Projektmanager rechts hinzugefügt habe und in mein Projekt noch #include "GPDR.h" eingefügt.

    Wenn ich dies compiliere

    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
    	gpdSetData(1, 1, GPD_UNDEFINED, GPD_UNDEFINED);
    }
    

    erhalte ich

    [ILINK32 Fehler] Error: Nicht auflösbares externes '__stdcall gpdSetData(long, long, double, double)' referenziert von UNIT1.OBJ
    

    Mache ich noch etwas falsch oder ist hier einfach ein Problem mit der LIB? Die Header hat sehr viele Funktionen und Konstanten. Jede Hilfe wäre sehr willkommen. 🙂

    Sowas wie dies hier ist aber nötig, wenn man eigentlich eine Header einbindet, oder? Das extern "C" ist im Header allerdings nicht enthalten.

    extern "C" __declspec(dllimport)bool gpdSetData(long var1, long var2, double var3 = GPDR_VAR3, double var4 = GPDR_VAR4);
    

    Die Header beginnt im übrigen so:

    #ifndef __GPD_H
    #define __GPD_H
    
    #if _MSC_VER >= 1000
    #pragma once
    #endif // _MSC_VER >= 1000
    
    #ifndef GPD_DLL
    #ifdef GPD_DLL_EXT
    
    #ifdef _USRDLL
    #define GPD_DLL __declspec(dllexport)
    #else
    #define GPD_DLL
    #endif
    
    #else
    
    #ifdef _USRDLL
    #define GPD_DLL __declspec(dllimport)
    #else
    #define GPD_DLL
    #endif
    
    #endif
    #endif
    
    #ifndef PASCAL
    #define PASCAL __stdcall
    #endif
    
    #define GPD_UNDEFINED -1E20
    
    GPD_DLL bool PASCAL gpdSetData(long var1, long var2, double var3 = GPD_UNDEFINED, double var4 = GPD_UNDEFINED);
    

    Fehlt hier irgendwas mit extern "C"?

    Muss ich in "Projektoptionen" noch irgendwas eintragen?



  • Hi,

    ich habe bis jetzt für sowas immer implib benutzt und es hat immer funktioniert.

    Laß Dich nicht von der Größe der erzeugten Bibliothek verwirren. Diese enthält nicht den Code der DLL sondern nur Verweise, darauf die dann TLINK auswerten kann. Daher mußt Du ja auch die DLL zusammen mit Deiner EXE ausliefern.

    VG Martin



  • Danke für die Antwort. Ich habe mit implib die 3KB LIB-Datei erstellt und in meinem Projekt eingebunden. Anstatt die Header einzubinden, habe ich es selbst mit drei Funktionen im Code direkt gemacht. In der Header stand es als

    #define GPD_DLL __declspec(dllimport)
    #define PASCAL __stdcall
    GPD_DLL bool PASCAL myFunc(long var1, long &var2);

    Also habe ich

    extern "C" __declspec(dllimport) bool __stdcall myFunc(long var1, long &var2);

    Wenn ich compiliere klappen so 2 von 3 Funktionen, bei der dritten (die selbe als würde ich die Header direkt einbinden) meldet auch hier
    [ILINK32 Fehler] Error: Nicht auflösbares externes 'myFunc' referenziert von UNIT1.OBJ

    In der DLL ist die Funktion enthalten. Das sehe ich mit dem Dependency Walker. Allerdings ist da die Funktion irgendwie anders dort dargestellt. Alle anderen Funktionen steht nur der Funktionsname sauber da, bei dieser steht davor noch ein "?" (Fragezeichen) und danach sowas wie @@balbla@noch_mehr_bla. Also in der Form "?myFunc@@blabla@blabla" wobei bei anderen nur der Funktionsname "myFunc2" steht. Weiß jemand was das bedeuten könnte?

    EDIT: Okay die Frage wegen dem Fragezeichen erklärt die Doku http://www.dependencywalker.com/faq.html unter dem Punkt "How do I view the parameter and return types of a function?".
    Per Button kann man im Tool die Darstellung ändern und dann steht bei dieser Funktion anstelle von "?myFunc@@blabla@blabla" dann "bool myFunc(long, long &)". Bei den anderen Funktionen ändert sich nichts. Weder wird ein Rückgabetyp angezeigt noch die Parameter.

    Was hat nur diese Funktion gegen mich 😃

    EDIT2: Achja ich habe auch ohne LIB probiert über LoadLibrary() die DLL zu laden und darüber die Funktionen aufzurufen. Auch da klappt es nur mit 2 von 3 Funktionen und bei der selben hängt es und es kommt ein Error.

    typedef bool(__stdcall *_myFunc)(long var1, long &var2);
    _myFunc myFunc;
    if ((myFunc = (_myFunc)GetProcAddress(myDLL, "myFunc")) == NULL)
    {
        	ShowMessage(L"error");
    }
    


  • Hallo,

    Stichwort: Name Mangling

    So wie es scheint ist die COFF DLL mit einem C++ Compiler übersetzt worden (MSVC) und hat nicht alle Methoden mittels C-Schnittstelle bereitgestellt (extern "C") - so wie du es ja auch schon festgestellt hast.
    Generell sind die C++ Compiler nicht untereinander binärkompatibel, so daß es nicht so einfach möglich ist vom C++ Builder aus auf C++ Funktionen von anderen Compilern (z.B. MSVC) zuzugreifen.
    Solange jedoch nur Standard-Datentypen verwendet werden (wie bei deiner Funktion also long oder double), hast du vllt. noch eine Chance - lies mal Using Visual C++ DLLs with C++Builder (ich habe es jetzt nicht ganz im Detail gelesen).
    Viel Erfolg.


Log in to reply