public MyFileReader(String fileName) { // Security permission check. String fullPath = Path.GetFullPath(fileName); new FileIOPermission(FileIOPermissionAccess.Read, fullPath).Demand(); // Open a file, and save its handle in _handle. // Note that the most optimized code turns into two processor // instructions: 1) a call, and 2) moving the return value into // the _handle field. With SafeHandle, the CLR's platform invoke // marshaling layer will store the handle into the SafeHandle // object in an atomic fashion. There is still the problem // that the SafeHandle object may not be stored in _handle, but // the real operating system handle value has been safely stored // in a critical finalizable object, ensuring against leaking // the handle even if there is an asynchronous exception. MySafeFileHandle tmpHandle; tmpHandle = NativeMethods.CreateFile(fileName, NativeMethods.GENERIC_READ, FileShare.Read, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero); // An async exception here will cause us to run our finalizer with // a null _handle, but MySafeFileHandle's ReleaseHandle code will // be invoked to free the handle. // This call to Sleep, run from the fault injection code in Main, // will help trigger a race. But it will not cause a handle leak // because the handle is already stored in a SafeHandle instance. // Critical finalization then guarantees that freeing the handle, // even during an unexpected AppDomain unload. Thread.Sleep(500); _handle = tmpHandle; // Makes _handle point to a critical finalizable object. // Determine if file is opened successfully. if (_handle.IsInvalid) { throw new Win32Exception(Marshal.GetLastWin32Error(), fileName); } }
internal extern static int ReadFile(MySafeFileHandle handle, byte[] bytes, int numBytesToRead, out int numBytesRead, IntPtr overlapped_MustBeZero);