3

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?

unreturned
  • 53
  • 2
  • 5

5 Answers5

2

Let Delphi perform the conversions automatically. Don't cast. You can cast a (ansi)string to a PChar, because their memory layout are compatible, but you can't cast a string to a widestring or viceversa. Delphi will perfrom conversion when you assign one to the other.

In Delphi < 2009

var
S: string;
W: WideString;
...
S := W;  // Conversion, WideString -> AnsiString;
W := S; // Conversion, AnsiString -> WideString
  • Applied to your code, a plain `Result:=IntToStr(a+b);` will do – Stijn Sanders Nov 15 '10 at 14:54
  • Another solution is to use MultiByteToWideChar() and WideCharToMultiByte() directly using the correct codepages, but unless their flexibility is needed is better to let Delphi call the appropriate conversion functions. –  Nov 15 '10 at 16:39
2

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);
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
1

Don't use return values other than HRESULT. Instead put your return value into parameter list as output parameter.

function MyDrawWS(a: Integer; b: Integer; out str : WideString): HRESULT; stdcall;

In this way, you are also forced to use COM memory manager IMalloc (CoTaskMemAlloc for pur COM, SysAllocString for Automation).

ChristianWimmer
  • 1,039
  • 8
  • 16
  • Not true. When you declare an **out reval** parameter in the type library editor, Delphi will generate a function, using the **safecall** convention. It's the safecall that takes care of the HRESULT value and generate an exception if not S_OK, while letting you to use the call as a plain function. –  Nov 15 '10 at 13:18
  • 1
    But this is not about safecall, so we should follow COM rules here. – ChristianWimmer Nov 16 '10 at 11:04
  • 1
    `safecall` is Delphi's wrapper around COM functions. If a COM function is declared in the TypeLibrary as returning an HRESULT return value and having a 'retval' parameter, `safecall` can safely be used with it. The `safecall` function return value needs to be the same data type as the 'retval' parameter data type, and the 'retval' parameter itself should NOT be declared in the `safecall` function. When called in the app's code, `safecall` will allocate a temp variable, call the COM function with the variable in the 'retval' parameter, do HRESULT checking, and return the variable's value. – Remy Lebeau Nov 18 '10 at 03:01
  • 1
    Okay, but safecall is not used here hence the HRESULT, stdcall and out parameter. If anybody doesn't use safecall then HRESULT should be returned. – ChristianWimmer Nov 18 '10 at 21:00
0

You need to use SysAllocString() or SysAllocStringLen() to allocate the BSTR.

sharptooth
  • 167,383
  • 100
  • 513
  • 979
0

First chance exception at $75A9FBAE. Exception class EAccessViolation with message 'Access violation at address 75A409A4 in module 'RPCRT4.dll'

  1. the error is coming from RPCRT4.dll

  2. EAccessViolation is mostly caused by accessing a null object, step through your code make sure all objects are valid objects.

Darkerstar
  • 924
  • 1
  • 8
  • 17