Gubienie wartości prarametru przesyłanego z DLL

0

Witam.
Dalej obrabiam DLLki i natknąłem się na problem, którego nie mogę rozwiązać, a mianowicie przesyłem sobie pointer string'a i w pewnym momencie gubi się gdzieś z niewyjaśnionych przyczyn (Ustaliłem że błędnie dostaje go procedura callback'owa cbProc).
I nie mam pomysłu co może być tego przyczyną, po wywołaniu testu sprawdzającego czy dll go zgubiła gdzieś, wypadł negatywnie.

DLL

library dll;


uses SysUtils;
{$R *.res}

var
 S:^String;

procedure Init(P:Pointer);stdcall;
begin
 S:=P;
 //WriteLn('Init proc get str ',Length(S));
 WriteLn('Pointer [0] ',Integer(@S));
end;

procedure TestCallBack(clientFunc: Pointer);stdcall;
var
 cbP:procedure(P:Pointer);
begin
  cbP:=clientFunc;
  cbP(S);
  WriteLn('Pointer [1] ',Integer(@S));
  //WriteLn('Get Callback Proc and str len', Length(S^));
end;

//Pointer is not used :)
procedure retest(P:Pointer);
begin
  WriteLn('Pointer [3] ',Integer(@S));
end;

exports TestCallBack,Init,retest;

begin
end.

App

program App;

{$APPTYPE CONSOLE}

uses SysUtils,Windows;

var
 DLLHandle:THandle;
 dllProc:procedure(myCBFunction: Pointer);stdcall;
 S:String;
 I:Integer;

procedure cbProc(P:Pointer);
begin
 WriteLn('Pointer [2] ',Integer(P));
 //WriteLn('cbProc Return pointer: ',Integer(P),' Length ',Length(String(P)));
end;

begin
 DLLHandle:=LoadLibrary(PChar('dll.dll'));
 try

   DLLHandle:=LoadLibrary(PChar('dll.dll'));
   if DLLHandle = 0 then begin
    WriteLn('DLL not found');
    Exit;
   end;

   @dllProc := GetProcAddress(DLLHandle,PChar('Init'));
   if @dllProc = nil then begin
    WriteLn('Function not found');
    Exit;
   end;

   for I := 0 to 1024 do S:='S'+S;

   dllProc(@S);
   //WriteLn('after init str len ',Length(S));

   ////////////////////////////////////////////////////////

   @dllProc := GetProcAddress(DLLHandle,PChar('TestCallBack'));
   if @dllProc = nil then begin
    WriteLn('Function not found');
    Exit;
   end;

   dllProc(@cbProc);

   WriteLn('After init CallBack');

   @dllProc := GetProcAddress(DLLHandle,PChar('retest'));
   if @dllProc = nil then begin
    WriteLn('Function not found');
    Exit;
   end;
   dllProc(@S);

   WriteLn(Length(S));

  WriteLn('end');
  ReadLn;
  except
    on E:Exception do begin
      Writeln(E.Classname, ': ', E.Message);
      ReadLn;
    end;
  end;
  FreeLibrary(DLLHandle);
end. 
1

Jak tworzysz nową DLL-kę, to w komentarzu masz, że jeśli chcesz przesyłać do/z DLL-ki stringi (typów: string/ansistring/unicodestring) to musisz dołączyć jakiś-tam moduł.
Nie mówiąc już o tym, że pointer na string w zmiennej typu Pointer to już w ogóle WTF.

Przesyłaj PChar.

0

Co do teko komenta to wiem, ale nie chce używać zew DLL, co do PCHar to nie może być w nim #0 a w moim przypadku może on się pojawić no i problem ograniczonej wielkości (260);

1

Jeśli chcesz koniecznie korzystać z typów String, AnsiString itd. to musisz dodać moduł ShareMem do listy, ponadto musi on być na pierwszym miejscu sekcji uses; Więcej możesz wyczytać w komentarzu;

Co do przekazywania PChar - skoro łańcuch może zawierać znaki o kodzie 0 to prócz samego wskaźnika na początek łańcucha przekaż także jego długość;

Przykład:

procedure WritePAnsiChar(APointer: PAnsiChar; ACount: Cardinal);
var
  strArg: AnsiString;
begin
  SetLength(strArg, ACount);
  Move(APointer^, strArg[1], ACount);
  Write('''', strArg, '''');
end;

var
  strLine: AnsiString;
  pchrLine: PAnsiChar;
begin
  strLine := 'object'#0'pascal';
  pchrLine := @strLine[1];

  WriteLn('''', AnsiString(pchrLine), '''');
  WritePAnsiChar(pchrLine, Length(strLine));

  ReadLn;
end.

Wyjście:

'object'
'object pascal'
1

Myślę że stringi (jakiekolwiek) to zły pomysł jeżeli może występować znak #0. To oznacza że masz dane binarne, a nie tekst. Przesyłaj tablice - dynamiczne, zwykłe, wskaźnik, wszystko jedno, ale nie string.

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