7

Is there a way to get a direct IntPtr to the data in a MemoryMappedFile? I have large data block with high frequency change and I don't want to copy it

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
ittay
  • 519
  • 5
  • 15

1 Answers1

8

No, not an IntPtr, that doesn't help you anyway. You can get a byte*, you can cast it at will to access the actual data type. And you can cast it to IntPtr if you have to. Having to use the unsafe keyword is quite intentional.

Create a MemoryMappedViewAccessor to create the view on the MMF. Then use the AcquirePointer() method of its SafeMemoryMappedViewHandle property to obtain the byte*.

A sample program that demonstrates the usage and shows various pointer shenanigans:

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

class Program {
    static unsafe void Main(string[] args) {
        using (var mmf = System.IO.MemoryMappedFiles.MemoryMappedFile.CreateNew("test", 42))
        using (var view = mmf.CreateViewAccessor()) {
            byte* poke = null;
            view.SafeMemoryMappedViewHandle.AcquirePointer(ref poke);
            *(int*)poke = 0x12345678;
            Debug.Assert(*poke == 0x78);
            Debug.Assert(*(poke + 1) == 0x56);
            Debug.Assert(*(short*)poke == 0x5678);
            Debug.Assert(*((short*)poke + 1) == 0x1234);
            Debug.Assert(*(short*)(poke + 2) == 0x1234);
            IntPtr ipoke = (IntPtr)poke;
            Debug.Assert(Marshal.ReadInt32(ipoke) == 0x12345678);
            *(poke + 1) = 0xab;
            Debug.Assert(Marshal.ReadInt32(ipoke) == 0x1234ab78);
            view.SafeMemoryMappedViewHandle.ReleasePointer();
        }
    }
}
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • I think you should call `ReleasePointer()`, at least to be sure the GC doesn't free everything in the middle of the code. – xanatos Jul 02 '15 at 09:58
  • And perhaps an abundant use of `using` for the same reason. – xanatos Jul 02 '15 at 10:00
  • Well, as you wish. Under protest, the OP should not be using the *using* statement. This snippet just demonstrates usage. – Hans Passant Jul 02 '15 at 10:23
  • I don't comprehend your comment... why shouldn't he use the `using`? – xanatos Jul 02 '15 at 10:24
  • Thanks. If I need to use the pointer in another module, what is the risk if I wouldn't call "ReleasePointer"? (My SharedMemory is not closed until the program finishes). I guess each call I would get the same pointer? – ittay Jul 03 '15 at 11:18
  • Do you have any guarantee that the "other module" won't try to use the pointer after the mmf and the view are closed? Simplest way to get that guarantee is to just not close them and leave it up to the finalizer. Otherwise the reason I protested. – Hans Passant Jul 03 '15 at 11:35
  • 2
    Note that if you call `CreateViewAccessor` with offset you must add that offset to the pointer from `AcquirePointer`, it is available as `view .PointerOffset`. The pointer from `AcquirePointer` refers to the beginning of the file regardless of the offset in `CreateViewAccessor`. Not sure if that is a bug or a feature, quite counterintuitive. – V.B. Jul 13 '18 at 10:30