我正在将我的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结构中使用它们。
我错过了某种注释魔法吗?
答案 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上有所改变;我的知识有点过时了。