COM接口不继承自IUnknown的影响。

huangapple go评论76阅读模式
英文:

Implications for COM Interfaces that don't inherit from IUnknown

问题

我试图实现一些可以在导出 Word 文档为 PDF时使用的 COM 接口。其中一些接口不继承自 IUnknown,例如:

#undef  INTERFACE
#define INTERFACE  IMsoServerFileManagerSite
DECLARE_INTERFACE(IMsoServerFileManagerSite)
{
  STDMETHOD_(BOOL, FGetHandle) (const WCHAR *pwzFileName, HANDLE *phFile, BOOL fRead, BOOL fWrite) PURE;
  STDMETHOD_(BOOL, FCloseHandle) (HANDLE hFile) PURE;
};

我发现如果我使用 local 属性(声明它们不是远程接口),可以将这些接口翻译为 IDL。例如:

[
    local,
    uuid(f8e47685-e402-4119-aa07-4ea4ff1f1123)
]
interface IMsoServerFileManagerSite
{
    BOOL FGetHandle(const WCHAR *pwzFileName, HANDLE *phFile, BOOL fRead, BOOL fWrite);
    BOOL FCloseHandle(HANDLE hFile);
}

还有另一个接口 IMsoDocExporter,它继承自 IUnknown,但有一些返回 void 而不是 HRESULT 的函数。当我将实现此接口的对象传递给 Word API 时,我可以附加调试器并看到我的 dll 被诸如 combase.dll!CRemoteUnknown::RemQueryInterface 的函数调用。

所以我的问题是:

  1. combase.dll!CRemoteUnknown::RemQueryInterface 是否意味着我的对象正在远程查询?(即我将需要代理/存根,并且不能使用 [local] 属性?)

  2. 如果接口使用非自动化类型,比如 HANDLE,并且不返回 HRESULT,它仍然可以进行封送吗?

  3. 是否有一种方法/最佳方法将这些接口翻译为 IDL,以便 MIDL 将提供代理/存根实现?(例如,MIDL 参考建议可以使用 call_as 将这些函数映射到远程调用函数 - 对于 HANDLE 我仍然不清楚可以做什么)

英文:

I am trying to implement some COM interfaces that can be used while exporting Word documents as PDF. Some of these interfaces don't inherit from IUnknown, for instance:

#undef  INTERFACE
#define INTERFACE  IMsoServerFileManagerSite
DECLARE_INTERFACE(IMsoServerFileManagerSite)
{
  STDMETHOD_(BOOL, FGetHandle) (const WCHAR *pwzFileName, HANDLE *phFile, BOOL fRead, BOOL fWrite) PURE;
  STDMETHOD_(BOOL, FCloseHandle) (HANDLE hFile) PURE;
};

I found that I can translate these interfaces to IDL if I use the local attribute (declaring that they aren't remote). For instance

[
    local,
    uuid(f8e47685-e402-4119-aa07-4ea4ff1f1123)
]
interface IMsoServerFileManagerSite
{
    BOOL FGetHandle(const WCHAR *pwzFileName, HANDLE *phFile, BOOL fRead, BOOL fWrite);
    BOOL FCloseHandle(HANDLE hFile);
}

Another such interface, IMsoDocExporter, does inherit from IUnknown, but has some functions that return void rather than HRESULT. When I pass an object implementing this interface to the Word API I can attach a debugger and see that my dll is being called by functions like combase.dll!CRemoteUnknown::RemQueryInterface.

So my questions are:

  1. Does combase.dll!CRemoteUnknown::RemQueryInterface mean that my object is being queried remotely? (i.e. I'll need a proxy/stub, and can't use the [local] attr?)

  2. if an interface uses non-automation types, such as HANDLE, and doesn't return an HRESULT can it still be marshalled?

  3. is there a way/what is the best way to translate these interfaces to IDL so that MIDL will provide the proxy/stub implementation? (e.g. MIDL reference suggested that call_as could be used to map these functions to remote callable functions -- still unclear what I could do with HANDLE though)

答案1

得分: 1

在进一步尝试后,我终于设法使其正常工作。@molbdnilo和@Jonathan Potter是正确的。只有IMsoDocExporter接口是COM对象,并且继承自IUnknown。其他接口似乎只是普通的虚表,它们似乎无法进行封送(至少不能不写大量自定义代理/存根代码)。

>1. combase.dll!CRemoteUnknown::RemQueryInterface是否意味着我的对象正在远程查询?

是的,但这只适用于IMsoDocExporter(实际的COM对象)

>2. 如果一个接口使用非自动化类型,如HANDLE,并且不返回HRESULT,它仍然可以被封送吗?

事实证明是的。正如我在原始帖子中提到的,您可以将这些方法标记为[local],然后定义一个类似的方法,带有[call_as]属性,返回HRESULT并具有可进行RPC的参数。然后,您只需要定义将一个调用转换为另一个调用的函数。最终,要封送一个HANDLE,您需要指定类型信息。

英文:

After some more playing around I finally managed to make it work. @molbdnilo and @Jonathan Potter were correct. Only the IMsoDocExporter interface is a COM object, and it inherits from IUnknown. The other interfaces are just plain vtables I suppose and it seems that they can't be marshalled (at least not without writing lots of custom proxy/stub code).

>1. Does combase.dll!CRemoteUnknown::RemQueryInterface mean that my object is being queried remotely?

Yes, but this only applied to IMsoDocExporter (the actual COM object)

>2. if an interface uses non-automation types, such as HANDLE, and doesn't return an HRESULT can it still be marshalled?

It turns out yes. As mentioned in my original post you can mark these methods [local] and then define a similar method with the [call_as] attribute that returns HRESULT and has RPC-able parameters. Then you just need to define the functions that translates one call to the other. Ultimately, to marshal a HANDLE you need to specify the type information.

huangapple
  • 本文由 发表于 2023年4月19日 18:10:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/76053268.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定