我正在将Win32 p / invoke代码转换为使用SafeHandle类而不是典型的IntPtr句柄。

尽管在DllImport方法签名中一切都可以很好地工作,但是当我整理Win32结构(即PROCESS_INFORMATION)时,我无法终生使它们正常工作。

// This works without issue.
[StructLayout(LayoutKind.Sequential)]
internal struct Win32ProcessInformation
{
    public IntPtr ProcessHandle { get; set; }
    public IntPtr ThreadHandle { get; set; }
    public int ProcessId { get; set; }
    public int ThreadId { get; set; }
}

// This does not work!
[StructLayout(LayoutKind.Sequential)]
internal struct Win32ProcessInformation
{
    public ProcessSafeHandle ProcessHandle { get; set; }
    public ThreadSafeHandle ThreadHandle { get; set; }
    public int ProcessId { get; set; }
    public int ThreadId { get; set; }
}


ProcessSafeHandleThreadSafeHandle类可与ReadProcessMemoryWriteProcessMemory之类的方法配合使用,但是我无法在上述Win32结构中使用它们。

我是否缺少某种注释魔术?

最佳答案

据我所知*,互操作封送处理程序不支持在类/结构中使用SafeHandles。

因此,在P / Invoke函数声明中用IntPtr替换SafeHandle可以很好地工作,但是在结构中替换PROCESS_INFORMATION则不起作用。 SafeHandle结构中的句柄必须由对托管[out]类一无所知的非托管代码初始化,因此CLR需要具有如何进行所需的Win32ProcessInformation封送处理的专门知识。

但是不用担心。按原样声明struct没错:

[StructLayout(LayoutKind.Sequential)]
internal struct Win32ProcessInformation
{
    public IntPtr ProcessHandle { get; set; }
    public IntPtr ThreadHandle { get; set; }
    public int ProcessId { get; set; }
    public int ThreadId { get; set; }
}


如果需要,一旦调用了填充SafeHandle结构的函数,就可以为IntPtrs中存储的每个句柄值创建一个Dispose()对象。这样可以确保在垃圾回收对象时关闭句柄(如果您忘记了之前调用SafeWaitHandle的话)。

对于进程句柄(如本例所示),SafeWaitHandle是一个不错的选择,因为所有进程句柄都是可以等待的。这使您不必做任何额外的工作,因为Process已经作为SafeHandle的公共专业名称提供。 (谈到做额外的工作,我假设您已经检查过以确保类尚未包装您使用P /调用流程API的原因?)

*这可能在某些最新版本的CLR中已更改;我的知识有点过时了。

10-08 17:01