Delphi 10.3.2 OSX64下修改QueryInterface调用约定的编译错误问题
我来帮你拆解这个问题,核心是Delphi对COM接口(尤其是IUnknown/IInterface)的特殊处理,以及跨平台调用约定的匹配问题。
为什么会出现E2211错误?
你遇到的编译错误,本质是因为你的MyIInterface使用了IUnknown的标准GUID({00000000-0000-0000-C000-000000000046})。Delphi会通过GUID识别接口类型,一旦匹配IUnknown的GUID,就会把你的自定义接口当作系统内置IInterface的等价物,强制要求你实现的方法和IInterface声明的调用约定完全一致。
而你尝试去掉stdcall/cdecl改用默认约定,就和系统IInterface中平台相关的调用约定(OSX下默认是cdecl)产生了冲突,于是抛出声明不一致的错误。
至于重命名QueryInterface为QueryInterface2仍要求实现原方法,也是同样的原因:Delphi认的是GUID,不是方法名——只要GUID是IUnknown的,就必须实现QueryInterface、_AddRef、_Release这三个标准方法。
解决方案
根据你的需求(对接GCC编译的dylib,使用OSX64默认调用约定),这里有两种可行的方案:
方案1:使用自定义GUID避免接口冲突
这是最安全的做法,彻底和系统IInterface解绑,自由定义调用约定:
- 给你的自定义接口生成一个唯一的GUID(用Delphi菜单栏的
Tools -> Create GUID生成) - 去掉所有调用约定修饰,使用OSX64默认约定
示例代码:
type // 替换成你自己生成的唯一GUID MyIInterface = interface ['{12345678-1234-1234-1234-123456789ABC}'] function QueryInterface(const IID: TGUID; out Obj): HResult; // 默认调用约定 function _AddRef: Integer; function _Release: Integer; end; TMyInterfacedObject = class(TObject, MyIInterface) protected function QueryInterface(const IID: TGUID; out Obj): HResult; function _AddRef: Integer; function _Release: Integer; end;
这样Delphi不会再把它和系统IInterface关联,你可以完全按照GCC dylib的要求定义调用约定,编译错误也会消失。
方案2:必须使用IUnknown GUID时的处理
如果你的dylib接口基于COM标准,必须用IUnknown的GUID,那需要修改系统IInterface的调用约定声明(仅限OSX64平台):
{$IFDEF OSX64} // 重新声明IInterface,替换默认调用约定 type IInterface = interface ['{00000000-0000-0000-C000-000000000046}'] function QueryInterface(const IID: TGUID; out Obj): HResult; function _AddRef: Integer; function _Release: Integer; end; {$ENDIF} TMyInterfacedObject = class(TObject, IInterface) protected function QueryInterface(const IID: TGUID; out Obj): HResult; function _AddRef: Integer; function _Release: Integer; end;
⚠️ 注意:这种方法会修改Delphi内置接口的行为,可能影响其他依赖IInterface的代码,一定要在OSX64条件编译下使用,并充分测试。
额外提示:匹配GCC的调用约定
OSX64下GCC默认使用System V AMD64 ABI调用约定,Delphi 10.3.2支持sysv关键字来显式指定这个约定。如果不确定默认约定是否匹配,你可以直接在方法上标注sysv:
type MyIInterface = interface ['{12345678-1234-1234-1234-123456789ABC}'] function QueryInterface(const IID: TGUID; out Obj): HResult; sysv; function _AddRef: Integer; sysv; function _Release: Integer; sysv; end;
内容的提问来源于stack exchange,提问作者Ivan Petrovic

