10
votes

I was re-reading through some .Net documentation today when I noticed that the first portion of the extern keywords documentation claims:

The extern modifier is used to declare a method that is implemented externally. A common use of the extern modifier is with the DllImport attribute when you are using Interop services to call into unmanaged code.

What caught my attention was that the document states that "a common use" of extern is that it is used with the DllImport attribute. This implies that there are other use-cases where DllImport is not required. I've not had to integrate many external, non-managed libraries into my applications but in all cases the linked methods were defined with DllImport.

I've searched multiple queries through Google and MSDN and I can't find a case or explanation of when the extern keyword would be used without defining the method as an external method import from an unmanaged dll.

How, and when, would you use the extern keyword without defining the [DllImport(...)] attribute on the method definition?

Please note, this is not specific to using extern when defining aliases. That is a different use of the keyword and that case is outlined in a different article within the MSDN C# language reference.

1
stackoverflow.com/questions/2347260/… This seems to be a relevant to youcvraman
@cvraman See the last sentence of my question.RLH
Unless you write your own just-in-time compiler: never. It is the jitter that needs to know how to resolve a "call something defined somewhere else" to a real call. The one you use every day only knows a specific set of cases, [DllImport] is one of them. Internal calls to a function defined in the CLR and a COM method call are the other ones. It is not extensible.Hans Passant
@HansPassant excellent explaination, as always, Hans!RLH
@HansPassant: do you have more info on the "COM method call" case? Sounds like something that could be in an answer, either mine or your own.Jeroen Mostert

1 Answers

11
votes

One case where I'd use it is if I were a Microsoft developer implementing a call to a method defined in the CLR itself. Like in GC._WaitForFullGCApproach:

[MethodImpl(MethodImplOptions.InternalCall)]
private static extern int _WaitForFullGCApproach(int millisecondsTimeout);

Note: no DllImport. Of course this is cheating a bit -- this is still a call to an unmanaged method, just not with an explicit reference to a DLL. Mere mortals cannot invoke such code, though, since it's valid only in the mscorlib assembly.

Another application of InternalCall is in interop types generated for COM:

namespace Microsoft.Office.Interop.Excel {
    [DefaultMember("_Default")]
    [ClassInterface(0)]
    [ComSourceInterfaces("Microsoft.Office.Interop.Excel.AppEvents\0")]
    [Guid("00024500-0000-0000-C000-000000000046")]
    [TypeLibType(2)]
    [ComImport]
    public class ApplicationClass {
        // ...
        [DispId(302)]
        [MethodImpl(MethodImplOptions.InternalCall)]
        public virtual extern void Quit();
        // ...
    }
}

The attributes allow the runtime to resolve the method call as an invocation to a COM interface. This use of InternalCall is valid outside mscorlib, obviously. You would not typically write such code in C# yourself; it's generated on demand when you add a COM type library as a reference.

The C# language specification goes into slightly more detail than the MSDN:

The extern modifier is typically used in conjunction with a DllImport attribute (§17.5.1), allowing external methods to be implemented by DLLs (Dynamic Link Libraries). The execution environment may support other mechanisms whereby implementations of external methods can be provided.

From an implementation standpoint, marking a method extern only has the effect of setting the RVA (relative virtual address) of the method to 0, marking it as having no implementation. Attributes like DllImport (and MethodImpl) are necessary to describe to the runtime how to locate the method's actual implementation. This is described in secion I.9.4 of ECMA-335, "Method implementation metadata" (and DllImport and InternalCall seem to be the only ways currently available).

The C# compiler will allow you to mark a method as extern and not use any attribute to indicate where the implementation lives, but any type with such a method will result in a TypeLoadException at runtime.