如何处理返回未记录的IUnknown的COM服务器方法

3

我已经从硬件SDK的类型库中导入了COM接口的一些方法,其中一些方法返回或接收IUnknown类型的值。例如,SDK文档将这些方法规定如下:

bool SetInput1Selection(InputSelection inputSelection)
InputSelection GetInput1Selection()

但是Delphi将这些方法导入为:
function SetInput1Selection(const inputSelection: IUnknown): WordBool; safecall;
function GetInput1Selection: IUnknown; safecall;

类型InputSelection似乎是一个简单的整数或枚举类型,但没有在任何地方指定。文档仅提供了14种不同可能值的表格,以及它们的含义。

理想情况下,我想声明自己的类型:

TInputSelection = (isCustom, isStartReset, ...)

以下是类型库如何定义这些函数的方式:

virtual HRESULT __stdcall SetInput1Selection (/*[in]*/ IUnknown * inputSelection, /*[out,retval]*/ VARIANT_BOOL * pRetVal ) = 0;
virtual HRESULT __stdcall GetInput1Selection (/*[out,retval]*/ IUnknown * * pRetVal ) = 0;

但是我该如何使这个工作起来?

如果您知道类型库中的 InputSelection 类型是枚举类型,并且您知道它的成员,请在 Delphi 导入中进行更正(就像您展示的那样)。这可能只是错误的导入。 - TLama
@TLama我尝试将_TLB_单元中的_IUnknown_替换为_Integer_。但是GetInput#Selection返回的值似乎不对应任何允许的值。它们甚至没有1:1地映射,这意味着输入通道设置不同值的情况下返回相同的值(SDK包括一个测试应用程序,可以读取/写入输入通道设置)。这里还有其他问题。有没有'正确'的做法? - Gerald Menzel
由于我们不知道你使用的SDK类型,你需要自己去查看。如果文档中没有明确提到,你应该询问SDK开发者。 - Sir Rufo
我有。显然,他们已经将sdk开发外包,现在无法提供任何开发人员支持。这不是我购买他们硬件时期望的结果。但现在我必须尽力而为。也许有一些取证方法可以找出如何处理这样的IUnknown参数? - Gerald Menzel
我在第一条评论中尝试表达的是(或者更准确地说是猜测,因为我没有看到你的类型库),Delphi导入程序可能在导入该参数时失败了,因此您应该手动修改Delphi导入(如果您知道该参数是枚举而不是接口)。 - TLama
以下是类型库如何定义这些函数:virtual HRESULT __stdcall SetInput1Selection (/*[in]*/ IUnknown * inputSelection, /*[out,retval]*/ VARIANT_BOOL * pRetVal ) = 0;virtual HRESULT __stdcall GetInput1Selection (/*[out,retval]*/ IUnknown * * pRetVal ) = 0;。所以我认为 Delphi 导入程序已经尽力了。文档似乎暗示 InputSelection 是一个枚举类型。但除此之外,我不知道如何解决这个问题。 - Gerald Menzel
1个回答

3
整数/枚举和接口在类型库中的描述不同,因此类型库导入程序很难混淆它们。 我猜 InputSelection 确实是一种包装其他数据的接口类型,并且可能具有访问该数据的自己的属性/方法。 如果该接口未出现在类型库中,则可能是私有接口。

你可以尝试在GetInput1Selection()返回的IUnknown上调用QueryInterface(),请求一个IDispatch接口。如果这导致崩溃,则IUnknown不是有效的接口指针,可能是由于不良的导入引起的。但如果它没有崩溃,那么它很可能是一个真正的接口,特别是如果QueryInterface()成功。如果成功,调用IDispatch.GetTypeInfo()以查看它是否描述自己。如果是这样,你就可以发现它实现的所有属性和方法,包括参数。在某些环境中,如果基于IDispatch的对象只是一个POD值(如整数)的包装器,它通常有一个Value属性,并且甚至有一个特殊的DISPID来访问这样的属性IDispatch.Invoke()(我不记得实际的DISPID号码,我需要查一下)。

更新: 你是否在编程Nanotec步进电机?我在网上找到了文档,它与您提到的功能类似:

GetInput1Selection
    Definition:
        InputSelection GetInput1Selection()

This function outputs the function for digital input 1.
The function corresponds to serial command ':port_in_a'.

SetInput2Selection
    Definition:
        bool SetInput2Selection(InputSelection inputSelection)

This function sets the function for digital input 2.
The value returned by the function can be used to check that the command was correctly recognized by the controller.
The function corresponds to serial command ':port_in_b'.

不幸的是,它没有描述InputSelection实际上是什么。


感谢抽出时间,Remy!调用 IDispatch 的 QueryInterface 不会崩溃,但也不成功。我还尝试了 Supports(GetInput1Selection,TDispatch),返回 FALSE。看来不支持 IDispatch。我还有哪些选项? - Gerald Menzel
更准确地说,QueryInterface(GetInput1Selection,IDispatch) 返回 E_NOINTERFACE - Gerald Menzel
然后您需要联系SDK供应商并咨询此事。QueryInterface()返回E_NOINTERFACE而不崩溃的事实意味着GetInput1Selection()实际上返回了一个有效的IUknown接口,这意味着文档是错误的,或者至少是误导性的。您确定导入的TypeLibrary中没有声明其他接口类型吗? - Remy Lebeau
很遗憾,供应商在这里没有提供帮助(请参见我上面的评论)。但是我采用了一种蛮力方法,并找到了一个兼容的接口:IProvideClassInfo,它提供对ITypeInfo接口的访问。也许这有用吧?我已经超出了我的能力范围。如果有进一步的帮助,将不胜感激! - Gerald Menzel
是的,我正在控制NanoTec步进电机接口。你说得对,文档很差。但是关于IProvideClassInfo,我不知道该怎么做。我稍微尝试了一下它的ITypeInfo接口,这导致我找到了mscorlib.dll的类型库。在这里,声明了一个_Object接口,我的神秘IUnknown也支持它。虽然我不知道那是否有任何意义。 - Gerald Menzel
查看这篇文章以了解如何使用ITypeInfo并从中获取信息。它解释了如何提取详细信息并重建接口和方法声明。你将能够使用这些信息确定你的神秘IUnknown实际上实现了什么,然后你可以为相应的接口编写声明,以便在代码中查询IUnknown以访问该功能。 - Remy Lebeau

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接