Delphi-DLL nutzen mit VC++ 2010!



  • Hallo,

    ich habe ein großes Problem, an dem ich schon seit 4 Tagen hänge. Ich möchte eine DLL, die ich mit Delphi erstellt habe, in VC++ 2010 nutzen sowie - sofern möglich auch in Bloodshed Dev-C++ .

    Delphi erstellt die exportierten Symbole undekoriert. Also in form von "myfunc". (Dies ist auch bei den Symbolen von z.B. kernel32.dll der Fall, obwohl die WinAPI Funktionen __stdcall sind)

    Bezüglich VC++ habe ich folgendes unternommen:

    Die DLL hab ich in das Projektverzeichnis gepackt.

    Dann habe ich eine DEF erstellt:

    LIBRARY   STATMONDLL32 
    EXPORTS 
      getVersionNumberA = _getVersionNumberA@0
    

    Nun habe ich die DEF in eine LIB "kompiliert" mittels "lib.exe".

    Die LIB habe ich eingebunden in die Linker-Einstellungen von VC++.

    Ich versuche die Funktion nun zu importieren:

    extern "C" char* _stdcall getVersionLabelA();
    

    (Gibt es einen Unterschied zwischen _stdcall und __stdcall ?)

    Beim Kompilieren gibt es die Meldung:

    1>DllTest.obj : error LNK2019: Verweis auf nicht aufgelöstes externes Symbol "_getVersionNumberA@0" in Funktion "_wmain".

    Ich sehe mit einem Hexeditor, dass in der LIB trozdem noch versucht wird, auf "_getVersionNumberA" zur Verfügung zu stellen anstelle "_getVersionNumberA@0"...

    Ich brauche unbedingt Hilfe bei diesem Problem. Danke.

    Gruß
    blackdrake



  • Dieser Thread wurde von Moderator/in SeppJ aus dem Forum C++ (auch C++0x) in das Forum Compiler- und IDE-Forum verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.





  • Leider hast du dich überhaupt nicht mit meinem Problem beschäftigt oder die Frage richtig gelesen!

    Ich habe mir das schon zig mal durchgelesen, aber das Problem ist nunmal, dass die DLL einen undekorierten Namen (func) hat und C++ gerne einen dekorierten hätte (_func@0). Der Alias in der DEF klappt nicht, da nur _func ankommt anstelle _func@0. In dem Wiki-Artikel ist nur beschrieben, wie man die DLLs kompatibel macht beim selben Compiler, also mit Nutzung von __declspec(dllexport) und __declspec(dllimport).



  • Suchtest du etwa folgende oder eine ähnliche Info?
    http://www.esanu.name/delphi/DLL/Calling delphi DLL from MS Visual C.html

    Bitte recht pampig antworten, wenn nicht zutreffend 🤡



  • Hallo,

    die Seite zeigt das Problem auf, allerdings mit einem Workaround.

    Ich habe folgenden Teilerfolg:

    Wenn ich Delphi durch "exports name" mitteile, dass es die Funktion als "myfunction@0" anstelle "myfunction" exportieren soll (@0 = Byteanzahl der Argumente), dann funktioniert der DLL-Aufruf mit VC++.

    Allerdings finde ich es ziemlich unschön, die Namen in der DLL zu dekorieren. (Obwohl die Dekoration bei __stdcall bei Microsoft üblich ist) Wenn ich z.B. in die kernel32.dll schaue, dann sehe ich, dass diese DLL undekorierte Symbole exportiert (obwohl __stdcall!).

    Mein Wunsch wäre es also, dass ich die Symbole genau so wie in der WinAPI undekoriert exportiere (Pascal-Standard) und ebenso importiere.

    Dieser Artikel beschreibt, wie man im Pascal-Style (= undekoriert) EXPORTIERT: http://support.microsoft.com/kb/140485 . Meine Frage ist, wie ich diesen undekorierten Kram wieder importieren kann. Das scheint irgendwie schwer zu sein...

    Gruß
    blackdrake



  • BITTE, könnt ihr mir helfen? Ich versuche schon seit 6 Tagen diese DLL in VC++ einzubinden und habe die Frage schon in 3 Foren gestellt. Kann mir denn keiner helfen?

    Die DLL ist hier einmal hochgeladen

    http://www.viathinksoft.de/temp/StatMonDll32.dll

    Eines der exportierten Symbole heißt

    "getVersionNumberA" (undekoriert)

    Eine Funktion hiervon ist wie folgt deklariert:

    extern "C" int __stdcall getVersionNumberA();
    

    Und sollte "0" zurückgeben.

    Bitte helft mir, ich bin langsam am Verzweifeln!

    Gruß
    blackdrake



  • Die Frage ist sehr interessant, denn sie ist im Wesentlichen äquivalent zur Frage "wie erstellt Microsoft die Import-Bibliotheken für Windows-DLLs?". Diese exportieren auch größtenteils stdcall-Funktionen ohne jedwede Dekoration.

    Dieser Artikel bespricht ein sehr ähnliches Problem sowie die (überraschend einfache) Lösung dazu:
    http://qualapps.blogspot.com/2007/08/how-to-create-32-bit-import-libraries.html



  • Vielen Dank für den Link! Diese Seite scheint sich mit exakt diesem Problem zu beschäftigen.

    Ich versuche es gerade nachzuvollziehen.

    1.Follow the instructions in Q131313 under Stubbing Out Functions. Make sure you name the project the same as the Windows DLL.

    1.Follow the instructions in Q131313 under Stubbing Out Functions. Make sure you name the project the same as the Windows DLL.

    Allerdings sehe ich hier ein Problem. In diesem Dokument steht, dass ich

    CL/c /Ob0 mydll.CPP
    

    anwenden soll. Meine DLL ist allerdings in Delphi kompiliert. Ich kann hier nichts mit "CL" machen.

    2.Make sure your dummy functions are defined with __declspec(dllexport) as well as __stdcall.

    Ebensowenig kann ich __declspec(dllexport) in Delphi erwirken.

    3.For the header file used by the parent application, make sure that your function declarations are surrounded with extern "C".

    Hab ich gemacht:

    extern "C" {
    	int __stdcall getVersionNumberA();
    }
    

    4.Add a .DEF file to your project that includes the function names with no decoration.

    Hab ich gemacht:

    LIBRARY   STATMONDLL32
    DESCRIPTION 'Status Monitor Interpreter'
    EXPORTS
      getVersionNumberA
    

    Resultat: Geht noch nicht 😞 Liegt daher das Geheimnis in den ersten beiden Schritten, die ich wegen Delphi nicht nachvollziehen kann?



  • blackdrake schrieb:

    1.Follow the instructions in Q131313 under Stubbing Out Functions. Make sure you name the project the same as the Windows DLL.

    Allerdings sehe ich hier ein Problem. In diesem Dokument steht, dass ich

    CL/c /Ob0 mydll.CPP
    

    anwenden soll. Meine DLL ist allerdings in Delphi kompiliert. Ich kann hier nichts mit "CL" machen.

    Womit die DLL kompiliert wurde, ist doch völlig unerheblich; entscheidend ist, daß du sie behandelst, als hättest du den Quelltext nicht, also völlig gleichartig wie irgendeine Windows-DLL. Und im einen wie im anderen Fall sollst du eine Stub-Funktion in C++ schreiben und dann wie oben mit CL kompilieren.

    blackdrake schrieb:

    2.Make sure your dummy functions are defined with __declspec(dllexport) as well as __stdcall.

    Ebensowenig kann ich __declspec(dllexport) in Delphi erwirken.

    Da du deine dummy functions ja in C++ schreibst, geht es doch.



  • Hallo,

    was ist denn gemeint mit "Stub functions"? Ich kenne diesen Begriff nicht.

    Habe ich die "dummy functions" (Schritt 3 + 4) korrekt gemacht?

    Was muss ich jetzt konkret machen, damit es funktioniert?

    Gruß
    blackdrake



  • Nachtrag:

    Wenn ich in der DEF folgendes stehen habe:

    EXPORTS
      getVersionNumberA
    

    Dann sieht die LIB (dumpbin) folgendermaßen aus:

    Version      : 0
      Machine      : 14C (x86)
      TimeDateStamp: 4E60108E Fri Sep 02 ...
      SizeOfData   : 00000024
      DLL name     : STATMONDLL32.dll
      Symbol name  : _getVersionNumberA
      Type         : code
      Name type    : no prefix
      Hint         : 2
      Name         : getVersionNumberA
    

    "NAME" ist korrekt. "SYMBOL NAME" falsch.

    Wenn ich in der DEF folgendes stehen habe:

    EXPORTS
      getVersionNumberA@0=getVersionNumberA
    

    Dann sieht die LIB so aus:

    Version      : 0
      Machine      : 14C (x86)
      TimeDateStamp: 4E601115 Fri Sep 02 0
      SizeOfData   : 00000026
      DLL name     : STATMONDLL32.dll
      Symbol name  : _getVersionNumberA@0
      Type         : code
      Name type    : no prefix
      Hint         : 2
      Name         : getVersionNumberA@0
    

    Jetzt genau andersrum: "NAME" falsch, dafür "SYMBOL NAME" korrekt.

    Gewünscht wäre eine LIB, die folgendes aufweist:

    Symbol name  : _getVersionNumberA@0
      Name         : getVersionNumberA
    


  • blackdrake schrieb:

    was ist denn gemeint mit "Stub functions"? Ich kenne diesen Begriff nicht.

    Steht im Artikel. Du tust eben so, als hättest du eine Implementation der Funktionen in C++; diese sind aber leere Funktionen. Sowas nennt man "Stub".

    blackdrake schrieb:

    Habe ich die "dummy functions" (Schritt 3 + 4) korrekt gemacht?

    Sieht so aus, ja.

    blackdrake schrieb:

    Was muss ich jetzt konkret machen, damit es funktioniert?

    Steht im Artikel, oder?



  • Ok. Gearbeitet habe ich mit "stubs" schon, nur habe ich den dazugehörigen Namen nie so benutzt.

    In dem Microsoft-Artikel steht, wie man das ganze löst mittels __declspec(dllimport) und __declspec(dllexport). Um die DLL muss ich mich ja nicht kümmern, also fällt die eine hälfte weg. Was für das Importieren notwendig ist, habe ich gemacht. Ebenso habe ich die 4 Punkte des Blog-Entries von Jim Beveridge beachtet.

    Das Problem ist jetzt, wie du oben siehst bei der LIB Datei. Man kann klar erkennen, dass entweder der Name oder der Symbol-Name falsch ist.

    In dem Blog von Jim steht allerdings noch etwas interessantes:

    Er schreibt, dass er die LIB mit "EXPORTS myfunc" erstellt hat und sein DUMPBIN zeigt "Name type: undecorate". MEIN dumpbin sagt mir "Name type: no prefix". Hier ist scheinbar schon ein Untersschied. Irgendwas stimmt mit meiner LIB nicht..

    Gruß
    blackdrake



  • Kann mir denn niemand helfen? Es kann doch nicht sein, dass niemand weiß, wie man Pascal-Style DLLs (undekoriert) in VC++ nutzt!

    Der Blog von Jim scheint irgendwie nicht zu stimmen.

    Er beschreibt dass er "myfunc" in die DEF Datei schreibt und dass dies reicht, dass die LIB mit dem Inhalt "Das Symbol _myfunc@0 heißt in der DLL myfunc" erstellt wird. Woher will den lib.exe wissen, dass myfunc genau einen Stack von 0 erwartet? Da kann also alleine vom Informationsdefizit etwas nicht stimmen.

    Meine Frage ist, wie ich eine LIB erstellen kann, so wie es Microsoft mit seinen WinAPI-LIBs macht. Diese weißen die Namenstypen "Name type: undecorate" auf. Mir ist nicht bekannt, dass man das mit einer DEF machen kann.

    Ich habe mit einem Hex-Editor einen Erfolg erzielt, allerdings finde ich die Lösung echt blöd, denn sie ist unsicher und man kann schnell etwas kaputt machen.

    Es funktioniert wie folgt:

    Die DEF Datei ist die folgende:

    LIBRARY   statmondll32
    EXPORTS
    getVersionNumberA@0=getVersionNumberA
    

    Diese wird nun in eine LIB gewandelt:

    lib.exe /def:statmondll32.def /out:statmondll32.lib
    

    Die LIB wird mit dumpbin folgendermaßen aussehen:

    Symbol name  : _getVersionNumberA@0
      Type         : code
      Name type    : no prefix
      Hint         : 0
      Name         : getVersionNumberA@0
    

    Der SYMBOL NAME ist OK. C++ wird also das Symbol in der LIB finden. FALSCH ist hingegen der Name Type. "no prefix" bedeutet, dass das "_" entfernt wird. Das "@0" bleibt. Folglich wird versucht, in der DLL "getVersionNumberA@0" zu finden, was nicht existiert!!!

    Wie schafft Microsoft, den Nametype auf "undecorate" umzubiegen?

    Öffnen wir die erstellte LIB in einem Hexeditor und suchen das LETZTE Vorkommen von "_getVersionNumberA@0".

    Wir springen mit dem Cursor 2 Byte zurück. Dort steht nun eine Zelle 0x08. Wir ändern den Wert in 0x0C.

    (Woher ich das mit 0x0C weiß? Von user32.lib abgeguckt... -.-)

    Anschließend zeigt Dumpbin:

    Symbol name  : _getVersionNumberA@0
      Type         : code
      Name type    : undecorate
      Hint         : 0
      Name         : getVersionNumberA
    

    Problem gelöst. Aber geht das auch ohne Hexeditor? Und vorallem: Wieso bin ich der erste von vielen Millionen C++ Programmierern, der einen Hex-Editor braucht um eine DLL (mit static linking) zu nutzen zu können???

    Kurz: Ich will lib.exe mitteilen, dass es das Symbol "undecorate" machen soll.

    Bitte, ich brauche euere Hilfe. Ich kann nicht glauben, dass ich nun auf den Tag genau 7 Tage damit verbringe, eine verdammte DLL auf elegante weise zu nutzen. 😡

    PS: Meine lib.exe Version:

    C:\Program Files\Microsoft Visual Studio 10.0\VC>lib.exe /verbose
    Microsoft (R) Library Manager Version 10.00.30319.01
    Copyright (C) Microsoft Corporation.  All rights reserved.
    


  • blackdrake schrieb:

    Bitte, ich brauche euere Hilfe. Ich kann nicht glauben, dass ich nun auf den Tag genau 7 Tage damit verbringe, eine verdammte DLL auf elegante weise zu nutzen. 😡

    Na, herzlichen Glückwunsch. Wenn du in dieser Zeit den Artikel genau gelesen und befolgt hättest, statt mit einem Hex-Editor herumzuspielen, wäre sie besser genutzt gewesen. Was im Artikel steht, ist nämlich ganz simpel und funktioniert wunderbar.

    1. Follow the instructions in Q131313 under Stubbing Out Functions. Make sure you name the project the same as the Windows DLL.
    2. Make sure your dummy functions are defined with __declspec(dllexport) as well as __stdcall.

    // statmondll32.c
    __declspec (dllexport) int __stdcall getVersionNumberA (void)
    {
    }
    

    3. For the header file used by the parent application, make sure that your function declarations are surrounded with extern "C".

    Oder alternativ: nimm eine .c-Datei statt einer .cpp-Datei. Geht aber beides.

    4. Add a .DEF file to your project that includes the function names with no decoration.

    LIBRARY StatMonDll32
    EXPORTS
      getVersionNumberA
    

    Projekt kompilieren, fertig.

    Da ich keine Lust habe, VS zu starten, geht der Rest auch über die Kommandozeile:

    cl /c statmondll32.c
    link /DLL /DEF:statmondll32.def statmondll32.obj
    dumpbin /HEADERS statmondll32.lib
    

    Ausgabe:

    Microsoft (R) COFF/PE Dumper Version 10.00.30319.01
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    Dump of file statmondll32.lib
    
    File Type: LIBRARY
    
    [...]
    
      Version      : 0
      Machine      : 14C (x86)
      TimeDateStamp: 4E62058D Sat Sep 03 12:46:37 2011
      SizeOfData   : 00000026
      DLL name     : StatMonDll32.dll
      Symbol name  : _getVersionNumberA@0
      Type         : code
      Name type    : undecorate
      Hint         : 0
      Name         : getVersionNumberA
    
    [...]
    


  • Vielen Dank für deine Antwort.

    Ich habe den Artikel schon aufmerksam gelesen, nur stand sowohl im Blog als auch im MS QB nur etwas von "LIB.EXE /DEF" drin, keinesfalls dass man die DEF zur Lösung des Problems an LINK.EXE verfüttern soll. Insofern ist die Vorgehensweise nicht 100% ersichtlich.

    Wie dem auch sei, leider funktioniert es immer noch nicht.

    LINK.EXE (sowohl in der CLI als auch in VC) meldet:

    statmondll32.def : error LNK2001: Nicht aufgelöstes externes Symbol "getVersionNumberA".
    statmondll32.lib : fatal error LNK1120: 1 nicht aufgelöste externe Verweise.
    

    Die DLL ist sicherheitshalber im gleichen Verzeichnis.

    Ich versteh nicht ganz, was LINK hier auszusetzen hat...



  • Das Blog-Posting geht davon aus, daß du das Ganze in Visual Studio erledigst und dementsprechend ein DLL-Projekt anlegst. Steht auch so drin.

    Daß es nicht klappt, ist eigenartig; wir verwenden doch beide VS 2010, also liegt der Unterschied (immer noch) in der Benutzung.

    Lade bitte mal alle dazugehörigen Dateien (*.c, *.def und eine Batch-Datei mit den CL-, LINK- und DUMPBIN-Aufrufen, die du tätigst) irgendwo hoch.



  • Hallo,

    ich habe das Problem nach einer kleinen Pause nun endlich lösen können. Ich habe nun auch endlich Verstanden, was es mit "Dummy" und "Stub" genau sind und für was man sie braucht. (Ich ging ursprünglich davon aus dass Dummy und Stub das selbe sind)

    Ich hatte deinen Code

    __declspec (dllexport) int __stdcall getVersionNumberA (void) 
    { 
    }
    

    wegen Compilermeldung geändert in

    __declspec (dllexport) int __stdcall getVersionNumberA (void);
    

    Dadurch war es kein Dummy mehr sondern ein Stub.

    Nach Änderung in

    __declspec (dllexport) int __stdcall getVersionNumberA (void) 
    {
      return 0;
    }
    

    geht es. Eine Dummy-DLL wird erstellt und liefert eine passende LIB. Mit dieser LIB binde ich das Symbol korrekt ein.

    Es ist ein wenig gewöhnungsbedürftig, dass man eine "Müll"-DLL erstellen muss, nur um diese LIB zu erhalten. Auf den meisten Webseiten wird das Vorgehen mit LIB.EXE erläutert oder gar darauf hingewiesen dass man keine LIB-Dateien mehr braucht, da sie obsolet seien. Per Batch lösche ich die Dummy-DLL dann schnell, damit sie nicht versehentlich veröffentlicht werden kann (da sie den selben Namen trägt wie die "echte" DLL).

    Ich denke, dass ich mal eine Anleitung in meinen Blog packen werde, wo ich die Vorgehensweise Schritt für Schritt erläutere, damit auch für Visual Studio Anfänger es verstehen können. Es gibt bis auf Jim's Blog kaum Informationen im Internet über das undekorierte Symbole importieren.

    Vielen Dank für deine Hilfe. Ohne den entscheidenden Hinweis mit "statmondll32.c" (Schritt 1+2 in Jim's Blog) wäre ich nicht vorangekommen.

    Gruß
    blackdrake



  • blackdrake schrieb:

    (Ich ging ursprünglich davon aus dass Dummy und Stub das selbe sind)

    Beide Begriffe sind schwammig. "Stub" bezieht sich aber in diesem Kontext pratisch immer auf eine (leere) Funktionsdefinition, "Dummy" aber meistens auch. Demnach war dein anfängliches Verständnis durchaus berechtigt.

    blackdrake schrieb:

    Ich hatte deinen Code

    __declspec (dllexport) int __stdcall getVersionNumberA (void) 
    { 
    }
    

    wegen Compilermeldung geändert in

    __declspec (dllexport) int __stdcall getVersionNumberA (void);
    

    Da kann ich dir natürlich auch nicht helfen, wenn du stillschweigend von meinem Vorschlag abweichst.

    blackdrake schrieb:

    Dadurch war es kein Dummy mehr sondern ein Stub.

    Dadurch war es keine Funktionsdefinition ("Stub", "Dummy-Definition") mehr, sondern nur eine -deklaration. Sicher aber kein Stub.


Anmelden zum Antworten