Autor Beitrag
Alice
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 120



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

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
// test.cpp : Definiert die Initialisierungsroutinen für die DLL.
//

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

ausblenden 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 <> 0then
     @DiiOpenDevice := GetProcAddress(hLibrary, '?calc@@YGNJPAD@Z');

      if (@DiiOpenDevice <> Nilthen
       DiiOpenDevice(1,'test.txt');

    if (hLibrary <> 0then
     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 user profile iconAXMD: Code- durch C#-Tags ersetzt


Zuletzt bearbeitet von Alice am Mo 09.06.08 11:12, insgesamt 1-mal bearbeitet
Silas
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 478

Windows XP Home
Delphi 2005, RAD Studio 2007, MASM32, FASM, SharpDevelop 3.0
BeitragVerfasst: 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:

ausblenden Quelltext
1:
DLL_EXPORT double _stdcall calc( long nubof , char *txtdatei );					
ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2077
Erhaltene Danke: 2

Win XP
Delphi 5 Ent., Delphi 2007 Prof
BeitragVerfasst: Di 27.05.08 16:34 
Versuchs mal mit
ausblenden Delphi-Quelltext
1:
  DiiOpenDevice : procedure ( nubof : integer ; txtdatei: pchar); stdcall;					



Edit: Zu langsam.
Alice Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 120



BeitragVerfasst: Di 27.05.08 17:25 
hi,

@Xentar
@Silas

danke! euch

cu

alice
Alice Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 120



BeitragVerfasst: Fr 06.06.08 06:08 
hi,

eine änderung, es wurde ein callback auf meinen wunsch eingebaut.

siehe:

vorher:
ausblenden Quelltext
1:
DLL_EXPORT double _stdcall calc( long nubof,char *txtdatei );					

nun:
ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: Fr 06.06.08 07:24 
ausblenden 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 120



BeitragVerfasst: Fr 06.06.08 08:20 
hi

hmm, so komme ich nicht weiter :(

ausblenden 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;
  /// ??? ich denke hier fehlt noch etwas? "DLL_EXPORT typedef void (__stdcall *ShowProgress)(long progress); "
  DiiOpenDevice : procedure ( nubofp : LongInt ; txtdatei: pchar; Proz: LongInt); stdcall;
begin

    hLibrary := LoadLibrary('test.dll');

    if (hLibrary <> 0then @DiiOpenDevice := GetProcAddress(hLibrary, '?calc@@YGXJPADP6GXJ@Z@Z');

    if (@DiiOpenDevice <> Nilthen begin
     DiiOpenDevice(12345,pchar('test.txt'),@Progess(Proz));
    end;

    if (hLibrary <> 0then FreeLibrary(hLibrary);


end;


was fehlt hier noch / bzw. ist falsch?

cu

alice
Martok
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 3661
Erhaltene Danke: 604

Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
BeitragVerfasst: Fr 06.06.08 09:21 
Du müsstest vielleicht irgendwo mal den Pointer übersetzen...

ausblenden Delphi-Quelltext
1:
2:
3:
4:
type
  TShowProgress = procedure(progress: integer); stdcall{nicht ganz sicher wegen stdcall... müsste aber eigentlich.}
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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 120



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


ausblenden volle Höhe 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'); // borland
    if (hLibrary <> 0then @DiiOpenDevice := GetProcAddress(hLibrary, '@calc$qqslpcpqqsl$v'); //borland
   end;

   if ms.Checked then begin
    hLibrary := LoadLibrary('pi.dll'); // ms
    if (hLibrary <> 0then @DiiOpenDevice := GetProcAddress(hLibrary, '?calc@@YGXJPADP6GXJ@Z@Z');   //ms
   end;

   if (@DiiOpenDevice <> Nilthen begin
     DiiOpenDevice(1024,pchar('test.txt'),@Progess);
   end;

   if (hLibrary <> 0then FreeLibrary(hLibrary);

end;


cu
Lossy eX
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1048
Erhaltene Danke: 4



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

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