Autor |
Beitrag |
don_basto
Hält's aus hier
Beiträge: 12
|
Verfasst: Sa 29.04.06 18:33
Hi,
ich beschäftige mich gerade zum ersten Mal mit Delphi. Ich habe eine DLL geschrieben, die ich gern unter Delphi testen möchte. Allerdings habe ich keine Tutorials, Links etc. gefunden, unter denen das Einbinden von DLLs beschrieben wird... .
Wie greife ich von Delphi aus auf Dlls zu?
(Die Dll-Fkt. orientieren sich an der Win32-API)
Danke,
don_basto.
|
|
Blackheart666
      
Beiträge: 2195
XP
D3Prof, D6Pers.
|
Verfasst: Sa 29.04.06 18:43
Schau mal hier www.dsdt.info/tutorials/dlls/ dort gibt's ein Tutorial zum Thema Dll.
|
|
don_basto 
Hält's aus hier
Beiträge: 12
|
Verfasst: Sa 29.04.06 18:56
Danke. Genau sowas habe ich gesucht. 
|
|
don_basto 
Hält's aus hier
Beiträge: 12
|
Verfasst: So 30.04.06 16:49
Noch eine Frage: Wie übersetze ich den C-String (const char*) nach Delphi?
Wenn ich den Delphi-String (string) nehme, gibt's Probleme.
//EDIT:
Bei String gibt's einen Laufzeitfehler und bei PChar wird der Einsprungpunkt in die Dll nicht gefunden. Die C-Signatur ist: load(const char* file)
|
|
don_basto 
Hält's aus hier
Beiträge: 12
|
Verfasst: So 30.04.06 18:21
Wenn ich die Dll dynamisch einbinde, wird die Dll zwar erfolgreich geladen, aber die Fkt. wird eben nicht gefunden.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| type TLoadFunction = function (filename : pchar): integer; stdcall;
function Init:bool; var LoadFunction : TLoadFunction; Handle : THandle; begin Handle:=LoadLibrary(PChar(ExtractFilePath(ParamStr(0))+'myLib.dll')); if Handle <> 0 then begin @LoadFunction := GetProcAddress(Handle, 'myLoad'); if @LoadFunction <> nil then begin LoadFunction(PChar('init.txt')); end; FreeLibrary(Handle); end;
result = true; end; |
|
|
Yamato
Hält's aus hier
Beiträge: 3
|
Verfasst: So 30.04.06 19:59
Ich hätte hier mal eine Zusatzfrage: Gibt es eigentlich eine Möglichkeit (kleines Tool oder so) herauszufinden, was sich für Funktionen mit welchen Parametern in einer DLL verbergen? Nicht jede DLL ist ja gut dokumentiert.
|
|
Waldteufel
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: So 30.04.06 20:55
Hi Yamato.
Yamato hat folgendes geschrieben: | was sich für Funktionen |
Das geht: DllExports  (nicht zu verwechseln mit dem gleichnamigen Tool von Luckie...)
Yamato hat folgendes geschrieben: | mit welchen Parametern |
Das geht leider nicht.
PS: Merke grade, dass auf der seite was mit der Reg-Datei unten nicht stimmt... 
|
|
nullplan001
      
Beiträge: 212
Win 2000 Professional, Debian Linux 4.0 (Etch,Stable)
Pascal (FreePascal 2.0.2, TurboPascal 7.0), C(++) (G++/GCC 3.4.2 + MinGW), Java (JDK 1.5.0_07), PHP (PHP 5.1.4)
|
Verfasst: So 30.04.06 22:17
@don-basto: Die auszuführende Funktion binde ich immer so ein:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| function LFunction (filename: pchar): integer; stdcall; var LoadFunction : TLoadFunction; Handle : THandle = 0;
begin @LoadFunction := nil; Handle := LoadLibrary(pchar('mylib.dll')); if Handle = 0 then begin Result := -1; exit; end; try @LoadFunction := GetprocAddress (Handle, pchar('myfun')); if @LoadFunction = nil then begin Result := -1; exit; end; Result := LoadFunction(filename); finally FreeLibrary(Handle); end; end; |
Im Hauptquelltext rufe ich dann die Funktion LFunction mit dem Parameter auf und tue so, als ob es sich hierbei um die darin geladene Funktion handelte. Ja nee, is klar, ist ja auch die geladene Funktion. Nur mit Fehlerkennung (-1). Weiterer Vorteil: Du willst das ja in einem Formular verwenden, nicht in einer Console-App. Da gibt es ja Wartezeiten. Hey, mit der Funktion da oben kannst du die DLL austauschen, wenn die Funktion gerade nicht verwendet wird. Und egal zu welcher wartezeit du das Programm beendest: Die DLL ist immer entladen. Das passiert immer am Ende der Funktion. Komme was wolle, bis auf vielleicht 'n Stromausfall. Die einzige Möglichkeit, dass am Ende die DLL immer noch drinsteht, ist die Programmtermination während der Verwendung der Funktion. Und zwar die unsanfte. (Unter Linux hieße es: Nicht TERM, sondern KILL. Wobei letztere Nachricht nur bei extrem störischen Programmen angewendet wird.)
Falls es nicht klar sein sollte: Die Funktion lädt die DLL, holt die Adresse der Funktion raus und führt die Funktion aus. Vorausgesetzt alles funktioniert. Wenn nicht, wird die DLL entladen und -1 zurückgegeben.
Und const char* nach Delphi dürfte ein Array of char sein. Was du dann wiederum in einen String umwandeln kannst. Andersrum nimmst du nicht @string_bla[0], sondern @string_bla[1]., weil in [0] ja nur die Länge steht. Achte darauf, dass das letzte Zeichen ein #0 ist, sonst rechnet C mit dem Inhalt deines Arbeitsspeichers weiter.
Tschö,
nullplan
_________________ Ich fahr' nicht selber, weil ich festgestellt habe: ich fahre zu emotional. Bin 180 gefahren wo 30 erlaubt war... -- Jürgen von der Lippe
|
|
Yamato
Hält's aus hier
Beiträge: 3
|
Verfasst: Mo 01.05.06 11:39
@Waldteufel:
Nettes Progrämmchen! Macht schon Spaß, in einigen DLLs rumzustöbern (obwohl in manchen gar nichts angezeigt wird?!). Doch wenn man den Namen extrahieren kann, warum dann nicht auch die Parameter? Komisch.
|
|
tommie-lie
      
Beiträge: 4373
Ubuntu 7.10 "Gutsy Gibbon"
|
Verfasst: Mo 01.05.06 11:55
don_basto hat folgendes geschrieben: | Noch eine Frage: Wie übersetze ich den C-String (const char*) nach Delphi? |
char * ist ein Zeiger auf ein char, also wäre die Delphi-Übersetzung PChar
don_basto hat folgendes geschrieben: | Delphi-Quelltext 1:
| type TLoadFunction = function (filename : pchar): integer; stdcall; | |
Bist du sicher, daß die Funktion in der DLL stdcall deklariert wurde? Wenn du keine zusätzliche Calling Convention in deiner C-DLL angegeben hast, ist die Calling Convention üblicherweise cdecl.
Ansonsten sollte deine Funktion eigentlich gefunden werden, wenn sie als "myLoad" exportiert wurde. Wenn du in C++ programmiert hast, könntest du Opfer das Name Manglings geworden sein, ein [code]extern "C" {}[code]-Block um die Funktionen sollte abhilfe schaffen. Ansonsten kannst du den korrketen NAmen mit DLLExports in Erfahrung bringen. Ansonsten sehe ich keinen Grund, warum er bei dir die Funktion nicht finden sollte.
nullplan001 hat folgendes geschrieben: | Delphi-Quelltext 1:
| function LFunction (filename: pchar): integer; stdcall; | |
Gibt es eigentlich einen Grund für dein stdcall an dieser Stelle?
Yamato hat folgendes geschrieben: | Doch wenn man den Namen extrahieren kann, warum dann nicht auch die Parameter? Komisch. |
Weil diese nicht dafür benötigt werden, wenn ich die Funktion aufrufen will. Deswegen stehen sie nicht in der Lookup-Tabelle der DLL. Nötig ist einzig und allein die Zuordnung Name->Adresse. Die PArameter muss ohnehin der Aufrufer richtig auf die Reihe kriegen, wieso sollten sie also in der Tabelle stehen, sie würden niemandem etwas bringen, außer dir, wenn du eine undokumentierte DLL vor dir hast. Es gibt Möglichkeiten entweder durch den Aufruf (aus einem anderen Programm, das die DLL benutzt) oder durch den Code der DLL auf die Parameter zu schließen. Bei stdcall beispielsweise muss die aufgerufene Funktion die PArameter vom Stack räumen. Das kannst du im Code erkennen und dann zumindest auf die Zahl der PArameter schließen. Durch die Benutzung des Stacks in der Funktion kannst du dann darauf schließen, wie groß diese Parameter sind, und wenn du gut Assembler kannst, sogar wofür genau sie verwendet werden. Ist aber nicht trivial.
_________________ Your computer is designed to become slower and more unreliable over time, so you have to upgrade. But if you'd like some false hope, I can tell you how to defragment your disk. - Dilbert
|
|
nullplan001
      
Beiträge: 212
Win 2000 Professional, Debian Linux 4.0 (Etch,Stable)
Pascal (FreePascal 2.0.2, TurboPascal 7.0), C(++) (G++/GCC 3.4.2 + MinGW), Java (JDK 1.5.0_07), PHP (PHP 5.1.4)
|
Verfasst: Mo 01.05.06 19:13
tommie-lie hat folgendes geschrieben: | Gibt es eigentlich einen Grund für dein stdcall an dieser Stelle? |
Gibt es: Die Funktion wurde in C geschrieben, richtig? Die C-Aufrufkonvention findet man in Delphi in stdcall wieder. Oder aber in cdecl. Aber ob Delphi das kann, weis ich nicht. Stdcall wird in jedem Fall unterstüzt.
Tschö,
nullplan
_________________ Ich fahr' nicht selber, weil ich festgestellt habe: ich fahre zu emotional. Bin 180 gefahren wo 30 erlaubt war... -- Jürgen von der Lippe
|
|
tommie-lie
      
Beiträge: 4373
Ubuntu 7.10 "Gutsy Gibbon"
|
Verfasst: Mo 01.05.06 19:20
nullplan001 hat folgendes geschrieben: | Gibt es: Die Funktion wurde in C geschrieben, richtig? |
Die Funktion in der DLL, die du aufrufst, ja. Aber nicht die Funktion, die du stdcall deklariert hast, die ist ganz offensichtlich in Delphi geschrieben. TLoadFunction muss die Aufrufkonvention haben, die auch in der dLL verwendet wurde, nicht dein Wrapper zum Aufruf.
nullplan001 hat folgendes geschrieben: | Die C-Aufrufkonvention findet man in Delphi in stdcall wieder. |
Nein. cdecl ist die Aufrufkonvention von C, keine andere. stdcall ist die Aufrufkonvention die aus Kompatibilitätsgründen in der Win32-API eingesetzt wird. Aber auch hier muss man dem C-Compiler sagen, welches ABI er nehmen soll, oder vor jede Funktion entsprechend eine Compiler-Direktive setzen, die ihm sagt, daß er die Funktion stdcall kompilieren soll.
nullplan001 hat folgendes geschrieben: | Aber ob Delphi das kann, weis ich nicht. |
Kann es.
_________________ Your computer is designed to become slower and more unreliable over time, so you have to upgrade. But if you'd like some false hope, I can tell you how to defragment your disk. - Dilbert
|
|
don_basto 
Hält's aus hier
Beiträge: 12
|
Verfasst: Mo 01.05.06 20:52
Erstmal danke für die Antworten, DLLExport ist auch ganz nützlich, aber mein Dllfkt. funtkionieren immer noch nicht. Es liegt auch nicht am PChar etc. Die Funktionen werden nicht gefunden. Als erstes würde ich vermuten, dass es an den Aufrufkonventionen liegt (bzw. an der Namessergänzung), aber ich kenne mich nicht dem Borland Debugger und der Hilfe aus. Im Visual Studio ist es einfacher.
Dank DLLExport komme ich an die dekorierte Dllfkt. ran: _myLoad@4.
Delphi-Quelltext 1:
| @LoadFunction := GetProcAddress(Handle, 'myLoad'); |
Aber wie finde ich die Fkt. raus, die hier gesucht wird ???
|
|
tommie-lie
      
Beiträge: 4373
Ubuntu 7.10 "Gutsy Gibbon"
|
Verfasst: Mo 01.05.06 21:00
_________________ Your computer is designed to become slower and more unreliable over time, so you have to upgrade. But if you'd like some false hope, I can tell you how to defragment your disk. - Dilbert
|
|
don_basto 
Hält's aus hier
Beiträge: 12
|
Verfasst: Mo 01.05.06 21:08
Hab ich schon drin. Aus C/C++ und C# hab ich auch keine Probleme mit der Benutzung der DLL, nur in Delphi hakt's leider.
|
|
nullplan001
      
Beiträge: 212
Win 2000 Professional, Debian Linux 4.0 (Etch,Stable)
Pascal (FreePascal 2.0.2, TurboPascal 7.0), C(++) (G++/GCC 3.4.2 + MinGW), Java (JDK 1.5.0_07), PHP (PHP 5.1.4)
|
Verfasst: Di 02.05.06 16:16
Seltsam... Naja, einer der Gründe, warum ich C nicht mag. Momentan kannst du nur mit dem Dependency Walker oder irgendeinem anderen ähnlichen Tool den echten Namen der Funktion aus der DLL holen und mit dem weiterarbeiten.
Tschö,
nullplan
_________________ Ich fahr' nicht selber, weil ich festgestellt habe: ich fahre zu emotional. Bin 180 gefahren wo 30 erlaubt war... -- Jürgen von der Lippe
|
|
tommie-lie
      
Beiträge: 4373
Ubuntu 7.10 "Gutsy Gibbon"
|
Verfasst: Di 02.05.06 18:09
In der Tat, mit der extern-"C"-Direktive sollte's eigentlich klappen.
nullplan001 hat folgendes geschrieben: | Naja, einer der Gründe, warum ich C nicht mag. |
Es hat a) nichts mit C, sondern mit C++ zu tun, und hat b) weder etwas mit C, noch mit C++ zu tun, weil es ein "Feature" des Compilers ist, nicht der Sprache.
_________________ Your computer is designed to become slower and more unreliable over time, so you have to upgrade. But if you'd like some false hope, I can tell you how to defragment your disk. - Dilbert
|
|
nullplan001
      
Beiträge: 212
Win 2000 Professional, Debian Linux 4.0 (Etch,Stable)
Pascal (FreePascal 2.0.2, TurboPascal 7.0), C(++) (G++/GCC 3.4.2 + MinGW), Java (JDK 1.5.0_07), PHP (PHP 5.1.4)
|
Verfasst: Di 02.05.06 18:22
Features sind u. a. deshalb toll, weil man sie abschalten kann / können sollte. Guck mal in die Compiler-Hilfe. Wenn es ein gutes Feature ist, lässt es sich per Direktive oder Command-Line-Switch abschalten. Einfach mal testen.
Tschö,
nullplan
_________________ Ich fahr' nicht selber, weil ich festgestellt habe: ich fahre zu emotional. Bin 180 gefahren wo 30 erlaubt war... -- Jürgen von der Lippe
|
|
don_basto 
Hält's aus hier
Beiträge: 12
|
Verfasst: So 20.08.06 12:56
Der Vollständigkeit halber der Grund für das Problem: Von C/C++ hab ich die Dll immer statisch eingebunden. Da der Linker die Feinarbeit übernimmt und das alles prima funktioniert hat, bin ich nicht auf die Idee gekommen, dass es vllt. an den dekorierten Name der Funktionen legen könnte. Das hat es aber! Nichtmal aus C/C++ ließ sich die Dll dynamisch binden.
Nachdem ich die Deko weggenommen hatte, lief's prima.
Grüße,
don_basto.
|
|