C# 带句柄的PInvoke结构的一次性包装器类
在阅读我的一些PInvoke代码时,我发现它使用了一个特殊的类来确保正确处理结构句柄,因为调用者应该关闭这些句柄: 进程信息中的句柄必须在以下情况下使用CloseHandle关闭: 他们不再需要了 使用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
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;
}