我正在将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; }
}
ProcessSafeHandle
和ThreadSafeHandle
类可与ReadProcessMemory
或WriteProcessMemory
之类的方法配合使用,但是我无法在上述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中已更改;我的知识有点过时了。