internal unsafe int WriteFileNative(HandleProtector hp, byte[] bytes, int offset, int count, NativeOverlapped* overlapped, out int hr) { // Don't corrupt memory when multiple threads are erroneously writing // to this stream simultaneously. (Note that the OS is reading from // the array we pass to WriteFile, but if we read beyond the end and // that memory isn't allocated, we could get an AV.) if (bytes.Length - offset < count) throw new IndexOutOfRangeException(InternalResources.GetResourceString("IndexOutOfRange_IORaceCondition")); // You can't use the fixed statement on an array of length 0. if (bytes.Length == 0) { hr = 0; return 0; } int numBytesWritten = 0; int r = 0; bool incremented = false; try { if (hp.TryAddRef(ref incremented)) { fixed (byte* p = bytes) { r = UnsafeNativeMethods.WriteFile(hp.Handle, p + offset, count, NativeMethods.NULL, overlapped); } } else hr = NativeMethods.ERROR_INVALID_HANDLE; // Handle was closed. } finally { if (incremented) hp.Release(); } if (r == 0) { hr = Marshal.GetLastWin32Error(); // Note: we should never silently swallow an error here without some // extra work. We must make sure that BeginWriteCore won't return an // IAsyncResult that will cause EndWrite to block, since the OS won't // call AsyncFSCallback for us. // For invalid handles, detect the error and mark our handle // as closed to give slightly better error messages. Also // help ensure we avoid handle recycling bugs. if (hr == NativeMethods.ERROR_INVALID_HANDLE) _handleProtector.ForciblyMarkAsClosed(); return -1; } else hr = 0; return numBytesWritten; }