Tekst z bibliotek dll

0

Jest taki problem :

biblioteka.dll:

(...)

procedure info(var p : PChar) ; stdcall;
var s : string ;
begin
  s := 'Program służy do asfasfa f asf f sa ble ble ble...' ;
  s := s + #13#10'asfasfasf   sf ble ble ble...' ;
  p := PChar(s)
end;
(...)

exports
  info name 'info' ;

program:

(...)

var p : PChar ;
    dll : THandle ;
    proc : procedure(pch : pchar) ; stdcall ;
begin
  DLL := LoadLibrary('biblioteka.dll'); 
  try
    @proc := GetProcAddress(DLL, 'About');  
    if @proc = nil then raise Exception.Create('Nie można załadować procedury');
    proc(p);
    application.MessageBox(p,'',mb_ok) ; 
  finally
    FreeLibrary(DLL);
  end;
end;

i na MessageBoxie się wywala. (EAccessViolation)
poprawiłem:

procedure info(var p : PChar) ; stdcall;
var s : string ;
begin
  s := 'Program służy do asfasfa f asf f sa ble ble ble...' ;
  s := s + #13#10'asfasfasf   sf ble ble ble...' ;
  GetMem(p, Length(s)) ;//  <---
  p := PChar(s)
end;

ale do pchara dodaje na końcu znak `

co jest źle?

ps. podczas kończenia pracy programu z wykorzystaniem dll też się wywala (EAccessViolation).

0

Nie wiem jak w Delphi ale w C zawsze alokuje się jeden znak więcej dla znaku NULL na końcu każdego stringa... Może spróbuj GetMem(p, Length(s)+1). A może inna funkcja alokująca...?

0

a nie lepiej użyć funkcji, zwracającej PChar?

0

Dll wczytywalem conajwyzej statycznie wiec nie ma doswiadczenia, ale czy w linijce

@proc := GetProcAddress(DLL, 'About');

nie powinno byc zamiast 'About' 'info'?
Poza tym dla krotkich tekstow mozesz uzyc typu string.
No i jeszcze jedno, proponowalbym przelecenie procedurki wczytujacej krokowo i sprawdzenie czy:

  • LoadLibrary nie daje wyniku 0 (nie wczytano dll)
  • czy @proc = nil (nie znaleziono funkcji)
0
rafal__ napisał(a)

Jest taki problem :
biblioteka.dll:
(...)

procedure info(var p : PChar) ; stdcall;
var s : string ;
begin
  s := 'Program służy do asfasfa f asf f sa ble ble ble...' ;
  s := s + #13#10'asfasfasf   sf ble ble ble...' ;
  p := PChar(s)
end;

(...)

program:

(...)

var p : PChar ;
    dll : THandle ;
    proc : procedure(pch : pchar) ; stdcall ;
begin
//...
    proc(p);
    application.MessageBox(p,'',mb_ok) ; 
//...
end;

i na MessageBoxie się wywala. (EAccessViolation)
poprawiłem:

procedure info(var p : PChar) ; stdcall;
var s : string ;
begin
  s := 'Program służy do asfasfa f asf f sa ble ble ble...' ;
  s := s + #13#10'asfasfasf   sf ble ble ble...' ;
  GetMem(p, Length(s)) ;//  <---
  p := PChar(s)
end;

co jest źle?

Źle jest to, że lokalny string (w procedurze info) jest zwalniany po wyjściu z tej procedury.

To, co zrobiłeś za pierwszym razem, to przypisanie wskaźnika na tekst, który (wskaźnik) po wyjściu z procedury może wskazywać w kosmos.

To, co zrobiłeś za drugim razem, to zarezerwowałeś bufor na tekst, ale też tylko przypisałeś wskaźnik na tekst, który zostanie zniszczony. Na dodatek spowodowałeś wyciek pamięci - bo zarezerwowałeś bufor, ale go utraciłeś (nadpisałeś wskaźnik).

Rozwiązań jest kilka. Przykłady:

  1. Deklarujesz zmienną typu string jako globalną w bibliotece - w ten sposób po wyjściu z procedury nie zostanie ona usunięta i będziesz mógł śmiało na wyjściu przekazać wskaźnik do niej.

  2. Modyfikujesz procedurę info w ten sposób, że przyjmuje ona dwa parametry - wskaźnik na bufor oraz rozmiar bufora. W ten sposób program musi najpierw zarezerwować bufor odpowiedniej wielkości a następnie przekazać procedurze wskaźnik na ten bufor oraz jego rozmiar. Procedura wtedy kopiuje tekst do bufora - nie więcej jednak niż (rozmiar-1) znaków - na końcu trzeba dodać znak #0. Aby skopiować string do bufora możesz użyć funkcji StrPLCopy

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