Delphi (UnicodeString):

function ShowDelphiMsg(inputStr : UnicodeString) : UnicodeString; stdcall; var a : UnicodeString; begin ShowMessage(inputStr); a := 'Тест!'; result := a; end; 

C #

 [DllImport("Native.dll", SetLastError = true, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)] [return: MarshalAs(UnmanagedType.LPWStr)] internal static extern string ShowDelphiMsg([MarshalAs(UnmanagedType.LPWStr)] string inputStr); 

This option perfectly transmits a string from C # to Delphi, Delphi prints the string. But the main problem is an error when returning a string from Delphi.

Vporos: Which UnmanagedType matches a UnicodeString from Delphi?

ps architecture for both x64 applications.


Delphi (WideString):

 function ShowDelphiMsg(inputStr : WideString) : WideString; stdcall; var a : WideString; begin ShowMessage(inputStr); a := 'Тест!'; result := a; end; 

It also causes an error when returning a value.


Simplified function

C #:

  [DllImport("Native.dll", SetLastError = true, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)] [return: MarshalAs(UnmanagedType.BStr)] internal static extern string ShowDelphiMsg(); 

Delphi:

 function ShowDelphiMsg() : WideString; stdcall; var a : WideString; begin a := 'Тест!'; result := a; end; 

The same mistake.

  • And what does the error message say? - zed
  • AcessViolationException, tobish nothing concrete. - Alexis
  • Not strong in C #, so maybe I’ll say nonsense, but: string ShowDelphiMsg(); - Does it overlap the previous UnmanagedType.BStr ? - kami
  • @kami, no, everything is fine here. - Alexis
  • Try in Delphi to execute UnuqueString (Result) with the last line. - kami

3 answers 3

Judging by the UnmanagedType.LPWStr code, UnmanagedType.LPWStr used PWideChar , which is a pointer to WideString . From function it is necessary to WideString .

UPD:

It turns out that due to the features of C # (?), You need to use this method:

Delphi:

 function SomeFunction2(out OutVar: Widestring): BOOL; stdcall; begin OutVar := 'Hello'; Result := True; end; 

C #

 [DllImport(@"Test.dll")] [return: MarshalAs(UnmanagedType.Bool)] static extern bool SomeFunction2([MarshalAs(UnmanagedType.BStr)] out string res); 

those. it is WideString return a WideString through the result, but to make an out parameter (but not a var see Alex's answer) is easy.

Goaded: https://stackoverflow.com/questions/9331026/why-can-delphi-dlls-use-widestring-without-using-sharemem

  • Yes, but in my opinion it is much more convenient to work with UnicodeString , so I would like to know which type exactly UnicodeString corresponds to. - Alexis
  • 2
    You cannot work with the UnicodeString type outside Delphi - it is an internal type, with reference counting. - zed
  • Well thank you. If there are no other answers, I will accept your answer. - Alexis
  • I recommend help on string types: String Types (Delphi) - zed
  • Hmm, checked, with WideString - the same error. Signature Delphi added to the question. - Alexis

The problem is that Delphi and Visual Studio disagree on how to interpret the stdcall calling stdcall .

Any function that returns a complex (including autorun) type:

 function SomeFunction: WideString; 

Delphi treats like:

 procedure SomeFunction(var AResult: WideString); 

At the same time, Visual Studio treats it either as:

 procedure SomeFunction(out AResult: WideString); 

Or as:

 function SomeFunction: Pointer; // действительно возврат через EAX/RAX 

(depending on which type is used in Result - Pointer size or more)

As a result, because of these differences, we either get Access Violation, or a memory leak.

Options for the right solutions:

  1. (The most correct) Use safecall instead of stdcall
  2. (Valid answer is zed) Explicitly describe the output parameter in Delphi
  3. (Hack - Alexis answer) Bring Result to a simple type and manually control it

If interested, you can read .

    In the process of studying I found another option that is more acceptable in my opinion:

    Delphi:

     uses ActiveX; function GetWideString(str: WideString): TBStr; stdcall; begin result := SysAllocString(POleStr(str)); end; 

    C #

     [DllImport("Native.dll", SetLastError = true, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)] [return: MarshalAs(UnmanagedType.BStr)] internal static extern string GetWideString([MarshalAs(UnmanagedType.BStr)]string inputString);