具有句柄的PInvoke结构的一次性包装类

时间:2017-01-27 08:46:34

标签: c# winapi pinvoke marshalling dispose

在阅读我的一些PInvoke代码时,我发现CreateProcess使用了一个特殊的类来确保正确处理PROCESS_INFORMATION结构句柄,因为调用者应该关闭它们:

  

PROCESS_INFORMATION中的句柄必须在使用CloseHandle时关闭   他们不再需要了。

CreateProcess为:

[DllImport(DllNames.Kernel32, CharSet = CharSet.Unicode, EntryPoint = "CreateProcess")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern Boolean TryCreateProcess(
    [In] [Optional] String lpApplicationName,
    [In] [Out] [Optional] StringBuilder lpCommandLine,
    [In] ref SECURITY_ATTRIBUTES lpProcessAttributes,
    [In] ref SECURITY_ATTRIBUTES lpThreadAttributes,
    [In] [MarshalAs(UnmanagedType.Bool)] Boolean bInheritHandles,
    [In] ProcessCreationFlags dwCreationFlags,
    [In] [Optional] IntPtr lpEnvironment,
    [In] [Optional] String lpCurrentDirectory,
    [In] ref STARTUPINFO lpStartupInfo,
    [Out] PROCESS_INFORMATION_DisposableWrapper lpProcessInformation);

PROCESS_INFORMATION_DisposableWrapper

[StructLayout(LayoutKind.Sequential)]
public class PROCESS_INFORMATION_DisposableWrapper: IDisposable
{
    private readonly PROCESS_INFORMATION _value;
    private Boolean _isDisposed = false;

    ~PROCESS_INFORMATION_DisposableWrapper()
    {
        this.Dispose(isDisposing: false);
    }

    public PROCESS_INFORMATION Value
    {
        get
        {
            this.ThrowIfDisposed();

            return this._value;
        }
    }

    protected void ThrowIfDisposed()
    {
        if (this._isDisposed)
            throw new ObjectDisposedException("PROCESS_INFORMATION has been already disposed");
    }

    public void Dispose()
    {
        this.Dispose(isDisposing: true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(Boolean isDisposing)
    {
        if (this._isDisposed)
            return;

        System.Console.WriteLine("Disposing");
        // No LastError checking because CreateProcess may fail and those handles will be invalid.
        WinApi.Handle.TryCloseHandle(this.Value.hThread);
        WinApi.Handle.TryCloseHandle(this.Value.hProcess);

        this._isDisposed = true;
    }
}

因此可以使用(通过便利伸缩过载),如:

using (var processData = new WinApi.ProcessAndThread.PROCESS_INFORMATION_DisposableWrapper())
{
    var isCreated = WinApi.ProcessAndThread.TryCreateProcess(
        @"C:\Windows\notepad.exe",
        "",
        creationFlags: WinApi.ProcessAndThread.ProcessCreationFlags.NONE,
        startUpInfo: WinApi.ProcessAndThread.STARTUPINFO.Create(),
        processInformationDisposable: processData);

    Console.WriteLine(isCreated);
}

似乎正确处理/关闭了有效句柄,但我不喜欢_isDisposed标志。我无法摆脱它,所以不要关闭手柄两次,但是它是否是一种可靠的方式来获得确定性和便利的处理我不确定。

所以,问题是:这是一个可靠的解决方案吗?或者,还有更好的方法?

也许SafeHandle中的PROCESS_INFORMATION字段代替IntPtr,但这对我不起作用(句柄字段变为空)。

[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
    public SafeProcessHandle hProcess;
    public SafeThreadHandle hThread;
    public UInt32 dwProcessId;
    public UInt32 dwThreadId;
}

0 个答案:

没有答案