通过索引调用原生 COM 接口方法.
Result := ComCall(Index, ComObj , Type1, Arg1, Type2, Arg2, ReturnType)
类型: 整数
虚拟函数表中方法的索引(从零开始).
Index 对应于方法在原始接口定义中的位置. Microsoft 文档通常按字母顺序列出方法, 这是不相关的. 为了确定正确的索引, 请找到原来的接口定义. 这可能在头文件或类型库中.
考虑方法继承于的父接口是很重要的. 因为所有的 COM 接口最终都是从 IUnknown 派生出来的, 所以前三个方法总是 QueryInterface (0), AddRef (1) 和 Release (2). 例如, IShellItem2 是 IShellItem 的扩展, 它从索引 3 开始, 包含 5 个方法, 所以 IShellItem2 的第一个方法(GetPropertyStore) 的索引为 8.
提示: 对于微软定义的 COM 接口, 尝试在互联网或 Windows SDK 中搜索 "IInterfaceNameVtbl" - 例如, "IUnknownVtbl". Microsoft 自己的接口定义附带这个接口的虚拟函数表的纯-C 语言定义, 它以正确的顺序显式地列出了所有方法.
传递无效的索引可能会导致不确定的行为, 包括(但不限于) 程序终止.
目标 COM 对象; 也就是说, 一个 COM 接口指针. 指针值可以直接传递, 也可以封装在带有 Ptr
属性的对象中, 如带有 VT_UNKNOWN 变量类型的 ComValue.
接口指针用于定位实现接口方法的虚拟函数的地址, 也作为参数传递. 这个参数通常不会在原生支持接口的语言中显式地出现, 而是在 C 言语风格的 "Vtbl" 定义中显示.
传递无效指针可能导致未定义的行为, 包括(但不限于) 程序终止.
类型: 字符串
每一对值表示要传递给方法的单个参数. 对的数量是无限的. 有关 Type, 请参阅 DllCall 类型列表. 有关 Arg, 指定要传递给方法的值.
类型: 字符串
如果省略, 返回类型默认为 HRESULT, 这是 COM 接口方法最常用的返回类型. 任何指示失败的结果都会抛出 OSError; 因此, 除非实际的返回类型是 HRESULT, 否则不能省略返回类型.
如果方法是不返回值的类型(C 语言中的 void
返回类型), 则指定 "Int" 或不带任何后缀的其他数字类型(HRESULT 除外), 并忽略返回值. 在这种情况下, 由于返回值寄存器的内容是任意的, 所以如果省略了 ReturnType, 可能会也可能不会抛出异常.
否则, 指定 DllCall 类型列表中的一个参数类型. 支持星号后缀.
尽管 ComCall 和 DllCall 支持 Cdecl, 但它通常不在 COM 接口方法中使用.
如果 ReturnType 是 HRESULT(或省略), 并且方法返回一个错误值(由 FAILED macro 定义), 则抛出 OSError.
否则, ComCall 将返回该方法返回的实际值. 如果方法是不返回值的类型(该返回类型在 C 语言中定义为 void
), 则结果是未定义的, 应将其忽略.
以下 DllCall 主题也适用于 ComCall:
ComObject, ComObjQuery, ComValue, Buffer 对象, CallbackCreate
从任务栏中删除活动窗口 3 秒钟. 可以与等效的 DllCall 示例进行比较.
/* ITaskbarList 虚拟函数列表中的方法: IUnknown: 0 QueryInterface -- 使用 ComObjQuery 代替 1 AddRef -- 使用 ObjAddRef 代替 2 Release -- 使用 ObjRelease 代替 ITaskbarList: 3 HrInit 4 AddTab 5 DeleteTab 6 ActivateTab 7 SetActiveAlt */ IID_ITaskbarList := "{56FDF342-FD6D-11d0-958A-006097C9A090}" CLSID_TaskbarList := "{56FDF344-FD6D-11d0-958A-006097C9A090}" ; 创建 TaskbarList 对象. tbl := ComObject(CLSID_TaskbarList, IID_ITaskbarList) activeHwnd := WinExist("A") ComCall(3, tbl) ; tbl.HrInit() ComCall(5, tbl, "ptr", activeHwnd) ; tbl.DeleteTab(activeHwnd) Sleep 3000 ComCall(4, tbl, "ptr", activeHwnd) ; tbl.AddTab(activeHwnd) ; 完成对象后, 只需将所有引用替换为 ; 其他一些值(如果是局部变量, 就返回): tbl := ""
tbl := TaskbarList() activeHwnd := WinExist("A") tbl.DeleteTab(activeHwnd) Sleep 3000 tbl.AddTab(activeHwnd) tbl := "" class TaskbarList { static IID := "{56FDF342-FD6D-11d0-958A-006097C9A090}" static CLSID := "{56FDF344-FD6D-11d0-958A-006097C9A090}" ; 在启动时调用, 以初始化类. static __new() { ; 获取 TaskbarList 的所有实例的基对象. proto := this.Prototype ; 绑定函数可用于预定义参数, 使 ; 这些方法在不需要包装器函数的情况下更容易使用. ; HrInit 本身没有参数, 所以只绑定索引, ; 而调用者将隐式地提供 'this'. proto.HrInit := ComCall.Bind(3) ; 将参数留空, 让调用者提供一个值. ; 在本例中, 空白参数是 'this'(通常是隐藏的). proto.AddTab := ComCall.Bind(4,, "ptr") ; 可以使用对象或映射来减少重复. for name, args in Map( "DeleteTab", [5,,"ptr"], "ActivateTab", [6,,"ptr"], "SetActiveAlt", [7,,"ptr"]) { proto.%name% := ComCall.Bind(args*) } } ; 在新实例上由 TaskbarList() 调用. __new() { this.comobj := ComObject(TaskbarList.CLSID, TaskbarList.IID) this.ptr := this.comobj.ptr ; 通过 ITaskbarList 请求初始化. this.HrInit() } }