Wykorzystanie bilblioteki C++ w Delphi

0

Witam serdecznie !

Mam problem z użyciem biblioteki napisanej lub przynajmniej kompatybilnej z BC++ w języku Delphi.

przykład kodu napisanego i działającego w BC++


bool __fastcall TForm1::PDI_Load()
{
bool bResult;


   PdiLib = LoadLibrary ("Biblioteka.dll");

   PF_PDI_Init_StandardRbg01 Pdi_Init;
    
   Pdi_Init = (PF_PDI_Init_StandardRbg01) GetProcAddress(PdiLib, "PDI_Init_StandardRbg01");

   Pdi_Init ("Plik_Konfigu","Test01", "1.00", "OFF",lResult);

deklaracja w pliku h


typedef void (*PF_PDI_Init_StandardRbg01) (char *, char *, char *, char *, long &);

pozostałe zmienne są podeklarowane w rożnych innych miejscach i nie maja większego znaczenia

Teraz to samo w Delphi (przynajmniej tak sadze)

unit Unit1;

interface

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

type
  TPF_PDI_Init_StandardRbg01 = procedure (a : PAnsiChar; b : PAnsiChar; c : PAnsiChar; d : PAnsiChar;e :LongInt); cdecl;

  TForm1 = class(TForm)
    procedure FormShow(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    PdiLib: THandle;
  end;

var
  Form1: TForm1;
  Pdi_Init: ^TPF_PDI_Init_StandardRbg01;
  lResult : LongInt;

implementation

{$R *.dfm}


procedure TForm1.FormShow(Sender: TObject);
begin
  PdiLib := LoadLibrary('Pdi.dll');
   if PdiLib >= 32 then { success }
   begin
     Pdi_Init := GetProcAddress(PdiLib, 'PDI_Init_StandardRbg01');
     lResult := lResult;
     if Pdi_Init = nil then
     MessageDlg('Error: Procedure name not exist !', mtError, [mbOk], 0)
   end
   else
     MessageDlg('Error: could not find example DLL', mtError, [mbOk], 0)

//  Pdi_Init('sdrgergrt','ergeggre', '1.00', 'OFF',lResult);                <---- ta komenda nie chce się skompilować !

end;
end.

Po zamianie wskaznika ^TPF_PDI_Init_StandardRbg01 na TPF_PDI_Init_StandardRbg01 czyli zwykłą funkcję inne rzeczy przestają chodzi ale się kompiluje, oczywiście finalnie wywala błąd.

unit Unit1;

interface

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

type
  TPF_PDI_Init_StandardRbg01 = procedure (a : PAnsiChar; b : PAnsiChar; c : PAnsiChar; d : PAnsiChar;e :LongInt); cdecl;

  TForm1 = class(TForm)
    procedure FormShow(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    PdiLib: THandle;
  end;

var
  Form1: TForm1;
  Pdi_Init: TPF_PDI_Init_StandardRbg01;
  lResult : LongInt;

implementation

{$R *.dfm}


procedure TForm1.FormShow(Sender: TObject);
begin
  PdiLib := LoadLibrary('Pdi.dll');
   if PdiLib >= 32 then { success }
   begin
     Pdi_Init := GetProcAddress(PdiLib, 'PDI_Init_StandardRbg01');
     lResult := lResult;
//     if Pdi_Init = nil then                                                                               <---- ta komenda nie chce się skompilować !
//     MessageDlg('Error: Procedure name not exist !', mtError, [mbOk], 0)
   end
   else
     MessageDlg('Error: could not find example DLL', mtError, [mbOk], 0)

  Pdi_Init('sdrgergrt','ergeggre', '1.00', 'OFF',lResult);             

end;
end.

Pytanie wiec są takie:

1 - Czy to się w ogóle da zrobić, dodam ze dll dla BC++ a pisze w BDelphi
2 - w przypadku gdy używam wskaźnika ^TPF_PDI_Init_StandardRbg01 czyli listing Delphi pierwszy, wszystko chodzi podobnie do C++, czyli ładuje bibliotekę, pobiera adres procedury "PDI_Init_StandardRbg01" itd.
Co jest dziwne to: to samo polecenie GetProcAddress daje rożne rezultaty w BC++ i BD ?? czemu ? Czy to ma znaczenie?
3 - główny problem z Drugim listingiem ze wywołuje: Access violation at address 1000C99A in module 'Biblioteka.dll'. Write of address 00000000.
4 - Natomiast pierwszy listing w Delphi nie daje możliwości skompilowania Pdi_Init() bo wywala błąd ;-(((

Myślę że pierwszy listing Delphi jest bliższy temu co zapisano w BC++, niemniej nie wiem co jest nie tak i czy to w ogóle ma szanse powodzenia ?

Pozdrawiam Szymon

0

if Pdi_Init = nil then

Spróbuj

if @Pdi_Init = nil
0

Po dalszej walce biblioteka ładowana statycznie też zagrała niemniej po kliknięciu Button1 wywołuje błąd:

Access violation at address 1000C99A in module 'Pdi.dll'. Write of address 00000000.

Może przyczyną błędu są źle zadeklarowane zmienne ??

Dodam, że String, czy PAnsiChar dają ten sam błąd ;-(

unit Unit1;

interface

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

type
  TPF_PDI_Init_StandardRbg01 = procedure (a : PAnsiChar; b : PAnsiChar; c : PAnsiChar; d : PAnsiChar;e :LongInt); cdecl;

//  ; stdcall ; External FT_DLL_Name name 'FT_SetBaudRate';

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    PdiLib: THandle;
  end;

    procedure PDI_Init_StandardRbg01(a : String; b : String; c : String; d : String;e :LongInt); cdecl; external 'Pdi.dll';

var
  Form1: TForm1;
  Pdi_Init: TPF_PDI_Init_StandardRbg01;
  lResult : LongInt;

implementation

{$R *.dfm}


procedure TForm1.Button1Click(Sender: TObject);
var
  a : LongInt;
begin

  PDI_Init_StandardRbg01('sdrgergrt','ergeggre', '1.00', 'OFF',lResult);
//  Pdi_Init('sdrgergrt','ergeggre', '1.00', 'OFF',lResult);

end;


procedure TForm1.Button2Click(Sender: TObject);
begin
  PdiLib := LoadLibrary('Pdi.dll');
   if PdiLib >= 32 then { success }
   begin
     Pdi_Init := GetProcAddress(PdiLib, 'PDI_Init_StandardRbg01');
     lResult := lResult;
//     if Pdi_Init = nil then
//     MessageDlg('Error: Procedure name not exist !', mtError, [mbOk], 0)
   end
   else
     MessageDlg('Error: could not find example DLL', mtError, [mbOk], 0)

end;

end. 
2

Przekazuj zawsze PChar, to na pewno.
Poza tym ostatni argument to powinien być wskaźnik (PLongint).

0

Witam !

Temat rozwiązano z powodzeniem ;-), kod poniżej

Zgodnie z sugestią furious programming trochę pogrupowałem definicje ;-)

Czego nadal nie rozumiem to:

Deklaracja w C++:

typedef void (*PF_PDI_Init_StandardRbg01) (char *, char *, char *, char *, long &);

gdzie PF_PDI_Init_StandardRbg01 jest wskaźnikiem, potem kolejne 4 wskaźniki a potem long & czyli chyba odwołanie do wartości, a u mnie w definicji funkcji same wskaźniki a dopiero w realnym wywołaniu funkcji jest odwołanie do wartości. Może jak ktoś rozumie te wskaźniki lepiej niż ja się wypowie.

Problem generalnie rozwiązany z pomocą sugestii Patryk27, niemniej nie wiem dlaczego PLongint a nie @LongInit??, W ogóle to jest nieźle zamieszane, a artykuł o wskaźnikach z forum nie wiele mi to rozjaśnił ;-(
Pomysł Azarien-a niestety nie dał się skompilować ;-( nie z uwagi na błąd sam w sobie, ale inne błędy kodu tego nie umożliwiały.

Co jest jeszcze istotne to cdecl na konću definicji bez tego nie chodzi i wywala błędy!

Pozdrawiam i dziękuje wszystkim za pomoc.

Tematu jeszcze nie zamykam bo może da on nowe spojrzenie na wątek:
http://4programmers.net/Forum/Delphi_Pascal/158521-wykorzystanie_w_delphi_biblioteki_dll_uzywanej_w_c
ponieważ mam również przykłady w VC++, i może to jakoś uda się wywołać z Delphi ??

unit Unit1;

interface

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

type
  TPF_PDI_Init_StandardRbg01 = procedure (a,b,c,d : PChar;e : PLongint); cdecl;

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    PdiLib: THandle;
    Pdi_Init: TPF_PDI_Init_StandardRbg01;
  end;

var
  Form1: TForm1;

  lResult : LongInt;
  PDI_CFG_Path : String;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  if @Pdi_Init <> nil then
    Pdi_Init(PChar(PDI_CFG_Path),'ICT', '1.00', 'ON',@lResult);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  PdiLib := LoadLibrary('Pdi.dll');
  if PdiLib >= 32 then
    begin
      Pdi_Init := GetProcAddress(PdiLib, 'PDI_Init_StandardRbg01');
      if @Pdi_Init = nil then
        MessageDlg('Error: Procedure addres not exist !', mtError, [mbOk], 0)
    end
  else
    MessageDlg('Error: Could not find DLL !', mtError, [mbOk], 0)
end;

end.
2

niemniej nie wiem dlaczego PLongint a nie @LongInit

PLongint to typ będący wskaźnikiem na Longint (Type PLongint = ^Longint;), podczas gdy @ to operator służący do pobrania adresu.
Możesz napisać na przykład @nazwa_zmiennej czy @nazwa_funkcji i w wyniku otrzymasz adres (wskaźnik) na daną rzecz, ale co miałoby robić @Longint?

1 użytkowników online, w tym zalogowanych: 0, gości: 1