c# - 编码(marshal) Win32 结构时的安全句柄 (PROCESS_INFORMATION)

标签 c# winapi pinvoke safehandle

我正在将 Win32 p/invoke 代码转换为使用 SafeHandle 类,而不是典型的 IntPtr 句柄。

虽然在 DllImport 方法签名中一切都工作得很好,但在编码(marshal) 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; }
}

ProcessSafeHandleThreadSafeHandle 类与 ReadProcessMemoryWriteProcessMemory 等方法配合得很好,但我无法使用它们位于像上面这样的 Win32 结构中。

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

最佳答案

据我所知*,互操作编码(marshal)拆收器不支持在类/结构中使用 SafeHandles。

因此,在 P/Invoke 函数声明中将 IntPtr 替换为 SafeHandle 效果很好,但在结构中替换它则不起作用。 PROCESS_INFORMATION 结构中的句柄必须由非托管代码初始化,这些代码对托管 SafeHandle 类一无所知,因此 CLR 需要具备如何初始化的专业知识执行所需的[out] 编码(marshal)处理。

不过不用担心。按原样声明结构没有任何问题:

[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 的公共(public)特化提供。 (说到做额外的工作,我假设您已经检查过以确保 Process 类尚未包含您 P/Invoking 流程 API 的原因?)

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

关于c# - 编码(marshal) Win32 结构时的安全句柄 (PROCESS_INFORMATION),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34690037/

相关文章:

c# - C#如何验证C#私有(private)定义?

c# - 从 DataTable 使用 C# Linq 的 ToDictionary

C#界面如何隐藏代码

c++ - WinApi Window多次创建后异常销毁

winapi - 如何在 Inno Setup 中使用 GetVolumeInformation?

c# - 断言在库初始化期间未被 except block 捕获

c# - 从 WindowsPhone 8.1 调用 GetDiskFreeSpaceExW api

c# - Xunit Assert.Throws 中的异步 lambda 表达式

windows - 如何确定 Windows 单选按钮按钮部分的大小

c++ - Linux 上的 .NET Core - 编码(marshal)结构