编组 Win32 结构时的安全句柄 (PROCESS_INFORMATION)
Posted
技术标签:
【中文标题】编组 Win32 结构时的安全句柄 (PROCESS_INFORMATION)【英文标题】:Safe Handles when marshaling Win32 structs (PROCESS_INFORMATION) 【发布时间】:2016-01-09 05:27:55 【问题描述】:我正在将我的 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 结构中使用它们。
我是否缺少某种注释魔法?
【问题讨论】:
我对.net一无所知,但只是看看SafeHandle
类,它的构造函数有两个参数(一个IntPtr
和一个bool
表示所有权)。我不确定编组器如何知道 bool
是真还是假。
好点。我已经尝试让我的SafeHandle
子类中的构造函数只采用IntPtr
(假设true
总是用于布尔)。不幸的是,仍然没有骰子。
只是不要试图把它全部敲进一个洞里。使用两个声明,一个将 just 用于互操作调用,另一个(通常是一个类)用于存储安全句柄。对比framework does it的方式,注意最后对SetProcessHandle的调用。
@JonathanPotter,编组器使用默认构造函数,并且具有 SafeHandle 的特殊知识,允许它设置句柄。 SafeHandle 的特定子类应提供一个默认构造函数,该构造函数传入一个合适的布尔值。
@Erik_at_Digit,您是否使用代表无效句柄的实例预先填充了句柄字段?我发现我需要预先填充用于 ref 参数的 SafeHandle 变量,结构可能有相同的要求。
【参考方案1】:
据我所知*,互操作封送拆收器不支持在类/结构中使用 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 上有所改变;我的知识有点过时了。
【讨论】:
谢谢,完全忘记了SafeWaitHandle
。使我不必编写子类。不幸的是,内置的Process
类没有公开任何访问进程内存的方法(ReadProcessMemory
或WriteProcessMemory
)。我创建了一个包装这些方法的流子类。此外,内置的Process
类不允许您创建带有标志的进程(如挂起)。所以我必须为此使用CreateProcess
Win32 API。以上是关于编组 Win32 结构时的安全句柄 (PROCESS_INFORMATION)的主要内容,如果未能解决你的问题,请参考以下文章