[DllImport("QCall")] 是啥?

Posted

技术标签:

【中文标题】[DllImport("QCall")] 是啥?【英文标题】:What is [DllImport("QCall")]?[DllImport("QCall")] 是什么? 【发布时间】:2012-03-18 11:30:27 【问题描述】:

.Net 库中的许多方法都是在本机代码中实现的。来自框架本身的那些标记为[MethodImpl(MethodImplOptions.InternalCall)]。来自某些非托管 DLL 的那些标记为 [DllImport](例如 [DllImport("kernel32.dll")])。到目前为止没有什么异常。

但是在写answer for another question的时候,我发现有很多方法都标有[DllImport("QCall")]。它们似乎是 .Net 的内部实现(例如 GC._Collect())。

我的问题是:[DllImport("QCall")] 到底是什么意思? [DllImport("QCall")][MethodImpl(MethodImplOptions.InternalCall)]有什么区别?

【问题讨论】:

这是一个特殊的内部调用;我正在寻找详细信息。 我记得不久前读到“QCall”是 clr.dll 的一部分。然而,除此之外,我知道的不多。 +1 提出一个很好的问题。 这是 .NET 4 特有的功能。您可以从 V4 参考源中获得一些见解,查看 System.Runtime.CompilerServices.Jithelpers.cs 的源代码。该字符串在 clr.dll 中出现两次,分别是 __IsQCall 和内联文字。这非常类似于 MethodImplOptions.InternalCall 之外的扩展机制,证明没有 CLR 源代码很难。 【参考方案1】:

这是一个旧线程。由于 CoreCLR 现在在 GitHub 上开源;如果有人还在寻找答案,这里是official documentation:

Calling from managed to native code

我们有两种技术可以从托管代码调用 CLR。 FCall 允许您直接调用 CLR 代码,并在操作对象方面提供了很大的灵活性,尽管由于不正确跟踪对象引用很容易导致 GC 漏洞。 QCall 允许您通过 P/Invoke 调用 CLR,并且比 FCall 更难意外误用。 FCall 在托管代码中被标识为设置了 MethodImplOptions.InternalCall 位的外部方法。 QCall 是静态外部方法,看起来像常规的 P/Invokes,但用于名为“QCall”的库。

FCall 有一个称为 HCall(用于 Helper 调用)的小变体,用于实现 JIT 助手,用于执行诸如访问多维数组元素、范围检查等操作。HCall 和 FCall 之间的唯一区别是 HCall 方法胜出'不显示在异常堆栈跟踪中。

然后在小标题中继续:

Choosing between FCall, QCall, P/Invoke, and writing in managed code QCall Functional Behavior

举例:

QCall Example - Managed Part QCall Example - Unmanaged Part

【讨论】:

【参考方案2】:

补充@SLaks 答案,MethodImplOptions.InternalCall 在这里简要描述:ThreadPoolPriority, and MethodImplAttribute

基本上 InternalCall 告诉运行时去检查它自己的命名函数的内部查找表。该表的存在是因为运行时代码中的源文件在编译运行时时显式声明了它们。它有一个用于实现所有内部调用的函数指针列表:

static ECFunc gGuidFuncs[] =  FCFuncElement("CompleteGuid", NULL, (LPVOID)GuidNative::CompleteGuid), NULL, NULL, NULL ;

此声明告诉运行时托管 Guid.CompleteGuid 方法的方法体实际上是本机 C++ GuidNative::CompleteGuid 函数。这篇文章不太清楚封送处理在这个地方是如何工作的,但总的来说,这显然取决于运行时实现,因为它既 a) 声明了函数体 [这取决于封送处理格式] 并且 b) 执行任何所需的封送处理.

【讨论】:

【参考方案3】:

我向 .Net 团队中的一些人询问过这个问题。

QCall 是对 CLR 运行时内的本地方法的调用。它们的行为与其他 [DllImport]s 相似,但它们更快,因为它们对本机方法的作用做出特定(未记录的)假设,因此它们可以跳过各种编组和 GC 以及异常检查。

InternalCall 不同;它用于调用在运行时生成的特殊反射式事物(这不是很清楚)。

【讨论】:

以上是关于[DllImport("QCall")] 是啥?的主要内容,如果未能解决你的问题,请参考以下文章

请问[DllImport("gpsapi.dll")]的dll文件放在哪儿?

c#使用DllImport调用c++dll的函数

C#DllImport传参

[DllImport("user32.dll")]这句代码是啥意思啊?没学过,解释下…

将 DllImport 放在哪里?

C#DllImport是干嘛的