封送 Win32 结构时的安全句柄 (PROCESS_INFORMATION)
Safe Handles when marshaling Win32 structs (PROCESS_INFORMATION)
我正在转换我的 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 结构中使用它们.
我是不是漏掉了某种注释魔法?
据我所知*,interop 封送拆收器不支持在 classes/structures.
中使用 SafeHandles
所以在 P/Invoke 函数声明中将 IntPtr
替换为 SafeHandle
效果很好,但在结构中替换它不起作用。 PROCESS_INFORMATION
结构中的句柄必须由对托管 SafeHandle
class 一无所知的非托管代码初始化,因此 CLR 需要具有如何执行操作的专门知识所需的 [out]
编组。
不过不用担心。您对结构 as-is:
的声明没有任何问题
[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
结构的函数,就可以为存储在 IntPtr 中的每个句柄值创建一个 SafeHandle
对象。这将确保在对象被垃圾收集时关闭句柄(如果您忘记早些时候调用 Dispose()
)。
对于进程句柄(如本例所示),SafeWaitHandle
是一个不错的选择,因为所有进程句柄都是可等待的。这使您不必做任何额外的工作,因为 SafeWaitHandle
已经作为 SafeHandle 的 public 专业化提供。 (说到做额外的工作,我假设您已经检查并确保 Process
class 没有包装您是 P/Invoking 进程 API 的原因?)
* 这可能在某些最新版本的 CLR 上发生了变化;我的见识略out-of-date.
我正在转换我的 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 结构中使用它们.
我是不是漏掉了某种注释魔法?
据我所知*,interop 封送拆收器不支持在 classes/structures.
中使用 SafeHandles所以在 P/Invoke 函数声明中将 IntPtr
替换为 SafeHandle
效果很好,但在结构中替换它不起作用。 PROCESS_INFORMATION
结构中的句柄必须由对托管 SafeHandle
class 一无所知的非托管代码初始化,因此 CLR 需要具有如何执行操作的专门知识所需的 [out]
编组。
不过不用担心。您对结构 as-is:
的声明没有任何问题[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
结构的函数,就可以为存储在 IntPtr 中的每个句柄值创建一个 SafeHandle
对象。这将确保在对象被垃圾收集时关闭句柄(如果您忘记早些时候调用 Dispose()
)。
对于进程句柄(如本例所示),SafeWaitHandle
是一个不错的选择,因为所有进程句柄都是可等待的。这使您不必做任何额外的工作,因为 SafeWaitHandle
已经作为 SafeHandle 的 public 专业化提供。 (说到做额外的工作,我假设您已经检查并确保 Process
class 没有包装您是 P/Invoking 进程 API 的原因?)
* 这可能在某些最新版本的 CLR 上发生了变化;我的见识略out-of-date.