Что такое [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) делает любое требуемое маршалинг.