Wykorzystanie bilblioteki C++ w Delphi

Wykorzystanie bilblioteki C++ w Delphi
SE
  • Rejestracja:prawie 17 lat
  • Ostatnio:ponad 6 lat
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++

Kopiuj

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

Kopiuj

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)

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

Kopiuj
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

Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 3 godziny
0

if Pdi_Init = nil then

Spróbuj

Kopiuj
if @Pdi_Init = nil
SE
  • Rejestracja:prawie 17 lat
  • Ostatnio:ponad 6 lat
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 ;-(

Kopiuj
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. 
flowCRANE
Grupuj sobie parametry tych samych typów, bo strasznie długie deklaracje Ci wychodzą;
Patryk27
Moderator
  • Rejestracja:ponad 17 lat
  • Ostatnio:ponad rok
  • Lokalizacja:Wrocław
  • Postów:13042
2

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


edytowany 1x, ostatnio: Patryk27
SE
  • Rejestracja:prawie 17 lat
  • Ostatnio:ponad 6 lat
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++:

Kopiuj
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 ??

Kopiuj
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.
Patryk27
Moderator
  • Rejestracja:ponad 17 lat
  • Ostatnio:ponad rok
  • Lokalizacja:Wrocław
  • Postów:13042
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?


edytowany 1x, ostatnio: Patryk27
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)