2012-02-28 18 views
61

Wiele metod w bibliotece .Net jest zaimplementowanych w natywnym kodzie. Te, które pochodzą z samej struktury, są oznaczone jako [MethodImpl(MethodImplOptions.InternalCall)]. Te, które pochodzą z niezarządzanej biblioteki DLL, są oznaczone jako [DllImport] (np. [DllImport("kernel32.dll")]). Do tej pory nic niezwykłego.Co to jest [DllImport ("QCall")]?

Podczas pisania answer for another question odkryłem, że istnieje wiele metod oznaczonych jako [DllImport("QCall")]. Wydają się być wewnętrzną implementacją .Net (np. GC._Collect()).

Moje pytanie brzmi: co dokładnie oznacza [DllImport("QCall")]? Jaka jest różnica między [DllImport("QCall")] i [MethodImpl(MethodImplOptions.InternalCall)]?

+1

To specjalne połączenie wewnętrzne; Próbuję znaleźć szczegóły. – SLaks

+0

Pamiętam, że od dawna czytam, że "QCall" jest częścią clr.dll. Ja jednak nie wiem zbyt wiele poza tym. +1 za doskonałe pytanie. – ahawker

+11

Jest to specyficzna funkcja .NET 4. Możesz uzyskać odrobinę wglądu ze źródła referencyjnego V4, spójrz na kod źródłowy dla System.Runtime.CompilerServices.Jithelpers.cs. Łańcuch pojawia się dwa razy w clr.dll, jako __IsQCall i jako inline literal. To bardzo przypomina mechanizm rozszerzenia poza MethodImplOptions.InternalCall, dowodząc, że jest to trudne bez kodu źródłowego CLR. –

Odpowiedz

14

To jest stary wątek. Ponieważ CoreCLR jest teraz dostępny w wersji open-source na GitHub; jeśli ktoś jest nadal szukają odpowiedzi, oto official documentation:

Calling from managed to native code

Mamy dwie techniki dzwoniąc do CLR z kodu zarządzanego. FCall pozwala na wywoływanie bezpośrednio do kodu CLR i zapewnia dużą elastyczność w zakresie manipulowania obiektami, chociaż łatwo jest spowodować dziury GC, nie śledząc poprawnie referencji obiektu. QCall pozwala na wywołanie CLR za pośrednictwem P/Invoke i jest znacznie trudniejsze do przypadkowego niewłaściwego użycia niż FCall. Fale są identyfikowane w zarządzanym kodzie jako metody zewnętrzne z zestawem bitów MethodImplOptions.InternalCall. QCalls są statycznymi metodami zewnętrznymi, które wyglądają jak zwykłe P/Invokes, ale do biblioteki o nazwie "QCall".

Istnieje niewielki wariant FCall o nazwie HCall (dla wywołania Helper) do implementacji pomocników JIT, do robienia rzeczy takich jak dostęp do wielowymiarowych elementów tablicy, sprawdzania zasięgu itp. Jedyną różnicą między HCall i FCall jest to, że metody HCall nie pojawi się w śladzie stosu wyjątków.

A potem kontynuuje podpozycjami:

z przykładów:

35

Poprosiłem o to niektórych ludzi z zespołu .Net.

QCalls to wywołania do natywnych metod w środowisku wykonawczym CLR. Zachowują się jak inne, ale są szybsze, ponieważ tworzą specyficzne (nieudokumentowane) założenia o tym, co robią natywne metody, więc mogą pominąć różne kontrole i kontrole GC i wyjątków.

InternalCall jest inny; To jest wezwanie do specjalnych rzeczy w stylu refleksji, które są generowane w czasie wykonywania (to nie było zbyt jasne).

0

Uzupełnianie odpowiedzi @SLaks, MethodImplOptions.InternalCall opisano krótko tutaj: ThreadPoolPriority, and MethodImplAttribute.

Zasadniczo funkcja InternalCall mówi środowisku wykonawczemu, aby przejrzał własną wewnętrzną tabelę odnośników o nazwanych funkcjach. Ta tabela istnieje z powodu pliku źródłowego w kodzie środowiska wykonawczego jawnie deklarującego je podczas kompilowania środowiska wykonawczego. Ma listę wskaźników funkcji do realizacji wszystkich połączeń wewnętrznych:

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

Ta deklaracja informuje środowisko wykonawcze, że ciało metoda zarządzanej metody Guid.CompleteGuid jest rzeczywiście rodzimy C++ GuidNative :: funkcja CompleteGuid. W artykule nie jest bardzo jasne, jak działa marshaling w tym miejscu, ale ogólnie rzecz biorąc, jest to wyraźnie zależne od implementacji środowiska wykonawczego, ponieważ zarówno a) deklaruje ciało funkcyjne [które zależy od formatu marszałkowskiego], jak i b) wykonuje wszelkie wymagane operacje marshalingowe .