Пример MSDN SafeHandle
Parhaps глупый вопрос... Я новичок в C# и.Net.
В примере для класса SafeHandle (C#) на MSDN код заставил меня немного почесать голову.
[SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode = true)]
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
internal class MySafeFileHandle : SafeHandleZeroOrMinusOneIsInvalid
{
private MySafeFileHandle()
: base(true)
{}
// other code here
}
[SuppressUnmanagedCodeSecurity()]
internal static class NativeMethods
{
// other code...
// Allocate a file object in the kernel, then return a handle to it.
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)]
internal extern static MySafeFileHandle CreateFile(String fileName,
int dwDesiredAccess, System.IO.FileShare dwShareMode,
IntPtr securityAttrs_MustBeZero, System.IO.FileMode
dwCreationDisposition, int dwFlagsAndAttributes,
IntPtr hTemplateFile_MustBeZero);
// other code...
}
// Later in the code the handle is created like this:
MySafeFileHandle tmpHandle;
tmpHandle = NativeMethods.CreateFile(fileName, NativeMethods.GENERIC_READ,
FileShare.Read, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero);
У меня вопрос: как работает Win32 HANDLE из C CreateFile
попасть в MySafeFileHandle
объекты защищены IntPtr
переменная "ручка"? Конструктор MySafeFileHandle
является частным и даже не берет IntPtr
в качестве аргумента!
Комментарий только над CreateFile
заявление говорит что-то о
… Слой маршаллинга платформы CLR будет хранить дескриптор в объекте SafeHandle атомарным способом.
Я не уверен, что точно знаю, что это значит, кто-нибудь может объяснить, пожалуйста?
1 ответ
Краткий ответ: это волшебство. Среда выполнения знает, как правильно преобразовать неуправляемые дескрипторы (которые являются просто значениями размера указателя) в SafeHandle
и назад.
Длинный ответ: это достаточно продвинутая технология. В частности, ILSafeHandleMarshaler
это (неуправляемый!) класс, который занимается маршалингом SafeHandle
назад и вперед. Исходный код усложняет процесс:
// 1) create local for new safehandle // 2) prealloc a safehandle // 3) create local to hold returned handle // 4) [byref] add byref IntPtr to native sig // 5) [byref] pass address of local as last arg // 6) store return value in safehandle
Код, который он выдает для загрузки неуправляемого дескриптора в безопасный дескриптор, на самом деле является управляемым кодом, хотя и управляемым кодом, который успешно игнорирует доступность. Он получает и вызывает конструктор по умолчанию для создания нового экземпляра:
MethodDesc* pMDCtor = pMT->GetDefaultConstructor();
pslIL->EmitNEWOBJ(pslIL->GetToken(pMDCtor), 0);
pslIL->EmitSTLOC(dwReturnHandleLocal);
И тогда это непосредственно устанавливает SafeHandle.handle
поле:
mdToken tkNativeHandleField =
pslPostIL->GetToken(MscorlibBinder::GetField(FIELD__SAFE_HANDLE__HANDLE));
...
// 6) store return value in safehandle
pslCleanupIL->EmitLDLOC(dwReturnHandleLocal);
pslCleanupIL->EmitLDLOC(dwReturnNativeHandleLocal);
pslCleanupIL->EmitSTFLD(tkNativeHandleField);
Ни конструктор, ни handle
поля действительно доступны, но этот код не подлежит проверке видимости.