Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/331.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/rest/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 带句柄的PInvoke结构的一次性包装器类_C#_Winapi_Pinvoke_Marshalling_Dispose - Fatal编程技术网

C# 带句柄的PInvoke结构的一次性包装器类

C# 带句柄的PInvoke结构的一次性包装器类,c#,winapi,pinvoke,marshalling,dispose,C#,Winapi,Pinvoke,Marshalling,Dispose,在阅读我的一些PInvoke代码时,我发现它使用了一个特殊的类来确保正确处理结构句柄,因为调用者应该关闭这些句柄: 进程信息中的句柄必须在以下情况下使用CloseHandle关闭: 他们不再需要了 使用CreateProcess作为: [DllImport(DllNames.Kernel32, CharSet = CharSet.Unicode, EntryPoint = "CreateProcess")] [return: MarshalAs(UnmanagedType.Bool)] publ

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

进程信息中的句柄必须在以下情况下使用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);
处理信息\u可处置包装

[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;
    }
}
因此,它可以使用(通过方便的伸缩过载)如下:

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

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

可能是使用
PROCESS\u INFORMATION
中的
SafeHandle
字段,而不是
IntPtr
,但这对我不起作用(handle字段变为null)


作为旁注,您不应该在
Dispose(bool isDisposing)
中设置
\u isDisposed=true
,您应该在
Dispose()
中设置它。如果是终结器调用
Dispose(false)
你根本不关心这个标志,将终结器代码减少到最小总是一个好主意……你的处境不稳。创建一个类
类ProcessInformation\u SafeHandle:SafeHandle
,这个类提供
进程信息的IntPtr句柄,从该句柄提取struct以获取
ProcessInformation
值。如果重写ReleaseHandle,则必须同时关闭
hThread
hProcess
,如果两者都成功关闭,则应返回true,否则返回false。此方法不应引发异常。此外,您还应该重写
IsInvalid
属性,该属性将确定句柄是否无效或已关闭。@M.kazemAkhgary它可能会工作,并且似乎比当前的解决方案更好。也许你可以制作一个原型,并把它作为一个答案添加进去?我无法测试它是否有效。如果你能以这种方式或其他方式回答自己的问题,我很高兴知道,我也会投赞成票;)作为旁注,您不应该在
Dispose(bool isDisposing)
中设置
\u isDisposed=true
,您应该在
Dispose()
中设置它。如果是终结器调用
Dispose(false)
你根本不关心这个标志,将终结器代码减少到最小总是一个好主意……你的处境不稳。创建一个类
类ProcessInformation\u SafeHandle:SafeHandle
,这个类提供
进程信息的IntPtr句柄,从该句柄提取struct以获取
ProcessInformation
值。如果重写ReleaseHandle,则必须同时关闭
hThread
hProcess
,如果两者都成功关闭,则应返回true,否则返回false。此方法不应引发异常。此外,您还应该重写
IsInvalid
属性,该属性将确定句柄是否无效或已关闭。@M.kazemAkhgary它可能会工作,并且似乎比当前的解决方案更好。也许你可以制作一个原型,并把它作为一个答案添加进去?我无法测试它是否有效。如果你能以这种方式或其他方式回答自己的问题,我很高兴知道,我也会投赞成票;)
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);
}
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
    public SafeProcessHandle hProcess;
    public SafeThreadHandle hThread;
    public UInt32 dwProcessId;
    public UInt32 dwThreadId;
}