2

我正在将我的 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; }
}

ProcessSafeHandleandThreadSafeHandle类与ReadProcessMemoryor之类的方法一起工作得很好WriteProcessMemory,但我不能在上面的 Win32 结构中使用它们。

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

4

1 回答 1

3

据我所知*,互操作封送拆收器不支持在类/结构中使用 SafeHandles。

因此IntPtrSafeHandle在 P/Invoke 函数声明中替换它可以正常工作,但在结构中替换它不起作用。结构中的句柄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结构的函数,就可SafeHandle以为存储在 IntPtrs 中的每个句柄值创建一个对象。这将确保在对象被垃圾收集时关闭句柄(如果您忘记提前调用Dispose())。

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

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

于 2016-01-09T09:10:50.627 回答