将C stdcall接口方法中的变量参数转换为Delphi

时间:2018-09-17 16:43:06

标签: delphi winapi com

我正在将ICallFrame接口转换为Delphi,但不确定如何处理ICallFrame::Invoke方法。

这是定义:

HRESULT Invoke(
  void *pvReceiver,
  ...  
);

根据文档,varargs指令仅适用于外部例程,并且仅适用于cdecl调用约定。

这有点奇怪,因为Invoke是用STDMETHODCALLTYPE声明的,因此是__stdcall的声明,这是一个被调用方干净的约定。但是可变参数函数不能是被调用方干净的,因为被调用方不知道传递了多少参数。 如果使用Visual Studio执行此操作,是否有某种编译器魔术?

即使编译器魔术使用了cdecl,Delphi编译器也不接受(因为它不是外部的)E2070 Unknown directive: 'varargs'

ICallFrame = interface(IUnknown)
  ['{D573B4B0-894E-11d2-B8B6-00C04FB9618A}']
  // other methods left out
  function Invoke(pvReceiver: PVOID): HRESULT; cdecl; varargs;
end;

根据鲁迪的回答,看来这可能有效:

type
    TfnInvoke = function(this: Pointer; pvReceiver: Pointer): HRESULT; cdecl varargs;

implementation 

function GetInterfaceMethod(const intf; methodIndex: dword) : pointer;
begin
  Result := Pointer(pointer(dword_ptr(pointer(intf)^) + methodIndex * SizeOf(Pointer))^);
end;
...
var
  Invoker: TfnInvoke;
  ...
  // Don't forget IUnknown methods when counting!
  Invoker := GetInterfaceMethod(myIntf, 21);
  Invoker(myIntf, FObject, 11, 17.3);

我将对此进行测试并报告... 编辑:经过测试,可以工作。

1 个答案:

答案 0 :(得分:5)

Stdcall不能使用变量参数。任何使用可变参数的C或C ++函数都必须为__cdecl,因为只有在该调用约定中,知道传递了多少参数的调用方(代码)才会清理堆栈。即使默认调用约定为stdcall,var args函数也将为cdecl

Delphi无法像这样生成函数,但是它可以使用varargs指令使用现有的外部 C函数(在DLL或.obj文件中)。

所以C(或C ++)函数类似

HRESULT Invoke(void *pvReceiver, ...);

应转换为:

function Invoke(pvReceiver: Pointer); cdecl; varargs;

请注意,在Delphi声明中省略了...部分。假设您使用varargs指令。

这使您可以像在C或C ++中那样在Delphi中使用它:

Invoke(someReceiver, 17, 1.456);

另一个例子:例如众所周知的C函数printf()

int printf(const char *format, ...);

被声明为

function printf(format: PAnsiChar {args}): Integer; cdecl; varargs;

System.Win.Crtl.pas 中。

更新

这似乎是接口的一种方法。

不确定是否可行,但我会尝试:

type
  TInvoke = function(Intf: IInterface; pvReceiver: Pointer): HRESULT; cdecl varargs; 
  // No semicolon between cdecl and varargs.

并将其用作:

MyResult := TInvoke(@myIntf.Invoke)(myIntf, someReceiver, 11, 17.3);

此方法可能已经通过__stdcall宏声明为STDMETHODCALLTYPE,但即使这样,如果它是可变参数,(VC ++)编译器也会生成__cdecl,就像Remy一样。勒博发现了in Raymond Chen's blog