将 C stdcall 接口方法中的变量参数转换为 Delphi
Convert variable arguments in C stdcall interface method to Delphi
我正在转换 ICallFrame interface to Delphi and I am not sure how to handle the 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;
根据 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);
我会用这个测试并报告...
编辑:测试和工作。
Stdcall
不能使用可变参数。任何采用可变参数的 C 或 C++ 函数都必须是 __cdecl
,因为只有在该调用约定中,知道传递了多少参数的调用方(代码)才会清理堆栈。即使默认调用约定是 stdcall
,var args 函数也将是 cdecl
.
Delphi 无法 生成 那样的函数,但它可以 使用现有的外部 C 函数(在 DLL 或.obj 文件)使用 varargs
指令。
所以像这样的 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 Lebeau 发现的那样 in Raymond Chen's blog。
我正在转换 ICallFrame interface to Delphi and I am not sure how to handle the 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;
根据 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);
我会用这个测试并报告... 编辑:测试和工作。
Stdcall
不能使用可变参数。任何采用可变参数的 C 或 C++ 函数都必须是 __cdecl
,因为只有在该调用约定中,知道传递了多少参数的调用方(代码)才会清理堆栈。即使默认调用约定是 stdcall
,var args 函数也将是 cdecl
.
Delphi 无法 生成 那样的函数,但它可以 使用现有的外部 C 函数(在 DLL 或.obj 文件)使用 varargs
指令。
所以像这样的 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 Lebeau 发现的那样 in Raymond Chen's blog。