2010-07-05 8 views
7

Subj. Chciałbym użyć ciągi zamiast PChar dlatego że oszczędza mi wiele casting, ale jeśli po prostu zrobićCzy można bezpiecznie przekazywać parametry ciągów stałych Delphi na granicach menedżera pamięci?

procedure SomeExternalProc(s: string); external SOMEDLL_DLL; 

a następnie wdrożyć go w jakimś innym projekcie z niewspólną menedżera pamięci:

library SeparateDll; 
procedure SomeExternalProc(s: string); 
begin 
    //a bla bla bla 
    //code here code here 
end; 

Mam (formalnie) brak gwarancji Delphi nie decyduje z jakiegokolwiek powodu, aby zmienić ciąg znaków, zmodyfikować swój licznik odwołań, duplikować lub wyróżniać go, czy cokolwiek innego. Na przykład:

var InternalString: string; 

procedure SomeExternalProc(s: string); 
begin 
    InternalString := s; 
end; 

Delphi inkrementuje licznik i kopiuje wskaźnik, to wszystko. Chciałbym, żeby Delphi skopiowała dane. Czy zadeklarowanie parametru jako "const" czyni go bezpiecznym z tego powodu? Jeśli nie, czy jest jakiś sposób na zrobienie tego? Deklarowanie parametr jako PChar nie wydaje się być rozwiązaniem, ponieważ trzeba oddać to za każdym razem:

procedure SomeExternalProc(s: Pchar); forward; 
procedure LocalProc; 
var local_s: string; 
begin 
    SomeExternalProc(local_s); //<<--- incompatible types: 'string' and 'PAnsiChar' 
end; 
+2

Dlaczego nie chcesz używać współużytkowanego MM? Dopóki używasz typu string związanego z Delphi, nie może to być zwykła biblioteka DLL z innych języków. Po co więc unikać dzielenia się MM? –

+0

Typ ciągu jest dość zgodny, może być interpretowany przez inne języki jako PChar. Nie mówię tu o zwrocie ciągów, oczywiście tylko o ciągach znaków. – himself

+0

... czy paczki? –

Odpowiedz

13

To prawdopodobnie pracować tak długo, jak tylko kiedykolwiek użyć DLL z skompilowanego kodu w tej samej wersji Delphi. Wewnętrzny format string był znany z wymiany między wydaniami i nie masz formalnej gwarancji, że nie zmieni się ponownie.

Jeśli chcesz uniknąć konieczności rzucać wszędzie go użyć, spróbuj zawijania funkcji, takich jak to:

procedure SomeExternalProc(s: Pchar); external dllname; 
procedure MyExternalProc(s: string); inline; 
begin 
    SomeExternalProc(PChar(local_s)); 
end; 

Następnie w kodzie, zadzwonić MyExternalProc zamiast SomeExternalProc, i wszyscy są szczęśliwi.

+0

Heh, pokonaj mnie mniej niż minutę :) – gabr

+0

+1 z powodu szczegółów wersjonowania. Dobry. –

+0

Robiłem to od pewnego czasu, ale pisząc te wszystkie kody pośredniczące ... (* edit: sprawdzony wygenerowany kod dla wersji inline, bez żadnych addrefów *) – himself

6

Jeśli zarówno aplikacja, jak i biblioteka DLL są napisane w tej samej wersji Delphi, po prostu użyj menedżera pamięci współdzielonej (więcej szczegółów: here).

Jeśli jedna strona jest napisana w innym języku niż nie ma innego sposobu niż użycie PChar lub WideString (WideStrings są zarządzane przez menedżera pamięci COM).

Lub można napisać funkcję otoki:

procedure MyExternalProc(const s: string); 
begin 
    SomeExternalProc(PChar(s)); 
end; 
-1

polecam użyć alternatywnego menedżera pamięci, takich jak RecyclerMM lub FastMM. Nie wymagają żadnych zewnętrznych udostępnionych dll MM i pozwala bezpiecznie przekazywać ciągi do bibliotek DLL. Jako bonus możesz uzyskać poprawę wydajności w całej aplikacji.

FastMM służy jako domyślny menedżer pamięci w Delphi 2006 i nowszych wersjach. Jest to również dobre narzędzie do wyszukiwania wycieków pamięci.

+0

Dzięki, choć ja to wszystko wiem. Nie używam, a dokładniej nie * polegam * na współdzielonym mm, ponieważ chcę interoperacyjności, a także uważam, że poleganie na współdzielonym mm jest złym stylem - sprawia, że ​​zapominasz o właściwym zarządzaniu pamięcią. – himself

+0

-1. To nie jest prawda. FastMM wymaga współużytkowania menedżera pamięci, aby bezpiecznie przekazywać łańcuchy. Jest wyposażony w jednostkę o nazwie SimpleShareMem, aby to osiągnąć. Po prostu nie można bezpiecznie udostępniać zarządzania strunami, nie powodując, że oba źródła używają tego samego sterty. –

+0

Mason, gdzie powiedziałem coś takiego? Pisałem o zewnętrznej bibliotece DLL (borlandmm.dll). Tak, SimpleShareMem jest potrzebny, jeśli chcesz udostępnić pamięć pomiędzy aplikacjami, które nie używają FastMM a bibliotekami, które używają FastMM. Ale mówiłem o użyciu FastMM zarówno w aplikacji i dll. – Andrew

0

Wystarczy dodać jeden fakt:

Delphi pozwala po prostu przypisać PChar do łańcucha tak na boku DLL nie trzeba żadnych typecast:

function MyDllFunction(_s: PChar): integer; 
var 
    s: string; 
begin 
    s := _s; // implicit conversion to string 

    // now work with s instead of the _s parameter 
end; 

Odnosi się to również do zaliczenia PChar jako parametr funkcji, która oczekuje ciągu znaków (według wartości).

Powiązane problemy