Why can a WideString not be used as a function return value for interop?

后端 未结 2 474
南方客
南方客 2020-11-22 12:23

I have, on more than one occasion, advised people to use a return value of type WideString for interop purposes.

  • Accessing Delphi DLL throwing oc
相关标签:
2条回答
  • 2020-11-22 12:41

    In C#/C++ you will need to define the Result as out Parameter, in order to maintain binary code compatibility of stdcall calling conventions:

    Returning Strings and Interface References From DLL Functions

    In the stdcall calling convention, the function’s result is passed via the CPU’s EAX register. However, Visual C++ and Delphi generate different binary code for these routines.

    Delphi code stays the same:

    function TestWideString: WideString; stdcall;
    begin
      Result := 'TestWideString';
    end;
    

    C# code:

    // declaration
    [DllImport(@"Test.dll")]        
    static extern void  TestWideString([MarshalAs(UnmanagedType.BStr)] out string Result);
    ...
    string s;
    TestWideString(out s); 
    MessageBox.Show(s);
    
    0 讨论(0)
  • 2020-11-22 12:54

    In regular Delphi functions, the function return is actually a parameter passed by reference, even though syntactically it looks and feels like an 'out' parameter. You can test this out like so (this may be version dependent):

    function DoNothing: IInterface;
    begin
      if Assigned(Result) then
        ShowMessage('result assigned before invocation')
      else
        ShowMessage('result NOT assigned before invocation');
    end;
    
    procedure TestParameterPassingMechanismOfFunctions;
    var
      X: IInterface;
    begin
      X := TInterfaceObject.Create;
      X := DoNothing; 
    end;
    

    To demonstrate call TestParameterPassingMechanismOfFunctions()

    Your code is failing because of a mismatch between Delphi and C++'s understanding of the calling convention in relation to the passing mechanism for function results. In C++ a function return acts like the syntax suggests: an out parameter. But for Delphi it is a var parameter.

    To fix, try this:

    function TestWideString: WideString; stdcall;
    begin
      Pointer(Result) := nil;
      Result := 'TestWideString';
    end;
    
    0 讨论(0)
提交回复
热议问题