Autor |
Beitrag |
Alice
      
Beiträge: 120
|
Verfasst: Di 27.05.08 16:14
hi,
ich versuche hier eine *.dll (kommend aus MS C++) anzusprechen, also deren
funktion in delphi zu nutzen:
hier der code aus C++:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| #include "stdafx.h" #include "test.h"
#ifdef _DEBUG #define new DEBUG_NEW #endif
# define DLL_EXPORT __declspec(dllexport)
DLL_EXPORT double _stdcall calc( long nubof , char *txtdatei ); |
und so habe ich es versucht:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| procedure TForm1.Button1Click(Sender: TObject); var hLibrary : HMODULE; DiiOpenDevice : procedure ( nubof : integer ; txtdatei: pchar); begin
hLibrary :=LoadLibrary('test.dll');
if (hLibrary <> 0) then @DiiOpenDevice := GetProcAddress(hLibrary, '?calc@@YGNJPAD@Z');
if (@DiiOpenDevice <> Nil) then DiiOpenDevice(1,'test.txt');
if (hLibrary <> 0) then FreeLibrary(hLibrary);
end; |
soweit ich sehen kann, wird die routine auch angesprochen
aber:
die übergebenen variablen kommen *verkehrt an, die nubof wir zu ??? (irgend ein num. wert)
und anstatt der test.txt (die durch die dll erstellt werden sollte) lautet die
datei z.b.: d„iBbfgiB
der inhalt der datei, jedoch wird ein ergebniss sein, dass auf ??? = nubof basiert.
wo liegt der fehler?
nebenbei:
ich konnte die routine nur über den namen '?calc@@YGNJPAD@Z' (ersehen in Dependency Walker)
ansprechen, eigentlich sollte sie nur 'calc' lauten.
wieso, ist das so?
cu and thx
alice
Moderiert von AXMD: Code- durch C#-Tags ersetzt
Zuletzt bearbeitet von Alice am Mo 09.06.08 11:12, insgesamt 1-mal bearbeitet
|
|
Silas
      
Beiträge: 478
Windows XP Home
Delphi 2005, RAD Studio 2007, MASM32, FASM, SharpDevelop 3.0
|
Verfasst: Di 27.05.08 16:33
Hallo,
das Problem besteht darin, dass die Pascal-Aufrufkovention "verkehrt herum" arbeitet, deswegen musst du dieselbe Aufrufkonvention auch in deinem Delphi-Code angeben:
Quelltext 1:
| DLL_EXPORT double _stdcall calc( long nubof , char *txtdatei ); | Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| procedure TForm1.Button1Click(Sender: TObject); var hLibrary : HMODULE; DiiOpenDevice : procedure ( nubof : integer ; txtdatei: pchar); stdcall; begin
...
end; |
Edit: Wegen dem Namen: Das liegt daran, dass C++ (im Gegensatz zu z.B. Pascal und C) die Namen standardmäßig so "verunstaltet", um die zu übergebenden Parameter festzulegen.
_________________ Religionskriege sind nur Streitigkeiten darüber, wer den cooleren imaginären Freund hat
Zuletzt bearbeitet von Silas am Di 27.05.08 16:35, insgesamt 1-mal bearbeitet
|
|
Xentar
      
Beiträge: 2077
Erhaltene Danke: 2
Win XP
Delphi 5 Ent., Delphi 2007 Prof
|
Verfasst: Di 27.05.08 16:34
Versuchs mal mit
Delphi-Quelltext 1:
| DiiOpenDevice : procedure ( nubof : integer ; txtdatei: pchar); stdcall; |
Edit: Zu langsam.
|
|
Alice 
      
Beiträge: 120
|
Verfasst: Di 27.05.08 17:25
hi,
@Xentar
@Silas
danke! euch
cu
alice
|
|
Alice 
      
Beiträge: 120
|
Verfasst: Fr 06.06.08 06:08
hi,
eine änderung, es wurde ein callback auf meinen wunsch eingebaut.
siehe:
vorher:
Quelltext 1:
| DLL_EXPORT double _stdcall calc( long nubof,char *txtdatei ); |
nun:
Quelltext 1: 2:
| DLL_EXPORT typedef void (__stdcall *ShowProgress)(long progress); DLL_EXPORT void _stdcall calc( long nubof,char * txtdatei,ShowProgress ProFunc); |
wie binde ich das ganze nun ein?, also so das ich auf dieses ShowProgress zugreifen kann
cu
alice
|
|
uall@ogc
      
Beiträge: 1826
Erhaltene Danke: 11
Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
|
Verfasst: Fr 06.06.08 07:24
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| procedure Progess; begin end;
calc(..,..,@Progress); |
_________________ wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit
|
|
Alice 
      
Beiträge: 120
|
Verfasst: Fr 06.06.08 08:20
hi
hmm, so komme ich nicht weiter
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27:
| procedure Progess(x:Integer); begin Form1.label1.caption := inttostr(x); end;
. . .
var hLibrary : HMODULE; DiiOpenDevice : procedure ( nubofp : LongInt ; txtdatei: pchar; Proz: LongInt); stdcall; begin
hLibrary := LoadLibrary('test.dll');
if (hLibrary <> 0) then @DiiOpenDevice := GetProcAddress(hLibrary, '?calc@@YGXJPADP6GXJ@Z@Z');
if (@DiiOpenDevice <> Nil) then begin DiiOpenDevice(12345,pchar('test.txt'),@Progess(Proz)); end;
if (hLibrary <> 0) then FreeLibrary(hLibrary);
end; |
was fehlt hier noch / bzw. ist falsch?
cu
alice
|
|
Martok
      
Beiträge: 3661
Erhaltene Danke: 604
Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
|
Verfasst: Fr 06.06.08 09:21
Du müsstest vielleicht irgendwo mal den Pointer übersetzen...
Delphi-Quelltext 1: 2: 3: 4:
| type TShowProgress = procedure(progress: integer); stdcall; var DiiOpenDevice : procedure ( nubofp : LongInt ; txtdatei: pchar; Proz: TShowProgress); stdcall; |
_________________ "The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
|
|
Alice 
      
Beiträge: 120
|
Verfasst: Mo 09.06.08 08:23
hi,
die dll wurde nun mit 2 versch. kompilern kompiliert ,
(die MS dll ist wesentlich scheller, ging aus test ohne callback hervor)
einmal mit borland c++ und MS c++,
das kompilat des borland kopilers funktioniert nun einwandfrei! (thx martok) incl. callback.
die MS dll jedoch nicht, die funktion springt zwar an,
der callback wird genau 2x angesprochen und bringt auch
ein bis dahin ein ergebniss, steigt dann aber aus (access violation)!?
warum? muss wenn ich eine MS dll nutze am folg. code etwas geändert werden
(bis auf den funkt. namen, den beide kompiler jeweils mit einem anderem namen versehen)?:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34:
| procedure Progess(x:integer); begin Form.ProgressBar.Position := x; end;
. . .
procedure TForm1.ButtonClick(Sender: TObject); type TShowProgress = procedure(progress: integer); stdcall; var DiiOpenDevice : procedure ( nubofp : LongInt ; txtdatei: pchar; Proz: TShowProgress); stdcall; begin
if borland.Checked then begin hLibrary := LoadLibrary('raw.dll'); if (hLibrary <> 0) then @DiiOpenDevice := GetProcAddress(hLibrary, '@calc$qqslpcpqqsl$v'); end;
if ms.Checked then begin hLibrary := LoadLibrary('pi.dll'); if (hLibrary <> 0) then @DiiOpenDevice := GetProcAddress(hLibrary, '?calc@@YGXJPADP6GXJ@Z@Z'); end;
if (@DiiOpenDevice <> Nil) then begin DiiOpenDevice(1024,pchar('test.txt'),@Progess); end;
if (hLibrary <> 0) then FreeLibrary(hLibrary);
end; |
cu
|
|
Lossy eX
      
Beiträge: 1048
Erhaltene Danke: 4
|
Verfasst: Mo 09.06.08 11:32
C++ Komplier versehen die Funktionsnamen mit einer Liste von Paramatern. Anzahl der Variablen und Parametertyp. Ganz komisch codiert. Kann aber je nach Kompiler unterschiedlich sein. Wenn du die Methoden in C++ als extern "C" deklarierst dann werden sie als C Methoden exportiert. Und dann bekommen sie nur den Namen der Methoden aber keine Parameter. Also würden dann nur noch "calc" heißen. Wie folgt sollte genügen.
C++ Header 1: 2: 3: 4: 5: 6: 7: 8: 9:
| #ifdef __cplusplus extern "C" { #endif
// Funktionsdeklaration
#ifdef __cplusplus } #endif |
Aufrufkonvention: Wenn du eine DLL ansprichst MUSST du immer auf die richtige Aufrufkonvention achten. Das ist sehr wichtig. C++ arbeitet meines Wissens nach per default mit stdcall. Pascal nicht. Bei stdcall werden die Paramater von Links nach Rechts auf dem Stack übergeben und der Aufgerufene räumt die Paramater wieder weg. Wenn du jetzt einen Pointer auf eine Methode hast die per Stdcall angesprochen wird aber die Parameter anders erwartet, dann kann das natürlich nicht gehen. Deswegen bei DLL besser immer eine Konvention angeben. Und zwar auf beiden Seiten.
Bei dir ist das Problem, dass deine Methode Progess keine Konvention hat. Also stdcall; anhängen.
PS: Außerdem sollte es genügen, wenn du die Methode Progess direkt übergibst. Da explizit den Pointer übergeben zu müssen sollte nicht nötig sein. Bzw ein konstanter String muss auch nicht nach pChar gecastet werden.
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| procedure Progess(x:integer); stdcall; begin Form.ProgressBar.Position := x; end;
DiiOpenDevice(1024, 'test.txt', Progess); |
_________________ Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.
|
|
|