DllImport vs ComImport

时间:2017-10-15 12:06:05

标签: c# c++ winapi com pinvoke

我试图围绕平台调用服务,组件对象模型等概念,但我发现很难理解什么是什么以及不同的职责在哪里。我一直在研究包含以下内容的代码:

[DllImport("shell32.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
[return: MarshalAs(UnmanagedType.Interface)]
internal static extern object SHCreateItemFromParsingName([MarshalAs(UnmanagedType.LPWStr)] string pszPath, IBindCtx pbc, ref Guid riid);

[ComImport]
[Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IShellItem

据我了解,前者导入一个创建shell项的函数,后者导入创建它们所需的类型(接口)。

我不明白为什么使用DllImport和其他ComImport。它们各自的文档中没有说明使用哪种方法,文档也没有提供COM对象的GUID。我唯一的猜测是区分因素是前者是一个函数而后者是一个界面。

2 个答案:

答案 0 :(得分:2)

IShellItem是一个COM接口。 COM通常不会与[DllImport]调用外部代码的方式进行比较。 COM非常有趣,界面声明了一组可以调用的方法,就像使用interface关键字的C#语言一样。

实际上,您总是需要一个在C#和COM中实现接口的具体类。在COM术语中称为coclass,这些类在视图中完全隐藏。通常用C ++编写,这种语言通常支持互操作性很差,但COM提供的协议使C ++代码可以从几乎任何语言调用。隐藏类实现是关键因素,完全隐藏了令人讨厌的小C ++细节。像构造函数,内存管理,继承,对象布局,异常,从一种语言到另一种语言的端口很差的功能。

您始终需要使用工厂函数来创建类对象。一个通用的方法是你正在谈论的,CoCreateInstance()辅助函数是非常常用的。您需要提供的只是CLSID,即coclass的指南。然后,COM运行时负责查找实现coclass的EXE或DLL,加载它并获取IClassFactory接口以获取创建的对象。必须注册COM服务器是至关重要的,注册表中的密钥告诉它哪个可执行文件负责该工作。

然后是第二种方式,即由库显式导出的工厂函数,如SHCreateItemFromParsingName()。它避免了我在前一段中提到的所有粘性物质。并不常见,但并非罕见,DirectX是使用工厂函数的库的另一个很好的例子,如D3D11CreateDevice()。当微软更喜欢工厂函数而不是coclass时,并不是很明显,除了可能不鼓励使用脚本语言中的这样的库。

如果接口已由coclass实现,那么您可以简单地使用new IShellItem()来创建对象。注意创建接口实例的难度,这在C#中是没有意义的。但故意为COM客户端代码。 C#编译器在底层生成代码以使对象工厂管道运行。

但是,由于SHCreateItemFromParsingName工厂函数是DLL中的常规导出函数,因此您现在需要使用[DllImport]来声明它。

答案 1 :(得分:1)

DllImportComImport无关。

DllImport在.NET中基本上定义了一个函数原型,以便以后调用本机DLL中的函数。这种类型的方法调用通常称为 P / Invoke Platform Invoke 的缩写)。

ComImport doesn't really import anything。它是在c#中定义COM接口的手动方式,对于自定义/ IUnknown接口或自动化不兼容类型是typically used

  

我唯一的猜测是区分因素是前者是一个函数而后者是一个界面。

不,ComImport也可以应用于课程。

编辑:我想我现在看到你的情况,见下文

什么是大差异?

好的,所以在一天结束时我们有两种方法可能调用本机代码(假设目前我们的COM示例是用本机代码编写的)。为什么有两种不同的方式?

一个很大的区别是这些方法(或函数)如何向世界公开或宣传。

Windows 导出上的典型 .dll 文件在.dll文件的EXPORTS表中的功能。您可以通过在Microsoft Dependency Viewer中打开它来查看DLL中导出的函数。

enter image description here

这包括:

    User32.dll 中的
  • PeekMessage Kernel32.dll
  • 中的
  • DeleteFile
  • shell32.dll
  • 中的好朋友SHCreateItemFromParsingName

现在,为了调用上述内容,您必须使用我们讨论过的[DllImport]

COM不同。 COM类和方法未在EXPORT表中列出,因此[DllImport] / p调用它们是不可能的。 COM严重依赖Windows注册表; COM类型库或后期绑定以完成工作。

COM可以在.EXE或.DLL中实现(只是为了混淆一些东西)。在依赖关系查看器中打开COM .dll仅列出所有COM服务器必须实现的COM注册/取消注册功能。

e.g。查看 mapishell.dll COM服务器(MS Office的一部分),即使我们知道存在功能,我们也看不到任何导出(注册除外)。

enter image description here

更多

如果您想进一步了解COM的工作原理,请查看my other answer here了解更多信息。