Search code examples
delphicomdelphi-2006widestring

How to return WideString from COM server?


This Interface at _TLB.pas file

// *********************************************************************//
// Interface: ITMyCOM
// Flags: (256) OleAutomation
// GUID: {D94769D0-F4AF-41E9-9111-4D8BC2F42D69}
// *********************************************************************//
ITMyCOM = interface(IUnknown)
['{D94769D0-F4AF-41E9-9111-4D8BC2F42D69}']
function MyDrawWS(a: Integer; b: Integer): WideString; stdcall;
end;

This looks at OS Windows

[
odl,
uuid(D94769D0-F4AF-41E9-9111-4D8BC2F42D69),
version(1.0),
helpstring("Interface for TMyCOM Object"),
oleautomation
]
interface ITMyCOM : IUnknown {
BSTR _stdcall MyDrawWS(
[in] long a, 
[in] long b);
};

Function in COM server looks as

function TTMyCOM.MyDrawWS(a, b: Integer): WideString;
begin
Result := WideString(IntToStr(a+b));
end;

In COM Client i`m calling this function like

Edit1.Text := String(MyCOM.MyDrawWS(1,1));

and get error First chance exception at $75A9FBAE. Exception class EAccessViolation with message 'Access violation at address 75A409A4 in module 'RPCRT4.dll'. Read of address FFFFFFF8'. Process Project1.exe (2296)

If i want returning Integer, it`s works. How to return WideString?


Solution

  • The correct way to handle this is as follows:

    [ 
    odl, 
    uuid(D94769D0-F4AF-41E9-9111-4D8BC2F42D69), 
    version(1.0), 
    helpstring("Interface for TMyCOM Object"), 
    oleautomation 
    ] 
    interface ITMyCOM : IUnknown { 
    HRESULT _stdcall MyDrawWS( 
    [in] long a,  
    [in] long b,
    [out, retval] BSTR* ret); 
    }; 
    
    ITMyCOM = interface(IUnknown) 
      ['{D94769D0-F4AF-41E9-9111-4D8BC2F42D69}'] 
      function MyDrawWS(a: Integer; b: Integer; out ret: WideString): HResult; stdcall; 
    end; 
    
    function TTMyCOM.MyDrawWS(a, b: Integer; out ret: WideString): HRESULT; 
    begin 
      ret := IntToStr(a+b);
      Result := S_OK;
    end; 
    
    var
      W: WideString;
    begin
      OleCheck(MyCOM.MyDrawWS(1, 1, W));
      Edit1.Text := W;
    end;
    

    Which can then be simplified a little by using Delphi's safecall calling convention in the Delphi declaration (not in the TypeLibrary itself) of the interface:

    ITMyCOM = interface(IUnknown) 
      ['{D94769D0-F4AF-41E9-9111-4D8BC2F42D69}'] 
      function MyDrawWS(a: Integer; b: Integer): WideString; safecall;
    end; 
    
    function TTMyCOM.MyDrawWS(a, b: Integer): WideString;
    begin 
      Result := IntToStr(a+b);
    end; 
    
    Edit1.Text := MyCOM.MyDrawWS(1, 1);