La chaîne vide devient nulle lorsqu’elle est transmise de Delphi à C # en tant qu’argument de fonction

J’ai un exe natif de Delphi qui appelle en C # dll via COM interop. Voici le cas le plus simple qui démontre ce problème:

Delphes:

IClass1 = interface(IDispatch) ['{B29BAF13-E9E4-33D7-9C92-FE28416C662D}'] function Test(const aStr: WideSsortingng): WideSsortingng; safecall; end; var obj: IClass1; s: ssortingng; begin obj := CoClass1.Create as IClass1; s := obj.Test(''); // Returns '[null]' end; 

C #:

 [ComVisible(true)] public interface IClass1 { ssortingng Test(ssortingng aStr); } [ComVisible(true)] public class Class1 : IClass1 { public ssortingng Test(ssortingng aStr) { if (aStr == null) return "[null]"; if (aStr == "") return "[empty]"; return "Not empty: " + aStr; } } 

Lorsque j’appelle la méthode Test avec une chaîne vide dans Delphi, la partie C # reçoit la valeur null en tant que valeur de paramètre. Pourquoi donc? Ne devrait-il pas être une chaîne vide également?

Dans Delphi, les valeurs AnsiSsortingng , UnicodeSsortingng et WideSsortingng sont représentées par un pointeur nil lorsqu’elles sont vides. COM utilise BSTR pour les chaînes. Delphi enveloppe BSTR avec WideSsortingng . Donc, il n’y a aucun moyen de passer une chaîne “vide” non-nil à une méthode COM qui prend un WideSsortingng tant que paramètre, ce sera nil .

Dans Delphi, une chaîne nulle (c’est-à-dire nil ) et une chaîne vide sont traitées comme équivalentes. En tant que tel, passer '' pour un paramètre ssortingng (ou WideSsortingng ) passe nil interne –

 program Project1; {$APPTYPE CONSOLE} {$R *.res} procedure Foo(const S: WideSsortingng); begin WriteLn(Pointer(S) = nil); end; begin Foo('Something'); //FALSE Foo(''); //TRUE ReadLn; end. 

L’équation des chaînes nulles et vides a en fait été copiée à partir de COM … donc une bibliothèque COM n’est pas vraiment l’endroit pour insister sur une distinction de style C # entre les deux.

Pourquoi le passage à un paramètre WideSsortingng a- WideSsortingng résultat que l’autre côté reçoit la valeur null ? BSTR comment Delphi représente un COM BSTR vide. Si vous devez réellement transmettre une chaîne vide, vous devez modifier IClass1 dans le code Delphi pour transmettre TBStr au lieu de WideSsortingng et utiliser SysAllocSsortingng ou SysAllocSsortingngLen pour créer un TBStr vide.

Modifiez la déclaration de la fonction dans le code Delphi en:

 function Test(const aStr: TBStr): WideSsortingng; safecall; 

Et transmettez SysAllocSsortingngLen('', 0) lorsque vous devez transmettre une chaîne vide.

Voici une démonstration complète:

C #

 using System; using System.Runtime.InteropServices; namespace ConsoleApplication1 { [ComVisible(true)] public interface IClass1 { ssortingng Test(ssortingng aStr); } [ComVisible(true)] public class Class1 : IClass1 { public ssortingng Test(ssortingng aStr) { if (aStr == null) return "[null]"; if (aStr == "") return "[empty]"; return "Not empty: " + aStr; } } class Program { [DllImport(@"Project1.dll")] static extern void Foo(IClass1 intf); static void Main(ssortingng[] args) { IClass1 intf = new Class1(); Foo(intf); } } } 

Delphes

 uses Ole2; type IClass1 = interface(System.IDispatch) function Test(const aStr: TBStr): WideSsortingng; safecall; end; var EmptyBStr: TBStr; procedure Foo(const intf: IClass1); stdcall; begin Writeln(intf.Test(nil)); Writeln(intf.Test(EmptyBStr)); Writeln(intf.Test(SysAllocSsortingng('foo'))); end; exports Foo; begin EmptyBStr := SysAllocSsortingngLen('', 0); end. 

Sortie

 [nul]
 [vide]
 Pas vide: foo