【问题标题】:COM interface declaration and use (or lack thereof)COM接口声明和使用(或缺少)
【发布时间】:2018-03-30 16:50:14
【问题描述】:

据我了解,COM 接口是 C++ 中的抽象类,但由于某种原因转换为 C# 接口。为什么必须在 C# 中声明接口的所有方法,即使不打算使用它的任何成员?以IFileOperation 为例,我尝试删除我验证过的函数声明,这些声明从未在我的代码中调用,但它会导致 System.AccessViolationException 被抛出。

【问题讨论】:

  • 当您是调用者时(如使用 IFileOperation),您必须指定相同数量/布局的方法,但如果您不使用它,则不必定义所有方法的详细信息.另外,如果您使用的唯一方法是第 3 种方法,那么您可以定义没有 args 的 method1()、method2()(作为占位符),然后使用完全相同的签名定义真正的 method3。但是当有人打电话给你时(比如当你实现 IFileOperationProgressSink 时),那么你必须定义所有具有所有签名的方法。接口只是二进制合约。
  • 第三个按什么顺序,按字母顺序排列?
  • 不,名称只适用于人类。最后,接口只是一个指向方法的指针表。请记住:它都是二进制的,不像 .NET 带有命名空间或类名等。
  • 我可以在 MSDN 上找到这些表吗,还是我必须深入挖掘?
  • 它们在 Windows SDK 的 .idl 和/或 .h 中定义。例如:IFileOperation 在我的 PC 上的 C:\Program Files (x86)\Windows Kits\10\Include\10.0.15063.0\um\ShObjIdl_core.h 中。该表是方法列表(以及基本接口方法,包括 IUnknown 方法)。不要相信 MSDN,方法的顺序没有意义,它只是用于文档。

标签: c# c++ interface com com-interop


【解决方案1】:

您的代码不会单独运行。 COM 接口是提供服务的代码和使用这些服务的代码之间的二进制契约。该合同是一个全有或全无的协议(需要注意的是,E_NOTIMPL 可用于指示某些可选方法不可用,如果接口文档表明这是允许的)。

IFileOperation 不是您的合同。它属于微软。它用于与 Microsoft 代码和其他 3rd 方代码进行交互。该代码(您不拥有)期望实现接口的类为接口中的每个方法提供函数指针(并将其放入 VTable 中)。这就是界面的意思。您不能不提供该函数指针。根据接口的文档化规则,该代码将调用它认为适合调用的接口中的任何方法。这不是你的选择。

如果您绝对确定该方法未被调用,则意味着您没有使用它与 shell 交互。如果您不喜欢其中的某些方法并且您不与 shell(或其他 3rd 方代码)交互,您可以随时制作自己的界面;没有人强迫你借别人的。确保 COM 服务器和客户端都同意接口定义。

另一方面,如果您正在与 shell 交互,您不知道 shell 会调用哪些方法。您必须为所有这些提供实现,即使您所做的只是返回错误。我对IFileOperation 不是很熟悉,所以请仔细阅读文档。某些方法可能会返回特定的错误消息(如 E_NOTIMPL)以指示特定功能不可用。

您遇到无效访问冲突这一事实强烈表明您不喜欢的方法之一确实被调用了。

【讨论】:

  • 并不是我“不喜欢”它们,只是我觉得手动写出它们是额外的工作,因为我自己不会打电话给它们中的一些。我确实删除了 IShellItem 的所有功能,它仍然有效。我想这取决于相关的界面。
  • 我还是不太清楚你在做什么。请注意,从文档中复制一个接口并将其称为 IFileOperation 不会使其成为 the IFileOperation。接口名称是任意的,并且是为了开发人员的利益。您的文档链接中 IFileOperation 的真实名称是IID {947AAB5F-0A5C-4C13-B4D6-4BF7836FC9F8}。如果您创建一个具有类似布局的新界面并将其称为 IFileOperation,那很好 - 但您的界面是您在 IDL 中分配给它的任何 IID - 然后您只需要确保双方都知道使用那个,而不是 IID {947...9F8}。
  • 我声明了这两个接口并将它们与各自的 GUID 链接起来。我可以使用 IFileOperation 和 IShellItem 来删除东西,但我刚刚意识到,如果我从 IFileOperations 声明中删除了那些我没有调用的函数,那么程序就会崩溃,但是如果我对 IShellItem 做同样的事情,它工作得很好。
  • 我明白了。不要从现有接口中删除任何内容;即使它们今天“工作”,它也可能会在下一个 Windows 补丁、旧版本的 Windows 或未来的 Windows 上,或者当你安装另一个 shell 实用程序时,或者在别人的机器上,或者当你在资源管理器上做某事时您还没有尝试过,或者在运行 Word 时... 如果 VTable 中缺少某个方法,shell 最终会跳转到随机内存。如果您绝对没有时间更全面地研究接口契约,请实现返回 E_NOIMPL 的方法;至少你不会冒险硬崩溃。
猜你喜欢
  • 2020-08-21
  • 1970-01-01
  • 2016-05-04
  • 1970-01-01
  • 2019-05-24
  • 2014-09-20
  • 1970-01-01
  • 1970-01-01
  • 2011-02-26
相关资源
最近更新 更多