【发布时间】:2012-01-18 14:18:28
【问题描述】:
什么是平台调用(P/Invoke)?
执行 P/Invoke 是什么意思?是calling an external dll吗?例如:
[DllImport("coredll.dll", SetLastError=true)]
private static extern bool SHGetSpecialFolderPath(
int hwndOwner,
string lpszPath,
ceFolders nFolder,
bool fCreate);
这就是 P/Invoke 的意思:使用[DllImport] 属性吗?
还有什么可以被认为是P/Invoke?
[ComImport] 呢?例如:
[System.Runtime.InteropServices.ComImport]
[Guid("F8383852-FCD3-11d1-A6B9-006097DF5BD4")]
public class ProgressDialog
{
}
注意:这个 COM 类 (F8383852-FCD3-11d1-A6B9-006097DF5BD4) 可以在
HKEY_CLASSES_ROOT\CLSID\{F8383852-FCD3-11d1-A6B9-006097DF5BD4}
(default) %SystemRoot%\system32\shell32.dll
ThreadingModel Both
我也可以用代码构造一个原生的ADO Recordset 对象:
[System.Runtime.InteropServices.ComImport]
[Guid("00000535-0000-0010-8000-00AA006D2EA4")]
public class Recordset
{
}
Object rs= new Recordset();
这算是 P/Invoke 吗?
如果我们选择说“P/Invoke 很糟糕”,那么 ComImport 是否与 DllImport 一样“糟糕”?
什么是平台调用(P/Invoke)?
更新:来自 MSDN:
Platform Invoke Tutorial
平台调用服务 (PInvoke) 允许托管代码调用 在 DLL 中实现的非托管函数。
C#代码可以直接调用非托管代码有两种方式:
- 直接调用从 DLL 导出的函数。
- 在 COM 对象上调用接口方法(有关详细信息,请参阅 COM Interop Part 1: C# Client Tutorial)。
我想我可能已经回答了我自己的问题。
一年半之后。现在没有人关注这个问题,也没有人喜欢它,我可以说我接受的答案是错误的。 P/Invoke 是 Platform Invoke 的缩写。这是一种在 CLR 内部运行的托管代码可以调用非托管本机(即平台)代码的机制。这几乎总是通过调用驻留在本机 dll 中的代码来完成。 COM dll 是本机代码;它们只是遵循严格的结构,以允许许多不同的编译器调用它们。
而且平台调用很糟糕。它绕过所有垃圾收集,并取决于平台(即我的 32 位 CLR 进程无法加载 64 位 dll,我为 Android 编写的应用程序无法在 Windows 上运行,我为 Windows 8 上的功能编写的应用程序将无法运行Windows XP)。
【问题讨论】:
-
"P/Invoke is bad" 这个陈述是错误的。它可能很糟糕,取决于几个因素,就像任何事情都可能很糟糕一样。任何做出这种笼统陈述的人只会表明他们缺乏经验。它还表明缺乏对 .NET Framework 工作原理的理解。
-
@Ramhound 感谢您不理解我在说什么。
-
请注意您输入刚刚粘贴到更新中的部分的方式!请注意它提到了两种从 C# 调用非托管代码的方法,但并没有说它们都是 P/Invoke。事实上,COM 在那篇文章中没有其他地方提到过。其他文本强烈建议 P/Invoke 仅适用于这两点中的第一点。事实上,请注意 MSDN 上有一个单独的 COM Interop Tutorials 页面(参见导航栏),它与 Platform Invoke 不同。
-
P/invoke 本身当然不错。使用而不是完美的托管替代品,那么是的。用作访问本来无法访问的库的一种方式,没有托管替代方案,它非常好。例如,我的产品是一个非托管程序,它通过非托管 DLL 公开 API。您将如何建议 .net 消费者来访问它。没有托管替代方案。
-
@DavidHeffernan 这就是您创建独立于平台的托管替代方案的时候。如何在非英特尔设备上运行您的应用?