72

Many methods in the .Net library are implemented in native code. Those that come from the framework itself are marked with [MethodImpl(MethodImplOptions.InternalCall)]. Those that come from some unmanaged DLL are marked with [DllImport] (e.g. [DllImport("kernel32.dll")]). So far nothing unusual.

But while writing answer for another question, I discovered there are many methods marked with [DllImport("QCall")]. They seem to be internal implementation of .Net (e.g. GC._Collect()).

My question is: What exactly does [DllImport("QCall")] mean? What is the difference between [DllImport("QCall")] and [MethodImpl(MethodImplOptions.InternalCall)]?

Community
  • 1
  • 1
svick
  • 214,528
  • 47
  • 357
  • 477
  • 1
    It's a special internal call; I'm trying to find details. – SLaks Feb 28 '12 at 23:41
  • I remember reading awhile back that "QCall" is part of clr.dll. I, however, don't know much beyond that. +1 for an excellent question. – ahawker Feb 29 '12 at 01:36
  • 11
    It is a .NET 4 specific feature. You can get a wee bit of insight from the V4 Reference Source, look at the source code for System.Runtime.CompilerServices.Jithelpers.cs. The string appears twice in clr.dll, as __IsQCall and as a inline literal. This strongly resembles an extension mechanism beyond MethodImplOptions.InternalCall, proving it is difficult without CLR source code. – Hans Passant Feb 29 '12 at 01:51

3 Answers3

36

I asked some people in the .Net team about this.

QCalls are calls to native methods within the CLR runtime. They behave like other [DllImport]s, but they're faster because they make specific (undocumented) assumptions about what the native methods do, so they can skip various marshalling and GC and exception checks.

InternalCall is different; it's for calls for special reflection-style things which are generated at runtime (this wasn't very clear).

svick
  • 214,528
  • 47
  • 357
  • 477
SLaks
  • 800,742
  • 167
  • 1,811
  • 1,896
19

This is an old thread. Since CoreCLR is now open-sourced on GitHub; if someone is still seeking the answer, here is the official documentation:

Calling from managed to native code

We have two techniques for calling into the CLR from managed code. FCall allows you to call directly into the CLR code, and provides a lot of flexibility in terms of manipulating objects, though it is easy to cause GC holes by not tracking object references correctly. QCall allows you to call into the CLR via the P/Invoke, and is much harder to accidentally mis-use than FCall. FCalls are identified in managed code as extern methods with the MethodImplOptions.InternalCall bit set. QCalls are static extern methods that look like regular P/Invokes, but to a library called "QCall".

There is a small variant of FCall called HCall (for Helper call) for implementing JIT helpers, for doing things like accessing multi-dimensional array elements, range checks, etc. The only difference between HCall and FCall is that HCall methods won't show up in an exception stack trace.

And then it continues in subheadings:

with examples:

vulcan raven
  • 29,699
  • 8
  • 51
  • 90
0

Supplementing @SLaks answer, MethodImplOptions.InternalCall is described briefly here: ThreadPoolPriority, and MethodImplAttribute.

Basically InternalCall tells the runtime to go check its own internal lookup table of named functions. That table exists due to a source file in the runtime code explicitly declaring them when the runtime is compiled. It has a list of function pointers for implementing all internal calls:

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

This declaration tells the runtime that the method body for the managed Guid.CompleteGuid method is actually the native C++ GuidNative::CompleteGuid function. The article isn't very clear on how marshaling works in this place, but in general that's clearly up to the runtime implementation, since it both a) declares the function body [which depends on the marshaling format] and b) does any required marshaling.

svick
  • 214,528
  • 47
  • 357
  • 477
Tim Lovell-Smith
  • 13,077
  • 11
  • 67
  • 89