public static MemoryMappedFile CreateFromFile(string path, FileMode mode, string mapName, long capacity, MemoryMappedFileAccess access) { if (path == null) { throw new ArgumentNullException(nameof(path)); } if (mapName != null && mapName.Length == 0) { throw new ArgumentException(SR.Argument_MapNameEmptyString); } if (capacity < 0) { throw new ArgumentOutOfRangeException(nameof(capacity), SR.ArgumentOutOfRange_PositiveOrDefaultCapacityRequired); } if (access < MemoryMappedFileAccess.ReadWrite || access > MemoryMappedFileAccess.ReadWriteExecute) { throw new ArgumentOutOfRangeException(nameof(access)); } if (mode == FileMode.Append) { throw new ArgumentException(SR.Argument_NewMMFAppendModeNotAllowed, nameof(mode)); } if (access == MemoryMappedFileAccess.Write) { throw new ArgumentException(SR.Argument_NewMMFWriteAccessNotAllowed, nameof(access)); } bool existed = File.Exists(path); FileStream fileStream = new FileStream(path, mode, GetFileAccess(access), FileShare.Read, 0x1000, FileOptions.None); if (capacity == 0 && fileStream.Length == 0) { CleanupFile(fileStream, existed, path); throw new ArgumentException(SR.Argument_EmptyFile); } if (access == MemoryMappedFileAccess.Read && capacity > fileStream.Length) { CleanupFile(fileStream, existed, path); throw new ArgumentException(SR.Argument_ReadAccessWithLargeCapacity); } if (capacity == DefaultSize) { capacity = fileStream.Length; } // one can always create a small view if they do not want to map an entire file if (fileStream.Length > capacity) { CleanupFile(fileStream, existed, path); throw new ArgumentOutOfRangeException(nameof(capacity), SR.ArgumentOutOfRange_CapacityGEFileSizeRequired); } SafeMemoryMappedFileHandle handle = null; try { handle = CreateCore(fileStream, mapName, HandleInheritability.None, access, MemoryMappedFileOptions.None, capacity); } catch { CleanupFile(fileStream, existed, path); throw; } Debug.Assert(handle != null); Debug.Assert(!handle.IsInvalid); return(new MemoryMappedFile(handle, fileStream, false)); }
public static MemoryMappedFile CreateFromFile(FileStream fileStream, string mapName, long capacity, MemoryMappedFileAccess access, HandleInheritability inheritability, bool leaveOpen) { if (fileStream == null) { throw new ArgumentNullException(nameof(fileStream), SR.ArgumentNull_FileStream); } if (mapName != null && mapName.Length == 0) { throw new ArgumentException(SR.Argument_MapNameEmptyString); } if (capacity < 0) { throw new ArgumentOutOfRangeException(nameof(capacity), SR.ArgumentOutOfRange_PositiveOrDefaultCapacityRequired); } if (capacity == 0 && fileStream.Length == 0) { throw new ArgumentException(SR.Argument_EmptyFile); } if (access < MemoryMappedFileAccess.ReadWrite || access > MemoryMappedFileAccess.ReadWriteExecute) { throw new ArgumentOutOfRangeException(nameof(access)); } if (access == MemoryMappedFileAccess.Write) { throw new ArgumentException(SR.Argument_NewMMFWriteAccessNotAllowed, nameof(access)); } if (access == MemoryMappedFileAccess.Read && capacity > fileStream.Length) { throw new ArgumentException(SR.Argument_ReadAccessWithLargeCapacity); } if (inheritability < HandleInheritability.None || inheritability > HandleInheritability.Inheritable) { throw new ArgumentOutOfRangeException(nameof(inheritability)); } // flush any bytes written to the FileStream buffer so that we can see them in our MemoryMappedFile fileStream.Flush(); if (capacity == DefaultSize) { capacity = fileStream.Length; } // one can always create a small view if they do not want to map an entire file if (fileStream.Length > capacity) { throw new ArgumentOutOfRangeException(nameof(capacity), SR.ArgumentOutOfRange_CapacityGEFileSizeRequired); } SafeMemoryMappedFileHandle handle = CreateCore(fileStream, mapName, inheritability, access, MemoryMappedFileOptions.None, capacity); return(new MemoryMappedFile(handle, fileStream, leaveOpen)); }
public unsafe static MemoryMappedView CreateView(SafeMemoryMappedFileHandle memMappedFileHandle, MemoryMappedFileAccess access, long offset, long size) { // MapViewOfFile can only create views that start at a multiple of the system memory allocation // granularity. We decided to hide this restriction from the user by creating larger views than the // user requested and hiding the parts that the user did not request. extraMemNeeded is the amount of // extra memory we allocate before the start of the requested view. MapViewOfFile will also round the // capacity of the view to the nearest multiple of the system page size. Once again, we hide this // from the user by preventing them from writing to any memory that they did not request. ulong nativeSize; long extraMemNeeded, newOffset; ValidateSizeAndOffset( size, offset, GetSystemPageAllocationGranularity(), out nativeSize, out extraMemNeeded, out newOffset); // if request is >= than total virtual, then MapViewOfFile will fail with meaningless error message // "the parameter is incorrect"; this provides better error message in advance Interop.mincore.MEMORYSTATUSEX memStatus; memStatus.dwLength = (uint)sizeof(Interop.mincore.MEMORYSTATUSEX); Interop.mincore.GlobalMemoryStatusEx(out memStatus); ulong totalVirtual = memStatus.ullTotalVirtual; if (nativeSize >= totalVirtual) { throw new IOException(SR.IO_NotEnoughMemory); } // split the long into two ints int offsetLow = unchecked ((int)(newOffset & 0x00000000FFFFFFFFL)); int offsetHigh = unchecked ((int)(newOffset >> 32)); // create the view SafeMemoryMappedViewHandle viewHandle = Interop.mincore.MapViewOfFile(memMappedFileHandle, (int)MemoryMappedFile.GetFileMapAccess(access), offsetHigh, offsetLow, new UIntPtr(nativeSize)); if (viewHandle.IsInvalid) { viewHandle.Dispose(); throw Win32Marshal.GetExceptionForLastWin32Error(); } // Query the view for its size and allocation type Interop.mincore.MEMORY_BASIC_INFORMATION viewInfo = new Interop.mincore.MEMORY_BASIC_INFORMATION(); Interop.mincore.VirtualQuery(viewHandle, ref viewInfo, (UIntPtr)Marshal.SizeOf(viewInfo)); ulong viewSize = (ulong)viewInfo.RegionSize; // Allocate the pages if we were using the MemoryMappedFileOptions.DelayAllocatePages option // OR check if the allocated view size is smaller than the expected native size // If multiple overlapping views are created over the file mapping object, the pages in a given region // could have different attributes(MEM_RESERVE OR MEM_COMMIT) as MapViewOfFile preserves coherence between // views created on a mapping object backed by same file. // In which case, the viewSize will be smaller than nativeSize required and viewState could be MEM_COMMIT // but more pages may need to be committed in the region. // This is because, VirtualQuery function(that internally invokes VirtualQueryEx function) returns the attributes // and size of the region of pages with matching attributes starting from base address. // VirtualQueryEx: http://msdn.microsoft.com/en-us/library/windows/desktop/aa366907(v=vs.85).aspx if (((viewInfo.State & Interop.mincore.MemOptions.MEM_RESERVE) != 0) || ((ulong)viewSize < (ulong)nativeSize)) { IntPtr tempHandle = Interop.mincore.VirtualAlloc( viewHandle, (UIntPtr)(nativeSize != MemoryMappedFile.DefaultSize ? nativeSize : viewSize), Interop.mincore.MemOptions.MEM_COMMIT, MemoryMappedFile.GetPageAccess(access)); int lastError = Marshal.GetLastWin32Error(); if (viewHandle.IsInvalid) { viewHandle.Dispose(); throw Win32Marshal.GetExceptionForWin32Error(lastError); } // again query the view for its new size viewInfo = new Interop.mincore.MEMORY_BASIC_INFORMATION(); Interop.mincore.VirtualQuery(viewHandle, ref viewInfo, (UIntPtr)Marshal.SizeOf(viewInfo)); viewSize = (ulong)viewInfo.RegionSize; } // if the user specified DefaultSize as the size, we need to get the actual size if (size == MemoryMappedFile.DefaultSize) { size = (long)(viewSize - (ulong)extraMemNeeded); } else { Debug.Assert(viewSize >= (ulong)size, "viewSize < size"); } viewHandle.Initialize((ulong)size + (ulong)extraMemNeeded); return(new MemoryMappedView(viewHandle, extraMemNeeded, size, access)); }