2010-07-05 8 views
7

Subj. Je voudrais utiliser des chaînes au lieu de PChar parce que me épargne coulée beaucoup, mais si je fais justeEst-il prudent de transmettre des paramètres de chaîne const Delphi à travers les limites du gestionnaire de mémoire?

procedure SomeExternalProc(s: string); external SOMEDLL_DLL; 

puis le mettre en œuvre dans un autre projet avec le gestionnaire de mémoire non partagée:

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

Je n'ai (formellement) aucune garantie Delphi ne décide pas, pour quelque raison que ce soit, de modifier la chaîne, de modifier son compteur de référence, de la dupliquer ou de la rendre unique, ou quoi que ce soit d'autre. Par exemple

var InternalString: string; 

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

Delphi incrémente refcounter et copie un pointeur, c'est tout. J'aimerais que Delphi copie les données. Est-ce que déclarer le paramètre "const" le rend sûr pour cette raison? Si non, y a-t-il un moyen de le faire? paramètre Déclarant que PChar ne semble pas être une solution parce que vous devez jeter chaque fois:

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

Tant que vous utilisez le type de chaîne lié à Delphi, il ne peut s'agir d'une DLL générique utilisable dans d'autres langues. Pourquoi donc éviter de partager le MM? –

+0

Le type de chaîne est très compatible, il peut être interprété par d'autres langages comme PChar. Je ne parle pas de renvoyer des chaînes, bien sûr, juste des paramètres de chaîne. – himself

+0

... ou des paquets? –

Répondre

13

Ce serait probablement travailler, aussi longtemps que vous utilisez ne jamais votre DLL à partir du code compilé dans la même version Delphes. Le format interne de chaîne est connu pour changer entre les versions, et vous n'avez aucune garantie formelle qu'il ne changera pas à nouveau.

Si vous voulez éviter d'avoir à jeter partout où vous l'utilisez, essayez d'emballage la fonction, comme ceci:

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

Ensuite, dans votre code, vous appelez MyExternalProc au lieu de SomeExternalProc, et tout le monde est heureux.

+0

Heh, me battre par moins d'une minute :) – gabr

+0

+1 en raison du détail de la version. Bien. –

+0

Je fais cela depuis un certain temps, mais en écrivant tous ces stubs ... (* edit: vérifié le code généré pour la version inline, pas addrefs après tout *) – himself

6

Si l'application et la DLL sont écrites dans la même version de Delphi, il suffit d'utiliser le gestionnaire de mémoire partagée (plus de détails here).

Si un côté est écrit dans une langue différente, il n'y a pas d'autre moyen que d'utiliser PChar ou WideString (WideString est géré par le gestionnaire de mémoire COM).

Ou vous pouvez écrire une fonction wrapper:

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

Je recommande d'utiliser un gestionnaire de mémoire de remplacement comme RecyclerMM ou FastMM. Ils ne nécessitent pas de dll MM externe et vous permet de transmettre des chaînes aux dll en toute sécurité. En prime, vous pouvez obtenir une belle amélioration des performances dans toute l'application. FastMM est utilisé comme gestionnaire de mémoire par défaut dans Delphi 2006 et au-delà.

C'est aussi un bon outil pour rechercher les fuites de mémoire.

+0

Merci, même si je sais tout cela. Je n'utilise pas, ou plus précisément, je ne m'appuie pas sur des mm partagés car je veux de l'interopérabilité, et je pense aussi que s'appuyer sur des mm partagés est un mauvais style - cela fait oublier la bonne gestion de la mémoire. – himself

+0

-1. Ce n'est pas vrai. FastMM vous oblige à partager le gestionnaire de mémoire afin de transmettre les chaînes en toute sécurité. Il vient avec une unité appelée SimpleShareMem pour accomplir ceci. Il n'y a simplement aucun moyen de partager la gestion des chaînes en toute sécurité sans que les deux sources utilisent le même tas. –

+0

Mason, où ai-je dit quelque chose comme ça? J'écrivais à propos de la DLL externe (borlandmm.dll). Oui, SimpleShareMem est nécessaire si vous souhaitez partager la mémoire entre une application qui n'utilise pas FastMM et les bibliothèques utilisant FastMM. Mais je parlais d'utiliser FastMM dans les deux applications et dll. – Andrew

0

Juste pour ajouter un seul fait:

Delphi vous permet d'affecter simplement PChar à une chaîne pour le côté DLL vous n'avez pas besoin 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; 

Cela vaut aussi pour le passage PChar en tant que paramètre d'une fonction qui attend une chaîne (par valeur). Pourquoi ne voulez-vous pas utiliser un MM partagé?