Пример 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 поля действительно доступны, но этот код не подлежит проверке видимости.

Другие вопросы по тегам