Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi C++ Dll in Delphi (https://www.delphipraxis.net/99887-c-dll-delphi.html)

jst69 19. Sep 2007 09:04


C++ Dll in Delphi
 
Hallo,

also ich habe ein Problem beim Einbinden einer DLL und habe schon verschiedenes ausprobiert. Nun brauche ich eure Hilfe. Die Variable c sollte mir das Resultat zurückgeben. Die DLL läuft durch und ich bekomme einen Rückgabewert, aber wenn ich die Variable c auslesen möchte, steht da immer noch der Initialwert und nicht das Resultat der Berechnung.

My Code:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
type
  {TIBANProc = function(d: integer; var c: PChar; b: PChar; a: PChar): integer; stdcall;}
  TIBANProc = function(a: PChar; b: PChar; var c: PChar; d: integer): integer; stdcall;

var
  hDLL: THandle; // Handle zur DLL
  iRes: integer; // Ergebnis der Funktion
  FarProc: TIBANProc;
  sDLLPath: PAnsiChar;
  a,b: pChar;
  c: pChar;
  d: integer;
begin
  sDLLPath := PChar(ExtractFilePath(Application.ExeName) + 'IBANKernel.dll');
  hDLL := LoadLibrary(sDLLPath);
  if hDLL = 0 then begin
    ShowMessage('DLL konnte nicht geladen werden.');
    Exit;
  end;

  try
    a := pChar('415811.00032');
    b := pChar('100');
    c := pChar('xy');
    d := 21;
    iRes := 0;
    @FarProc := GetProcAddress(hDLL, 'IT_IBANConvert');
    if Assigned(@FarProc) then
      iRes := FarProc(a,b,c,d);
    ShowMessage('Bingo-->'+a+'-->'+b+'-->'+c+'------->'+IntToStr(iRes));

    FreeLibrary(hDLL);
  except
    ShowMessage('Funktion der DLL konnte nicht ausgeführt werden.');
  end;
end;
Hier noch die H-Datei der DLL:
Code:
typedef int (__cdecl *IT_IBANConvert)     (char *pszKonto,
                                            char *pszBCPC,
                                            char *pszIBAN,
                                            int nIBANLen,
                                            char *pszBC,
                                            int nBCLen,
                                            char *pszPC,
                                            int nPCLen,
                                            char *pszBIC,
                                            int nBICLen);
Die ersten 4 Parameter sind zwingend, die anderen nicht. Was mache ich falsch?

[edit=SirThornberry]Delphi-Tags und C-Tags gesetzt - nächstes mal bitte selbst machen :-) Mfg, SirThornberry[/edit]

Lossy eX 19. Sep 2007 09:37

Re: C++ Dll in Delphi
 
Du benutzt 2 unterschiedliche Aufrufkonvetionen. Deine Methode benutzt stdcall und die aus der DLL benutzt __cdecl. Das entspricht cdecl in Delphi.

Und dann solltest du in jedem Falle alle Parameter deklarieren. Egal ob die Werte davon benötigt werden oder nicht. Die Funktion erwartet immer alle Parameter egal ob DU sie verwendest oder nicht. Aber übergeben musst du sie. Für "leere" pchars einfach ein nil und für Zahlen eine 0 übergeben. Das sollte ausreichen.

Sollte also in etwa so aussehen.
Code:
TIBANProc = function(
  pszKonto: PChar;
  pszBCPC: PChar;
  pszIBAN: PChar;
  nIBANLen: Integer;
  pszBC: pChar;
  nBCLen: Integer;
  pszPC: pChar;
  nPCLen: Integer;
  pszBIC: pChar;
  nBICLen: Integer
): Integer; cdecl;
Das var ist bei pChars nicht nötig, wenn nicht sogar falsch, da ein pChar bereits den Pointer auf einen Text enthält. Wenn du jetzt noch var sagst, dann wird eigentlich sogar die Adresse der pChar Variable übergeben, da ja der Wert der Variable verändert werden darf.

Wenn du konstante Strings an eine Methode übergeben möchtest, dann kannst du das auch schon direkt machen. Delphi übergibt dann automatisch nur den Pointer. Bei pChars die als Rückgabewert dienen (kann man da nur vermuten) musst du dafür sorgen, dass der Platz in dem Pointer auch entsprechend groß ist. Da würde ich empfehlen. Entweder mit StrAlloc / StrDispose einen Text zu erzeugen oder bei einem String SetLength aufrufen und dann pChar(Text) an die Methode zu übergeben. Wenn die nämlich versuchen etwas in den Speicher zu schreiben und die Größe ist zu klein oder der Wert für die Länge ist zu groß, dann greifen die unweigerlich in fremden Speicher. Damit hast du dann einen sogenannten Bufferoverflow erzeugt. Was häßlich enden kann. ;)

PS: a, b, c, d sind immer ganz schlechte Bezeichner. ;)

Muetze1 19. Sep 2007 09:50

Re: C++ Dll in Delphi
 
Und benutze lieber SageLoadLibrary(), dass scheint mir keine Borland C++Builder DLL zu sein...

jst69 19. Sep 2007 10:49

Re: C++ Dll in Delphi
 
Bingo so funktionierts! Besten Dank!

Hier mein Code:
Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    Edit4: TEdit;
    Edit5: TEdit;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;
       
  procedure DllMessage; external 'IBANKernel.dll'

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
type
  TIBANProc = function(
  pszKonto: PChar;
  pszBCPC: PChar;
  pszIBAN: PChar;
  nIBANLen: Integer;
  pszBC: pChar;
  nBCLen: Integer;
  pszPC: pChar;
  nPCLen: Integer;
  pszBIC: pChar;
  nBICLen: Integer
): Integer; cdecl;

var
  hDLL: THandle; // Handle zur DLL
  iRes: integer; // Ergebnis der Funktion
  FarProc: TIBANProc;
  sDLLPath: PAnsiChar;
  pszKonto,pszBCPC,pszIBAN,pszBC,pszPC,pszBIC: pChar;
  nIBANLen,nBCLen,nPCLen,nBICLen: integer;
begin
  sDLLPath := PChar(ExtractFilePath(Application.ExeName) + 'IBANKernel.dll');
  hDLL := LoadLibrary(sDLLPath);
  if hDLL = 0 then begin
    ShowMessage('DLL konnte nicht geladen werden.');
    Exit;
  end;

  try
    pszKonto := pChar(edit2.Text);
    pszBCPC := pChar(edit1.Text);
    pszIBAN := nil;pszIBAN := StrAlloc(20);
    nIBANLen := 21;
    pszBC := nil;pszBC := StrAlloc(20);
    nBCLen := 10;
    pszPC := pChar('100');pszPC := StrAlloc(20);
    nPCLen := 10;
    pszBIC := nil;pszBIC := StrAlloc(20);
    nBICLen := 10;
    iRes := 0;
    @FarProc := GetProcAddress(hDLL, 'IT_IBANConvert');
    if Assigned(@FarProc) then
    begin
      iRes := FarProc(pszKonto,pszBCPC,pszIBAN,nIBANLen,pszBC,nBCLen,pszPC,nPCLen,pszBIC,nBICLen);
      edit3.Text := pszPC;
      edit4.Text := pszIBAN;
      edit5.Text := IntToStr(iRes);
    end;
    //ShowMessage('Bingo-->'+pszKonto+'-->'+pszBCPC+'-->'+pszIBAN+'------->'+IntToStr(iRes));

    FreeLibrary(hDLL);
  except
    ShowMessage('Funktion der DLL konnte nicht ausgeführt werden.');
  end;
end;

end.
NB: Ich weiss, StrDispose() fehlt noch:-)

[edit=SirThornberry]Bitte, bitte, bitte, bitte setzte nächstes mal selbst die Delphi-Tags damit der Quelltext lesbar ist - Mfg, SirThornberry[/edit]


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:24 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz