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

问题描述 投票:3回答:1

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

这是定义:

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

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

这有点奇怪,因为用STDMETHODCALLTYPE声明了Invoke,因此__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;

基于Rudy的答案,似乎这可行:

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

我将用此测试并报告回来...编辑:测试和工作。

delphi winapi com
1个回答
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指令时会假设它。

这允许你在Delphi中使用它,就像在C或C ++中一样:

Invoke(someReceiver, 17, 1.456);

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

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

被宣布为

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

在System.Win.Ctrl.pad中。

Update

这似乎是一种界面的方法。

不确定这是否有效,但我会尝试:

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 Lebeau发现了in Raymond Chen's blog

© www.soinside.com 2019 - 2024. All rights reserved.