如何从COM服务器返回WideString?

时间:2010-11-15 11:17:08

标签: delphi com delphi-2006 widestring

此接口位于_TLB.pas文件

// *********************************************************************//
// 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;

这是关于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);
};

COM服务器中的功能看起来像

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

在COM客户端中,我正在调用此函数,如

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

并获得错误 $ 75A9FBAE的第一次机会异常。异常类EAccessViolation,消息'模块'RPCRT4.dll'中地址为75A409A4的访问冲突。读取地址FFFFFFF8'。处理Project1.exe(2296)

如果我想要返回Integer,那就行了。如何返回WideString?

5 个答案:

答案 0 :(得分:1)

请勿使用HRESULT以外的返回值。而是将返回值作为输出参数放入参数列表中。

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

通过这种方式,您还被迫使用COM内存管理器IMalloc(CoTaskMemAlloc用于pur COM,SysAllocString用于自动化)。

答案 1 :(得分:1)

让Delphi自动执行转换。不要施放。您可以将(ansi)字符串转换为PChar,因为它们的内存布局是兼容的,但您不能将字符串转换为宽字符串或反之亦然。当您将一个指定给另一个时,Delphi将进行转换。

在德尔福< 2009年

var
S: string;
W: WideString;
...
S := W;  // Conversion, WideString -> AnsiString;
W := S; // Conversion, AnsiString -> WideString

答案 2 :(得分:1)

处理此问题的正确方法如下:

[ 
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;

通过在接口的Delphi声明(不在TypeLibrary本身)中使用Delphi的safecall调用约定,可以稍微简化一下:

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);

答案 3 :(得分:0)

您需要使用SysAllocString()SysAllocStringLen()来分配BSTR。

答案 4 :(得分:0)

$ 75A9FBAE的第一次机会异常。异常类EAccessViolation,消息'模块'RPCRT4.dll'中地址为75A409A4的访问冲突

  1. 错误来自RPCRT4.dll

  2. EAccessViolation主要是通过访问空对象引起的,单步执行代码确保所有对象都是有效对象。