0

I've tried several variations of the code below with returning HRESULT (which is the preferable COM standard) or returning BSTR. I've tried other datatypes as well. I usually get a "missing implementation of interface method" compile error, but when I used a return type of WideString, there was a runtime AccessViolationException on the result:=RetVal; instruction.

I'm using C# on the client side:

var msg = delphi.GetMessage("My Message");

Here is mi RIDL:

HRESULT _stdcall GetMessage([in] BSTR msg, [out, retval] BSTR* RetVal);

Here is my implementation:

function TDelphiCom.GetMessage(msg:WideString; out RetVal:WideString):HRESULT;
var
  tempString: string;
begin
  tempString:=msg;
  RetVal:=WideString(tempString);
end;

What is the correct way to pass strings in/out of a Delphi COM server?

Kevin S. Miller
  • 913
  • 1
  • 9
  • 21

1 Answers1

0

Your RIDL declaration is correct.

You did not show the C# declaration of the method, so we can't see if you are marshaling parameters correctly or not.

On the Delphi side, your implementation is missing the stdcall calling convention (to match the RIDL declaration), as well as exception handling so you can return a proper HRESULT on failures:

function TDelphiCom.GetMessage(msg: WideString; out RetVal: WideString): HRESULT; stdcall;
var
  tempString: string;
begin
  try
    tempString := string(msg);
    RetVal := WideString(tempString);
    Result := S_OK;
  except
    // do something...
    Result := DISP_E_EXCEPTION;
  end;
end;

Though, you really should use the safecall calling convention instead and let it deal with the error handling for you:

function TDelphiCom.GetMessage(msg: WideString): WideString; safecall;
var
  tempString: string;
begin
  tempString := string(msg);
  Result := WideString(tempString);
end;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • The C# client code is near the top of the question - just one line. – Kevin S. Miller Feb 01 '19 at 21:39
  • @KevinS.Miller on the C# side, I was referring to the **declaration** of the method, not the **invokation** of it. We can't see how you declared it to know whether it is marshaling parameters correctly or not. – Remy Lebeau Feb 01 '19 at 21:59
  • We don't know whether or not the stdcall was missing because the declaration wasn't shown, only the implementation. Always a problem when user presents partial code. – David Heffernan Feb 02 '19 at 08:49
  • Perhaps I don't understand the question about the C# declaration. The Delphi code produces a COM server, and the C# instantiates the COM server object and invokes GetMessage method (declared in the RIDL, and implemented in Delphi) of that server. Both the RIDL and the Delphi specify stdcall. – Kevin S. Miller Feb 02 '19 at 22:14
  • You are correct that the Delphi code above does not explicitly show the stdcall because it is declared in the function prototype and that is the implementation. I regret the omission. – Kevin S. Miller Feb 02 '19 at 22:25
  • I'm changing the accepted answer to this. At first, it would not compile, but I found that I had to enable SafeCall at Tools > Options > Language > Delphi Options > Type Library > Tools > Options > Language > Delphi Options > Type Library. – Kevin S. Miller Feb 04 '19 at 16:41