Tablice dyamiczne w DLL

0

Cześć, od razu mówię, że nie chcę używać żadnych Sharememów i innych takich i DLLki mogą być pisane w różnych językach.

Mam taką funkcję:

function foo(var code: integer; var template: PChar): HRESULT; safecall;

Tą funkcję wywołuję z DLL. Jak widać, ma ona zwrócić zmienną code typu integer, a także zmienną template typu PChar. I nie byłoby pytania, gdyby PChar nie był "łańcuchem kończącym się znakiem #0".

Co to dla mnie oznacza? Ano, w tym miejscu dllka musi przekazać pewne dane binarne i np. może to być: 0xFF00AA

W przypadku użycia PChar faktycznie w aplikacji dostanę: 0xFF

Teraz pytanie moje brzmi, jakiego tutaj mogę użyć typu zamiast PChar? Utrudnienie jest takie, że nie znam maksymalnej długości tych danych. Może to być 1 bajt, może 100, a może i 2 kB. I teoretycznie może więcej.

Od początku myślałem o użyciu array of byte co by było najlepszym rozwiązaniem, jednak tutaj musiałbym znać maksymalny jej rozmiar(jak wiadomo, w dll nie przekazujemy tablic dynamicznych). Jakoś ją ograniczyć, a generalnie jedynym tutaj ograniczeniem ma być ilość wolnej pamięci.

Cały czas kombinuję coś ze wskaźnikami, ale tak naprawdę poruszam się na chybił trafił. Ktoś ma może jakiś pomysł?

0

czy template jest alokowany przez DLL-kę, czy DLL-ka tylko wypełnia zadany bufor?
gdzie ma być pamięć zwalniana?

0
Azarien napisał(a)

czy template jest alokowany przez DLL-kę, czy DLL-ka tylko wypełnia zadany bufor?
gdzie ma być pamięć zwalniana?

Template niestety jest alokowany przez DLLkę.
Zrobiłem taki myk:

  1. Przekazuję wskaźnik na Byte:
function foo(var pSize: integer; var data: PByte): HRESULT; safecall;
  1. Następnie w dll alokuję pamięć i wypełniam danymi:
var
  s: string;
begin
  s:='Test';
  pSize:=length(s);

  GetMem(Data, pSize);
  copyMemory(Data, @s, pSize);
  result:=S_OK;
end;

a w aplikacji głównej:

var
  s: string;
begin
  setLength(s, pSize);
  copyMemory(@s, data, pSize);
end;

I to wydaje się działać. Pozostaje jedynie kwestia zwolnienia pamięci. Muszę chyba napisać procedurę:

procedure DLLFreeMem(P: Pointer);
begin
  FreeMem(P);
end;

i wywołać ją z aplikacji w DLL. W taki sposób to DLLka zwolni zajętą przez siebie pamięć i powinno być git. Jeśli ktoś widzi jakiś błąd w rozumowaniu lub rozwiązaniu, proszę o cynk ;)

[DOPISANE]
Niestety w rozumowaniu jest błąd. Podczas zwalniania biblioteki dostaję AV, nawet gdy używam DLLFreeMem z typem w parametrze jako PByte. Tak więc problem ze zwolnieniem pamięci zostaje.

0

Sprawdź może coś zamazujesz niepoprawnym kopiowaniem, poprawne kopiowanie:
copyMemory(@s[1], data, pSize);

0
_13th_Dragon napisał(a)

Sprawdź może coś zamazujesz niepoprawnym kopiowaniem, poprawne kopiowanie:
copyMemory(@s[1], data, pSize);

Teraz faktycznie błędu nie ma, ale za to zmienna S ma wartość adresu, w którym są potrzebne dane, a nie te dane.

[DOPISANE]
OK, udało mi się zrobić to w taki sposób:

var
  i, pSize: integer;
  p: Pointer;
  s: string;
  data: PByte;
begin
  //pobieram dane DATA i pSIZE wywołując funkcję z DLL
  //...
//a teraz zaczyna się zabawa
    setLength(s, pSize);
    copyMemory(@i, data, 4);
    p:=Ptr(i);
    copyMemory(@s[1], p, pSize);
    showMessage(s);
end;

To działa tak, jak chcę, tylko, że mam wrażenie, że robię to trochę na około. Jeślil ktoś ma lepszy pomysł, to poproszę :)

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