Autor Beitrag
don_basto
Hält's aus hier
Beiträge: 12



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2195

XP
D3Prof, D6Pers.
BeitragVerfasst: Sa 29.04.06 18:43 
Schau mal hier www.dsdt.info/tutorials/dlls/ dort gibt's ein Tutorial zum Thema Dll.
don_basto Threadstarter
Hält's aus hier
Beiträge: 12



BeitragVerfasst: Sa 29.04.06 18:56 
Danke. Genau sowas habe ich gesucht. :)
don_basto Threadstarter
Hält's aus hier
Beiträge: 12



BeitragVerfasst: 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 Threadstarter
Hält's aus hier
Beiträge: 12



BeitragVerfasst: 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.
ausblenden 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



BeitragVerfasst: 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



BeitragVerfasst: So 30.04.06 20:55 
Hi Yamato.

user profile iconYamato hat folgendes geschrieben:
was sich für Funktionen
Das geht: DllExports :-) (nicht zu verwechseln mit dem gleichnamigen Tool von user profile iconLuckie...)

user profile iconYamato 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... :shock:
nullplan001
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
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)
BeitragVerfasst: So 30.04.06 22:17 
@don-basto: Die auszuführende Funktion binde ich immer so ein:
ausblenden 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



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic star
Beiträge: 4373

Ubuntu 7.10 "Gutsy Gibbon"

BeitragVerfasst: Mo 01.05.06 11:55 
user profile icondon_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 ;-)

user profile icondon_basto hat folgendes geschrieben:
ausblenden 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.

user profile iconnullplan001 hat folgendes geschrieben:
ausblenden Delphi-Quelltext
1:
function LFunction (filename: pchar): integer; stdcall;					
Gibt es eigentlich einen Grund für dein stdcall an dieser Stelle?

user profile iconYamato 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
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
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)
BeitragVerfasst: Mo 01.05.06 19:13 
user profile icontommie-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
ontopic starontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic star
Beiträge: 4373

Ubuntu 7.10 "Gutsy Gibbon"

BeitragVerfasst: Mo 01.05.06 19:20 
user profile iconnullplan001 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 Threadstarter
Hält's aus hier
Beiträge: 12



BeitragVerfasst: 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. :wink:

Dank DLLExport komme ich an die dekorierte Dllfkt. ran: _myLoad@4.
ausblenden Delphi-Quelltext
1:
@LoadFunction := GetProcAddress(Handle, 'myLoad');					

Aber wie finde ich die Fkt. raus, die hier gesucht wird ???
tommie-lie
ontopic starontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic star
Beiträge: 4373

Ubuntu 7.10 "Gutsy Gibbon"

BeitragVerfasst: Mo 01.05.06 21:00 
user profile icondon_basto hat folgendes geschrieben:
Dank DLLExport komme ich an die dekorierte Dllfkt. ran: _myLoad@4.
ausblenden Delphi-Quelltext
1:
@LoadFunction := GetProcAddress(Handle, 'myLoad');					

Aber wie finde ich die Fkt. raus, die hier gesucht wird ???
Mit "_myLoad@4". Aber ich empfehle dir trotzdem dringend die Benutzung von extern "C" {}. Macht dein Leben leichter ;-)
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
#include <stdio.h>

extern "C"
{

  void someFunction()
  {
    printf("Hello, world");
  };

}
Der Symbolname im Binary ist dann ebenfalls nur "someFunction" und nichts anderes.

_________________
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 Threadstarter
Hält's aus hier
Beiträge: 12



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
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)
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic star
Beiträge: 4373

Ubuntu 7.10 "Gutsy Gibbon"

BeitragVerfasst: Di 02.05.06 18:09 
user profile iconnullplan001 hat folgendes geschrieben:
Seltsam...
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
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
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)
BeitragVerfasst: 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 Threadstarter
Hält's aus hier
Beiträge: 12



BeitragVerfasst: 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.