Что такое [DllImport ( "QCall" )]?

Многие методы в библиотеке .Net реализованы в собственном коде. Те, которые поступают из самого фрейма, отмечены [MethodImpl(MethodImplOptions.InternalCall)]. Те, которые исходят из некоторой неуправляемой DLL, отмечены [DllImport] (например, [DllImport("kernel32.dll")]). Пока ничего необычного.

Но при написании ответа на другой вопрос, я обнаружил, что существует множество методов, отмеченных [DllImport("QCall")]. Кажется, что они являются внутренней реализацией .Net(например, GC._Collect()).

Мой вопрос: что означает [DllImport("QCall")]? В чем разница между [DllImport("QCall")] и [MethodImpl(MethodImplOptions.InternalCall)]?

Ответ 1

Это старый поток. Поскольку CoreCLR теперь открыт для GitHub; если кто-то все еще ищет ответ, вот официальная документация :

Вызов из управляемого кода

У нас есть два метода для вызова в CLR из управляемого кода. FCall позволяет вам напрямую звонить в код CLR и обеспечивает большую гибкость с точки зрения манипулирования объектами, хотя легко вызвать GC-отверстия, не правильно отслеживая ссылки на объекты. QCall позволяет вам звонить в CLR через P/Invoke и намного сложнее случайно использовать, чем FCall. FCalls идентифицируются в управляемом коде как внешние методы с установленным битом MethodImplOptions.InternalCall. QCalls - это статические внешние методы, которые выглядят как обычные P/Invokes, но для библиотеки под названием "QCall".

Существует небольшой вариант FCall, называемый HCall (для вызова Helper) для реализации помощников JIT, для выполнения таких действий, как доступ к многомерным элементам массива, проверка диапазона и т.д. Единственная разница между HCall и FCall заключается в том, что методы HCall выиграли 't отображается в трассе стека исключений.

И затем он продолжается в подзаголовках:

с примерами:

Ответ 2

Я спросил некоторых людей в команде .Net об этом.

QCalls - это вызовы для собственных методов в среде CLR. Они ведут себя как другие [DllImport] s, но они быстрее, потому что они делают конкретные (недокументированные) предположения о том, что делают нативные методы, поэтому они могут пропускать различные проверки маркеров и GC и исключения.

InternalCall отличается; это для вызовов особых вещей стиля отражения, которые генерируются во время выполнения (это было не очень понятно).

Ответ 3

Дополняя ответ @SLaks, здесь описывается метод MethodImplOptions.InternalCall: ThreadPoolPriority и MethodImplAttribute.

В основном InternalCall сообщает, что время выполнения проверяет собственную внутреннюю таблицу поиска именованных функций. Эта таблица существует из-за исходного файла в коде среды выполнения, явно объявляющего их при компиляции среды выполнения. Он содержит список указателей на функции для всех внутренних вызовов:

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

В этом объявлении указано, что тело метода для управляемого метода Guid.CompleteGuid фактически является встроенной функцией С++ GuidNative:: CompleteGuid. В статье не очень понятно, как работает маршалинг в этом месте, но в целом это явно зависит от реализации времени выполнения, поскольку он и объявляет тело функции [которое зависит от формата маршалинга], и b) делает любое требуемое маршалинг.