编组Win32结构时的安全句柄(PROCESS_INFORMATION)

时间:2016-01-09 05:27:55

标签: c# winapi pinvoke safehandle

我正在将我的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结构中使用它们。

我错过了某种注释魔法吗?

1 个答案:

答案 0 :(得分:2)

据我所知 * ,interop封送器不支持在类/结构中使用SafeHandles。

因此,在P / Invoke函数声明中将IntPtr替换为SafeHandle可以正常工作,但它不能在结构中替换它。 PROCESS_INFORMATION结构中的句柄必须由非托管代码初始化,该代码对托管SafeHandle类一无所知,因此CLR需要具备如何执行所需操作的专业知识[out]编组。

但不用担心。您对结构的声明没有任何问题:

[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; }
}

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

对于进程句柄(如本例所示),SafeWaitHandle将是一个不错的选择,因为所有进程句柄都是可以等待的。这使您无需进行任何额外的工作,因为SafeWaitHandle已作为SafeHandle的公共专业提供。 (说到做额外的工作,我假设你已经检查过以确保Process课程还没有包含你P / Invoking流程API的原因?)

* 这可能在最新版本的CLR上有所改变;我的知识有点过时了。