Entwickler-Ecke
Windows API - C++ DLL in Delphi ansprechen!?!
Alice - Di 27.05.08 16:14
Titel: C++ DLL in Delphi ansprechen!?!
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
Silas - Di 27.05.08 16:33
Titel: Re: C++ DLL in Delphi ansprechen!?!
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.
Xentar - Di 27.05.08 16:34
Versuchs mal mit
Delphi-Quelltext
1:
| DiiOpenDevice : procedure ( nubof : integer ; txtdatei: pchar); stdcall; |
Edit: Zu langsam.
Alice - Di 27.05.08 17:25
hi,
@Xentar
@Silas
danke! euch
cu
alice
Alice - 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 - Fr 06.06.08 07:24
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| procedure Progess; begin end;
calc(..,..,@Progress); |
Alice - 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 - 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; |
Alice - 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)?:
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: 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 - 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); |
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!