2010-07-05 13 views
7

Subj. Ich möchte Strings statt PChar verwenden, weil das mir viel Gießen erspart, aber wenn ich nurIst es sicher, Delphi Const String Parameter über Speicher Manager Grenzen zu übergeben?

procedure SomeExternalProc(s: string); external SOMEDLL_DLL; 

tun und setzen es dann in einem anderen Projekt mit nicht-Shared-Memory-Manager:

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

Ich habe (formal) keine Garantie Delphi entschließt sich aus irgendeinem Grund nicht, die Zeichenkette zu ändern, ihren Referenzzähler zu ändern, sie zu duplizieren oder zu individualisieren, oder was auch immer. Zum Beispiel

Delphi inkrementiert refcounter und kopiert einen Zeiger, das ist es. Ich möchte, dass Delphi die Daten kopiert. Erklärt der Parameter "const" aus diesem Grund? Wenn nicht, gibt es einen Weg, es zu tun? Deklarieren Parameter als PChar scheint keine Lösung zu sein, weil Sie es jedes Mal werfen müssen:

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

Warum möchten Sie kein freigegebenes MM verwenden? Solange Sie den an Delphi gebundenen Zeichenfolgetyp verwenden, kann es keine generische DLL sein, die aus anderen Sprachen verwendet werden kann. Warum vermeiden Sie das Teilen der MM? –

+0

String-Typ ist durchaus kompatibel, es kann von anderen Sprachen als PChar interpretiert werden. Ich spreche natürlich nicht von Saitenrückläufen, sondern nur von Saitenparametern. – himself

+0

... oder Pakete? –

Antwort

13

die wahrscheinlich funktionieren würde, solange man immer nur von Code verwenden, um Ihre DLL in der gleichen Version kompiliert von Delphi. Das interne Format string wurde bekanntermaßen zwischen den Versionen geändert, und Sie haben keine formelle Garantie, dass es sich nicht wieder ändert.

Wenn Sie zu vermeiden, wollen überall Sie es verwenden zu werfen, versuchen Sie die Funktion Einwickeln, wie folgt aus:

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

Dann in Ihrem Code, rufen Sie MyExternalProc statt SomeExternalProc, und jeder ist glücklich.

+0

Heh, schlag mich um weniger als eine Minute :) – gabr

+0

+1 wegen der Versionsdetails. Gut. –

+0

Ich mache das schon seit einiger Zeit, schreibe aber alle diese Stubs ... (* edit: check generierten Code für Inline-Version, keine Adressen mehr *) – himself

6

Wenn sowohl die App als auch die DLL in derselben Delphi-Version geschrieben sind, verwenden Sie einfach den Shared Memory Manager (mehr Details here).

Wenn eine Seite in einer anderen Sprache geschrieben wird, gibt es keine andere Möglichkeit, als PChar oder WideString zu verwenden (WideStrings werden vom COM-Speichermanager verwaltet).

Oder Sie können eine Wrapper-Funktion schreiben:

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

Ich empfehle zu verwenden, um einen alternativen Speichermanager wie RecyclerMM oder FastMM. Sie benötigen keine externen freigegebenen MM-DLLs und können Strings sicher an die DLLs übergeben. Als Bonus erhalten Sie möglicherweise eine schöne Leistungsverbesserung in der gesamten Anwendung.

FastMM wird in Delphi 2006 und höher als Standardspeichermanager verwendet. Es ist auch ein gutes Werkzeug, um die Speicherlecks zu suchen.

+0

Danke, obwohl ich das alles weiß. Ich benutze nicht, oder genauer gesagt, * vertraue * nicht auf gemeinsame mm, weil ich Interoperabilität will, und ich denke auch, dass man sich auf gemeinsame mm verlassen kann, ist ein schlechter Stil - lässt Sie die richtige Speicherverwaltung vergessen. – himself

+0

-1. Das ist nicht wahr. FastMM erfordert, dass Sie den Speichermanager freigeben, um Strings sicher herumzugeben. Es kommt mit einer Einheit namens SimpleShareMem, um dies zu erreichen. Es gibt einfach keine Möglichkeit, die Zeichenfolgenverwaltung sicher zu teilen, ohne dass beide Quellen denselben Heap verwenden. –

+0

Mason, wo habe ich sowas gesagt? Ich habe über die externe DLL (borlandmm.dll) geschrieben. Ja, SimpleShareMem wird benötigt, wenn Sie den Speicher zwischen Anwendungen teilen möchten, die FastMM nicht verwenden, und Bibliotheken, die FastMM verwenden. Aber ich sprach über die Verwendung von FastMM in der Anwendung und DLL. – Andrew

0

Nur eine einzige Tatsache hinzuzufügen:

Delphi ermöglicht es Ihnen einfach PChar in einem String zuweisen, so auf der DLL-Seite Sie eine Typumwandlung nicht brauchen:

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; 

Dies gilt auch für die Weitergabe PChar als Parameter für eine Funktion, die eine (nach Wert) Zeichenfolge erwartet.

Verwandte Themen