public static ThreadPoolBoundHandle BindHandle(SafeHandle handle)
{
if (handle == null)
throw new ArgumentNullException(nameof(handle));
if (handle.IsClosed || handle.IsInvalid)
throw new ArgumentException(SR.Argument_InvalidHandle, nameof(handle));
// Make sure we use a statically-rooted completion callback,
// so it doesn't get collected while the I/O is in progress.
Interop.NativeIoCompletionCallback callback = s_nativeIoCompletionCallback;
if (callback == null)
s_nativeIoCompletionCallback = callback = new Interop.NativeIoCompletionCallback(OnNativeIOCompleted);
SafeThreadPoolIOHandle threadPoolHandle = Interop.Kernel32.CreateThreadpoolIo(handle, s_nativeIoCompletionCallback, IntPtr.Zero, IntPtr.Zero);
if (threadPoolHandle.IsInvalid)
{
int hr = Marshal.GetHRForLastWin32Error();
if (hr == System.HResults.E_HANDLE) // Bad handle
throw new ArgumentException(SR.Argument_InvalidHandle, nameof(handle));
if (hr == System.HResults.E_INVALIDARG) // Handle already bound or sync handle
throw new ArgumentException(SR.Argument_AlreadyBoundOrSyncHandle, nameof(handle));
throw Marshal.GetExceptionForHR(hr, new IntPtr(-1));
}
return new ThreadPoolBoundHandle(handle, threadPoolHandle);
}