在阅读我的一些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;
}