I have created a MemoryMappedFile using C#.Net Compact Framework on WinCE7. When I am trying to open the same MemorymappedFile in another process, I am getting a null file handle.
Here is the code I am using.
namespace MMFWriteDemo
{
[Serializable]
public class FileMapIOException : IOException
{
private int m_win32Error;
public int Win32ErrorCode
{
get { return m_win32Error; }
}
public override string Message
{
get
{
if (Win32ErrorCode != 0)
return base.Message + " (" + Win32ErrorCode + ")";
return base.Message;
}
}
public FileMapIOException(int error)
: base()
{
m_win32Error = error;
}
public FileMapIOException(string message)
: base(message)
{
}
public FileMapIOException(string message, Exception innerException)
: base(message, innerException)
{
}
} // class FileMapIOException
public enum MapAccess
{
FileMapCopy = 0x0001,
FileMapWrite = 0x0002,
FileMapRead = 0x0004,
FileMapAllAccess = 0x001f,
}
[Flags]
public enum MapProtection
{
PageNone = 0x00000000,
// protection - mutually exclusive, do not or
PageReadOnly = 0x00000002,
PageReadWrite = 0x00000004,
PageWriteCopy = 0x00000008,
// attributes - or-able with protection
SecImage = 0x01000000,
SecReserve = 0x04000000,
SecCommit = 0x08000000,
SecNoCache = 0x10000000,
}
internal class Win32MapApis
{
[DllImport("coredll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr CreateFile(
String lpFileName, int dwDesiredAccess, int dwShareMode,
IntPtr lpSecurityAttributes, int dwCreationDisposition,
int dwFlagsAndAttributes, IntPtr hTemplateFile);
[DllImport("coredll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr CreateFileMapping(
IntPtr hFile, IntPtr lpAttributes, int flProtect,
int dwMaximumSizeLow, int dwMaximumSizeHigh,
String lpName);
[DllImport("coredll", SetLastError = true)]
public static extern bool FlushViewOfFile(
IntPtr lpBaseAddress, IntPtr dwNumBytesToFlush);
[DllImport("coredll", SetLastError = true)]
public static extern IntPtr MapViewOfFile(
IntPtr hFileMappingObject, int dwDesiredAccess, int dwFileOffsetHigh,
int dwFileOffsetLow, IntPtr dwNumBytesToMap);
//[DllImport("coredll", SetLastError = true, CharSet = CharSet.Auto)]
//public static extern IntPtr OpenFileMapping(
// int dwDesiredAccess, bool bInheritHandle, String lpName);
public static IntPtr OpenFileMapping(uint dwDesiredAccess, bool bInheritHandle, string lpName)
{
IntPtr t_pHandle = Win32MapApis.CreateFileMapping(new IntPtr(-1), IntPtr.Zero, (int)MapAccess.FileMapRead, 0, 0, lpName);
return t_pHandle;
}
[DllImport("coredll", SetLastError = true)]
public static extern bool UnmapViewOfFile(IntPtr lpBaseAddress);
[DllImport("coredll", SetLastError = true)]
public static extern bool CloseHandle(IntPtr handle);
[DllImport("coredll.dll", SetLastError = true)]
public static extern Int32 GetLastError();
} // class Win32MapApis
public class MemoryMappedFile : MarshalByRefObject, IDisposable
{
//! handle to MemoryMappedFile object
private IntPtr _hMap = IntPtr.Zero;
private MapProtection _protection = MapProtection.PageNone;
private string _fileName = "";
public string FileName { get { return _fileName; } }
private long _maxSize;
private readonly bool _is64bit;
public long MaxSize { get { return _maxSize; } }
#region Constants
private const int GENERIC_READ = unchecked((int)0x80000000);
private const int GENERIC_WRITE = unchecked((int)0x40000000);
private const int OPEN_ALWAYS = 4;
private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
private static readonly IntPtr NULL_HANDLE = IntPtr.Zero;
#endregion // Constants
#region Properties
public bool IsOpen
{
get { return (_hMap != NULL_HANDLE); }
}
public bool Is64bit
{
get { return _is64bit; }
}
private MemoryMappedFile()
{
_is64bit = IntPtr.Size == 8;
}
~MemoryMappedFile()
{
Dispose(false);
}
#region Create Overloads
public static MemoryMappedFile
Create(MapProtection protection, long maxSize, string name)
{
return Create(null, protection, maxSize, name);
}
public static MemoryMappedFile
Create(MapProtection protection, long maxSize)
{
return Create(null, protection, maxSize, null);
}
public static MemoryMappedFile
Create(string fileName, MapProtection protection)
{
return Create(fileName, protection, 0, null);
}
public static MemoryMappedFile
Create(string fileName, MapProtection protection,
long maxSize)
{
return Create(fileName, protection, maxSize, null);
}
public static MemoryMappedFile
Create(string fileName, MapProtection protection,
long maxSize, String name)
{
MemoryMappedFile map = new MemoryMappedFile();
if (!map.Is64bit && maxSize > uint.MaxValue)
throw new ConstraintException("32bit systems support max size of 4gb.");
// open file first
IntPtr hFile = INVALID_HANDLE_VALUE;
if (!string.IsNullOrEmpty(fileName))
{
if (maxSize == 0)
{
if (!File.Exists(fileName))
{
throw new Exception(string.Format("Winterdom.IO.FileMap.MemoryMappedFile.Create - \"{0}\" does not exist ==> Unable to map entire file", fileName));
}
FileInfo backingFileInfo = new FileInfo(fileName);
maxSize = backingFileInfo.Length;
if (maxSize == 0)
{
throw new Exception(string.Format("Winterdom.IO.FileMap.MemoryMappedFile.Create - \"{0}\" is zero bytes ==> Unable to map entire file", fileName));
}
}
// determine file access needed
// we'll always need generic read access
int desiredAccess = GENERIC_READ;
if ((protection == MapProtection.PageReadWrite) ||
(protection == MapProtection.PageWriteCopy))
{
desiredAccess |= GENERIC_WRITE;
}
// open or create the file
// if it doesn't exist, it gets created
hFile = Win32MapApis.CreateFile(
fileName, desiredAccess, 0,
IntPtr.Zero, OPEN_ALWAYS, 0, IntPtr.Zero
);
if (hFile == INVALID_HANDLE_VALUE)
//throw new FileMapIOException(Marshal.GetHRForLastWin32Error());
throw new FileMapIOException("MMF");
map._fileName = fileName;
}
map._hMap = Win32MapApis.CreateFileMapping(
hFile, IntPtr.Zero, (int)protection,
(int)((maxSize >> 32) & 0xFFFFFFFF),
(int)(maxSize & 0xFFFFFFFF), "unique"
);
// close file handle, we don't need it
if (hFile != INVALID_HANDLE_VALUE) Win32MapApis.CloseHandle(hFile);
if (map._hMap == NULL_HANDLE)
//throw new FileMapIOException(Marshal.GetHRForLastWin32Error());
throw new FileMapIOException("MMF");
map._protection = protection;
map._maxSize = maxSize;
return map;
}
#endregion // Create Overloads
public static MemoryMappedFile Open(MapAccess access, String name)
{
MemoryMappedFile map = new MemoryMappedFile
{
_hMap = Win32MapApis.OpenFileMapping((uint)access, false, name)
};
if (map._hMap == NULL_HANDLE)
throw new FileMapIOException("MMF");
//throw new FileMapIOException(Marshal.GetHRForLastWin32Error());
map._maxSize = -1; // debug unknown
return map;
}
public void Close()
{
Dispose(true);
}
public IntPtr MapView(MapAccess access, long offset, long size)
{
if (!IsOpen)
throw new ObjectDisposedException("Winterdom.IO.FileMap.MemoryMappedFile.MapView - MMF already closed");
// Throws OverflowException if (a) this is a 32-bit platform AND (b) size is out of bounds (ie. int bounds) with respect to this platform
IntPtr mapSize = new IntPtr(size);
IntPtr baseAddress = Win32MapApis.MapViewOfFile(
_hMap, (int)access,
(int)((offset >> 32) & 0xFFFFFFFF),
(int)(offset & 0xFFFFFFFF), mapSize
);
if (baseAddress == IntPtr.Zero)
throw new FileMapIOException("MMF");
//throw new FileMapIOException(Marshal.GetHRForLastWin32Error());
return baseAddress;
}
public MapViewStream MapAsStream()
{
if (!IsOpen)
throw new ObjectDisposedException("Winterdom.IO.FileMap.MemoryMappedFile.MapView - MMF already closed");
// sws should verify against _protection
// Don't know what to do about FILE_MAP_COPY et al
bool isWriteable = (_protection & MapProtection.PageReadWrite) == MapProtection.PageReadWrite;
return new MapViewStream(this, MaxSize, isWriteable);
}
public void UnMapView(IntPtr mapBaseAddr)
{
Win32MapApis.UnmapViewOfFile(mapBaseAddr);
}
public void UnMapView(MapViewStream mappedViewStream)
{
UnMapView(mappedViewStream.ViewBaseAddr);
}
public void Flush(IntPtr viewBaseAddr)
{
// Throws OverflowException if (a) this is a 32-bit platform AND (b) size is out of bounds (ie. int bounds) with respect to this platform
IntPtr flushLength = new IntPtr(MaxSize);
Win32MapApis.FlushViewOfFile(viewBaseAddr, flushLength);
}
public void Flush(MapViewStream mappedViewStream)
{
Flush(mappedViewStream.ViewBaseAddr);
}
#region IDisposable implementation
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (IsOpen)
Win32MapApis.CloseHandle(_hMap);
_hMap = NULL_HANDLE;
if (disposing)
GC.SuppressFinalize(this);
}
#endregion // IDisposable implementation
} // class MemoryMappedFile
public class MapViewStream : Stream, IDisposable
{
#region Map/View Related Fields
protected MemoryMappedFile _backingFile;
protected MapAccess _access = MapAccess.FileMapWrite;
protected bool _isWriteable;
IntPtr _viewBaseAddr = IntPtr.Zero; // Pointer to the base address of the currently mapped view
protected long _mapSize;
protected long _viewStartIdx = -1;
protected long _viewSize = -1;
long _position; //! our current position in the stream buffer
#region Properties
public IntPtr ViewBaseAddr
{
get { return _viewBaseAddr; }
}
public bool IsViewMapped
{
get { return (_viewStartIdx != -1) && (_viewStartIdx + _viewSize) <= (_mapSize); }
}
#endregion
#endregion // Map/View Related Fields
#region Map / Unmap View
#region Unmap View
protected void UnmapView()
{
if (IsViewMapped)
{
_backingFile.UnMapView(this);
_viewStartIdx = -1;
_viewSize = -1;
}
}
#endregion
#region Map View
protected void MapView(ref long viewStartIdx, ref long viewSize)
{
// Now map the view
_viewBaseAddr = _backingFile.MapView(_access, viewStartIdx, viewSize);
_viewStartIdx = viewStartIdx;
_viewSize = viewSize;
}
#endregion
#endregion
#region Constructors
internal MapViewStream(MemoryMappedFile backingFile, long mapSize, bool isWriteable)
{
if (backingFile == null)
{
throw new Exception("MapViewStream.MapViewStream - backingFile is null");
}
if (!backingFile.IsOpen)
{
throw new Exception("MapViewStream.MapViewStream - backingFile is not open");
}
if ((mapSize < 1) || (mapSize > backingFile.MaxSize))
{
throw new Exception(string.Format("MapViewStream.MapViewStream - mapSize is invalid. mapSize == {0}, backingFile.MaxSize == {1}", mapSize, backingFile.MaxSize));
}
_backingFile = backingFile;
_isWriteable = isWriteable;
_access = isWriteable ? MapAccess.FileMapWrite : MapAccess.FileMapRead;
// Need a backingFile.SupportsAccess function that takes a MapAccess compares it against its stored MapProtection protection and returns bool
_mapSize = mapSize;
_isOpen = true;
// Map the first view
Seek(0, SeekOrigin.Begin);
}
#endregion
#region Stream Properties
public override bool CanRead
{
get { return true; }
}
public override bool CanSeek
{
get { return true; }
}
public override bool CanWrite
{
get { return _isWriteable; }
}
public override long Length
{
get { return _mapSize; }
}
public override long Position
{
get { return _position; }
set { Seek(value, SeekOrigin.Begin); }
}
#endregion // Stream Properties
#region Stream Methods
public override void Flush()
{
if (!IsOpen)
throw new ObjectDisposedException("Winterdom.IO.FileMap.MapViewStream.Flush - Stream is closed");
// flush the view but leave the buffer intact
_backingFile.Flush(this);
}
public override int Read(byte[] buffer, int offset, int count)
{
if (!IsOpen)
throw new ObjectDisposedException("Stream is closed");
if (buffer.Length - offset < count)
throw new ArgumentException("Invalid Offset");
int bytesToRead = (int)Math.Min(Length - _position, count);
Marshal.Copy((IntPtr)(_viewBaseAddr.ToInt64() + _position), buffer, offset, bytesToRead);
_position += bytesToRead;
return bytesToRead;
}
public override void Write(byte[] buffer, int offset, int count)
{
if (!IsOpen)
throw new ObjectDisposedException("Stream is closed");
if (!CanWrite)
throw new FileMapIOException("Stream cannot be written to");
if (buffer.Length - offset < count)
throw new ArgumentException("Invalid Offset");
int bytesToWrite = (int)Math.Min(Length - _position, count);
if (bytesToWrite == 0)
return;
Marshal.Copy(buffer, offset, (IntPtr)(_viewBaseAddr.ToInt64() + _position), bytesToWrite);
_position += bytesToWrite;
}
public override long Seek(long offset, SeekOrigin origin)
{
if (!IsOpen)
throw new ObjectDisposedException("Stream is closed");
long newpos = 0;
switch (origin)
{
case SeekOrigin.Begin: newpos = offset; break;
case SeekOrigin.Current: newpos = Position + offset; break;
case SeekOrigin.End: newpos = Length + offset; break;
}
// sanity check
if (newpos < 0 || newpos > Length)
throw new FileMapIOException("Invalid Seek Offset");
_position = newpos;
if (!IsViewMapped)
{
MapView(ref newpos, ref _mapSize); // use _mapsize here??
}
return newpos;
}
public override void SetLength(long value)
{
// not supported!
throw new NotSupportedException("Winterdom.IO.FileMap.MapViewStream.SetLength - Can't change map size");
}
public override void Close()
{
Dispose(true);
}
#endregion // Stream methods
#region IDisposable Implementation
private bool _isOpen;
public bool IsOpen { get { return _isOpen; } }
public new void Dispose()
{
Dispose(true);
}
protected new virtual void Dispose(bool disposing)
{
if (IsOpen)
{
Flush();
UnmapView();
_isOpen = false;
}
if (disposing)
GC.SuppressFinalize(this);
}
~MapViewStream()
{
Dispose(false);
}
#endregion // IDisposable Implementation
} // class MapViewStream
public class GenericMemoryMappedArray<TValue> : IDisposable, IEnumerable<TValue>
where TValue : struct
{
#region Private fields
private string _path;
private string _fileName;
private string _uniqueName = "mmf-" + "12345Test";//Guid.NewGuid();
private long _fileSize;
private MemoryMappedFile _map;
private int _dataSize;
private bool _deleteFile = true;
private byte[] _buffer;
private IntPtr _memPtr;
private bool _autogrow = true;
private Dictionary<int, MapViewStream> _inUse = new Dictionary<int, MapViewStream>(10);
private Dictionary<int, DateTime> _lastUsedThread = new Dictionary<int, DateTime>();
private readonly object _lockObject = new object();
//private Timer _pooltimer;
private bool _isDisposed;
#endregion
#region Properties
public string UniqueName
{
get { return _uniqueName; }
set { _uniqueName = value; }
}
public long Length
{
get
{
return _fileSize / _dataSize;
}
}
public long Position
{
set
{
int threadId = Thread.CurrentThread.ManagedThreadId;
_lastUsedThread[threadId] = DateTime.UtcNow;
Stream s = GetView(threadId);
s.Position = value * _dataSize;
}
}
public bool AutoGrow
{
get { return _autogrow; }
set { _autogrow = value; }
}
public override string ToString()
{
return string.Format("Length {0}", Length);
}
#endregion
#region Constructor
public GenericMemoryMappedArray(long size, string path)
{
_path = path;
_fileName = Path.Combine(path, _uniqueName + ".bin");
//_fileName = Path.Combine(path, "mmfTest.bin");
// Get the size of TValue
_dataSize = Marshal.SizeOf(typeof(TValue));
// Allocate a global buffer for this instance
_buffer = new byte[_dataSize];
// Allocate a global unmanaged buffer for this instance
_memPtr = Marshal.AllocHGlobal(_dataSize);
SetFileSize(size);
}
#endregion
#region Finalizer
~GenericMemoryMappedArray()
{
Dispose(false);
}
#endregion
#region Private methods
private Stream GetView(int threadId)
{
MapViewStream s;
if (!_inUse.TryGetValue(threadId, out s))
{
// create new view and add to pool
MapViewStream mvs = _map.MapAsStream();
lock (_lockObject)
{
_inUse.Add(threadId, mvs);
}
return mvs;
}
return s;
}
private void SetFileSize(long size)
{
_fileSize = _dataSize * size;
_map = MemoryMappedFile.Create(_fileName, MapProtection.PageReadWrite, _fileSize);
}
#endregion
#region Public methods
public void Write(byte[] buffer)
{
int threadId = Thread.CurrentThread.ManagedThreadId;
_lastUsedThread[threadId] = DateTime.UtcNow;
Stream s = GetView(threadId);
s.Write(buffer, 0, buffer.Length);
}
public void WriteByte(byte b)
{
int threadId = Thread.CurrentThread.ManagedThreadId;
_lastUsedThread[threadId] = DateTime.UtcNow;
Stream s = GetView(threadId);
byte[] buffer = new byte[1] { b };
s.Write(buffer, 0, 1);
}
public int Read()
{
int threadId = Thread.CurrentThread.ManagedThreadId;
_lastUsedThread[threadId] = DateTime.UtcNow;
Stream s = GetView(threadId);
int count = s.Read(_buffer, 0, _buffer.Length);
return count;
}
public byte ReadByte()
{
int threadId = Thread.CurrentThread.ManagedThreadId;
Stream s = GetView(threadId);
return (byte)s.ReadByte();
}
public TValue this[long index]
{
get
{
lock (this)
{
if (index >= Length)
{
throw new ArgumentOutOfRangeException("index", "Tried to access item outside the array boundaries");
}
Position = index;
Read();
TValue value = ConvertToTValue();
return value;
}
}
set
{
lock (this)
{
if (index >= Length)
{
if (_autogrow)
Grow(index, 10);
else
{
throw new ArgumentOutOfRangeException("index", "Tried to access item outside the array");
}
}
Position = index;
ConvertToBytes(value);
Write(_buffer);
}
}
}
private void ConvertToBytes(TValue value)
{
// Could set the last parameter to false if TValue only contains value types
// Safer to leave it to true for all purposes.
Marshal.StructureToPtr(value, _memPtr, true);
Marshal.Copy(_memPtr, _buffer, 0, _dataSize);
}
private TValue ConvertToTValue()
{
Marshal.Copy(_buffer, 0, _memPtr, _dataSize);
object obj = Marshal.PtrToStructure(_memPtr, typeof(TValue));
return (TValue)obj;
}
private void Grow(long size, int percentage)
{
_deleteFile = false;
lock (_lockObject)
{
Dispose(true);
long oldSize = _fileSize;
_fileSize = (long)((float)size * _dataSize * ((100F + percentage) / 100F)); //required filesize
if (_fileSize < (oldSize + _dataSize))
{
_fileSize = oldSize + _dataSize;
}
_map = MemoryMappedFile.Create(_fileName, MapProtection.PageReadWrite, _fileSize);
}
}
#endregion
#region Clone Members
public GenericMemoryMappedArray<TValue> Clone()
{
string copyName = _uniqueName + Guid.NewGuid();
string currentPath = Path.Combine(_path, copyName + ".bin");
File.Copy(_fileName, currentPath);
GenericMemoryMappedArray<TValue> current = new GenericMemoryMappedArray<TValue>(Length, currentPath);
return current;
}
#endregion
#region IDisposable Members
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_isDisposed && disposing)
{
lock (_lockObject)
{
// Clean up all views
foreach (KeyValuePair<int, MapViewStream> pair in _inUse)
{
pair.Value.Dispose();
pair.Value.Close();
}
_inUse.Clear();
_lastUsedThread.Clear();
}
if (_map != null)
{
_map.Close();
}
}
try
{
if (_deleteFile)
{
Marshal.DestroyStructure(_memPtr, typeof(TValue)); // Clear unmanaged buffer data
Marshal.FreeHGlobal(_memPtr); // Free unmanaged buffer
if (File.Exists(_fileName)) File.Delete(_fileName);
}
}
catch (Exception)
{
// TODO: Handle files which for some reason didn't want to be deleted
throw;
}
_deleteFile = true;
}
#endregion
#region IEnumerable<TValue> Members
public IEnumerator<TValue> GetEnumerator()
{
lock (this)
{
Position = 0;
for (int i = 0; i < Length; i++)
{
Read();
yield return ConvertToTValue();
}
}
}
#endregion
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
}
Application for creating the memory mapped file and writing to it, this works OK.
namespace MMFWriteDemo
{
class Program
{
static void Main(string[] args)
{
GenericMemoryMappedArray<byte> mmfTest = new GenericMemoryMappedArray<byte>(1024 * 1024 * 8, @"internal\data");
int i = 0;
byte b = 0;
while (i < 1000)
{
mmfTest.WriteByte(b);
b++;
if (b == 255)
{
b = 0;
}
i++;
}
Console.ReadLine();
}
}
}
This works good, i can see the file created and I can write to it.
Application for opening the memory mapped file and reading from it, it does not work.
namespace MMFReaderDemo
{
class Program
{
static void Main(string[] args)
{
GenericMemoryMappedArray<byte> mmfTest = new GenericMemoryMappedArray<byte>(1024 * 1024 * 8, @"internal\data");
int i = 0;
while (i < 100)
{
Console.WriteLine(mmfTest.ReadByte());
i++;
}
}
}
}
ErrorCode: 0x80000005
Actually I am trying to share the memory mapped file between driver(written in C++) and user app(written in C#).
User contributions licensed under CC BY-SA 3.0