Wątek przeniesiony 2014-02-08 22:42 z Delphi i Pascal przez olesio.

DLL ładowanie dynamiczne i zwrot wartości przez funkcję

0

Dlaczego po wywołaniu poniżej funkcje dostaję AV ? Przy debugowaniu widzą że jest wpisywana wartość do Result ale po wywołaniu FreeLibrary i wyjściu z funkcji dostaję np AV. Stringi nie są dłuższe niż 255 znaków.

function TfContractors.Get_City(text: string): string;
var
  DLL : THandle;
  GetCity : function(code: string): string; stdcall;
begin
  DLL := LoadLibrary('biblioteka.dll'));
  try
    @GetCity := GetProcAddress(DLL, 'GetCity');
    if @GetCity = nil then Exit('');
    Result := GetCity(text);
  finally
    FreeLibrary(DLL);
  end;
end;
1

Podstawy, przenoszę do newbie. Ostrzeżenie przy tworzeniu dllki nie wzieło się z czyjegoś widzimisię. Używaj PCharów zamiast stringów.

0
function TfContractors.Get_City(text: string): string;
var
  DLL : THandle;
  GetCity : function(code: PChar): PChar; stdcall;
begin
  DLL := LoadLibrary('biblioteka.dll');
  try
    @GetCity := GetProcAddress(DLL, 'GetCityPChar');
    if @GetCity = nil then Exit('');
     Result := String(GetCity(pchar(text)));
  finally
    FreeLibrary(DLL);
  end;
end;

procedure Button1.Click;
begin
  showmessage(get_city('00-001'));
end;

A to jest w DLLce

const KodyPocztowe : Array[1..99999] of string = (.....);


Function GetCityPChar(code: PChar): PChar; stdcall;
var
  id: integer;
begin
  try
    id := StrToInt(StringReplace(code, '-', '', [rfReplaceAll]));
    GetMem(Result,Length(KodyPocztowe[id])+1);
    StrCopy(Result,PChar(KodyPocztowe[id]));
  except
    Exit('');
  end;
end;

Kliknięcie buttona powoduje wystąpienie AV. Ale jest jedna rzecz na którą zwróciłem uwagę poniżej kod:

function TfContractors.Get_City(text: string): string;
var
  DLL : THandle;
  GetCity : function(code: PChar): PChar; stdcall;
begin
  DLL := LoadLibrary('biblioteka.dll');
  try
    @GetCity := GetProcAddress(DLL, 'GetCity2');
    if @GetCity = nil then Exit('');
     Result := StrPas(GetCity(pchar(text)));
     Showmessage(Result);
  finally
    FreeLibrary(DLL);
    Showmessage(Result);
  end;
end;

Wykonanie takiej procedury powoduje:

Wyświetlenie pierwszego Showmessage z poprawnymi danymi zwróconymi z Dll.
Natomiast drugi showmessage już się nie wykonuje dając AV.

A teoretycznie powinien bo przecież kopiuję dane do stringa czyli Result? Czy się mylę?

0

Trzeba też wspomnieć o tym, że aby używać typu String należy dodać do listy Uses moduł ShareMem; Choć jak możesz to raczej korzystaj z PChar, tak jak wspomniał @olesio;

"Nie działa" to nie jest wytłumaczenie - napisz co się dzieje dokładnie i czy w ogóle się kompiluje.

0

Jednak się pomyliłem to funkcja FreeLibrary(DLL); powoduje AV

1

Sprawdziłem co jest nie tak i muszę stwierdzić, że... nie wiem :]

Wykonałem taką małą aplikację aby przetestować pobieranie łańcucha z funkcji z biblioteki DLL; Kod całego modułu biblioteki DLL:

library pchrdll;

  function GetPCharFromDLL(AInput: PChar): PChar; stdcall;
  const
    RETURN_VALUE = String('PChar from DLL!');
    RETURN_VALUE_LEN = Length(RETURN_VALUE);
  begin
    if AInput^ = '0' then
      // zwykłe przypisanie
      Result := 'Zero'
    else
    begin
      // skopiowanie z jakiegoś bufora - tutaj ze stałej łańcuchowej
      GetMem(Result, RETURN_VALUE_LEN);
      Move(RETURN_VALUE[1], Result^, RETURN_VALUE_LEN);
    end;
  end;

exports
  GetPCharFromDLL;

begin

end.

No i kod zdarzenia OnClick przycisku ładującego tekst z funkcji z DLL:

procedure TMainForm.btnLoadPCharClick(Sender: TObject);
var
  hLibrary: THandle;
  GetPCharFromDLL: function(AInput: PChar): PChar; stdcall;
  pchrValue: PChar;
begin
  hLibrary := LoadLibrary('DLL\pchrdll.dll');
  try
    @GetPCharFromDLL := GetProcAddress(hLibrary, 'GetPCharFromDLL');

    if @GetPCharFromDLL = nil then
      Application.MessageBox('cannot load function from library.', 'PChar from DLL', MB_ICONSTOP)
    else
    begin
      pchrValue := GetPCharFromDLL('1');
      edtDLLPChar.Text := StrPas(pchrValue);
    end;
  finally
    FreeLibrary(hLibrary);
  end;
end;

Po wciśnięciu przycisku ładowana jest funkcja z biblioteki, po czym zostaje wywołana, a jej rezultat ląduje w zmiennej pchrValue, z której zostaje skopiowany do komponentu edtDLLPChar; Jeśli w parametrze funkcji GetPCharFromDLL poda się łańcuch '0' - funkcja zwróci słowo 'Zero'; W przeciwnym razie zwróci łańcuch 'PChar from DLL!';

@Rafał D - źródło zarówno biblioteki, jak i programu ją obsługującego dołączam do posta.

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