MSDN SafeHandle示例

Kar*_*son 8 .net c#

可能是一个愚蠢的问题......我是C#和.Net的新手.

在MSDN上的SafeHandle类(C#)的示例中,代码让我抓狂了一下.

[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);
Run Code Online (Sandbox Code Playgroud)

我的问题是: C函数的Win32 HANDLE如何CreateFile进入MySafeFileHandle受保护的IntPtr"handle"变量对象?构造函数MySafeFileHandle是私有的,甚至不IntPtr作为参数!

CreateFile声明的评论说了些什么

... CLR的平台编组层将以原子方式将句柄存储到SafeHandle对象中.

我不确定我到底知道这意味着什么,有人可以解释一下吗?

Jer*_*ert 4

简短的回答:这很神奇。运行时知道如何正确地将非托管句柄(只是指针大小的值)相互转换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
Run Code Online (Sandbox Code Playgroud)

它发出的将非托管句柄加载到安全句柄中的代码实际上是托管代码,尽管托管代码很高兴地忽略了可访问性。它获取并调用默认构造函数来创建一个新实例:

MethodDesc* pMDCtor = pMT->GetDefaultConstructor();
pslIL->EmitNEWOBJ(pslIL->GetToken(pMDCtor), 0);
pslIL->EmitSTLOC(dwReturnHandleLocal);   
Run Code Online (Sandbox Code Playgroud)

然后直接设置字段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);
Run Code Online (Sandbox Code Playgroud)

构造函数和handle字段实际上都不可访问,但此代码不受可见性检查的约束。

  • @zzxyz:当然——不安全的托管代码可以做任何它想做的事,包括在任意内存上乱写乱画。然而,还需要注意的是,大多数复杂的封送处理并不是用托管代码编写的(甚至不是不安全的),因为它需要以一种有趣的方式与垃圾收集器和托管运行时的状态进行交互。有些东西不能用纯托管代码编写(甚至不安全)并且仍然是正确的。这段封送处理会发出一些托管指令,但我省略了围绕它的一堆有趣的非托管内容。 (2认同)