none
Retrieving Data From Memory via IntPtr INT Value RRS feed

  • Question

  • I'm trying to create a memory cache between a Windows service and an IIS application. The service code writes a serialized class to unmanaged memory fine:

                IntPtr cachePtr = new IntPtr();
                BinaryFormatter binformatter = new BinaryFormatter();
                MemoryStream memstream = new MemoryStream();
                binformatter.Serialize(memstream, CacheData);

                try
                {
                    byte[] cachedata = memstream.ToArray();
                    cachePtr = Marshal.AllocHGlobal(cachedata.Length);
                    byte* memBytePtr = (byte*)cachePtr.ToPointer();
                    UnmanagedMemoryStream ustream = new UnmanagedMemoryStream(memBytePtr, cachedata.Length, cachedata.Length, FileAccess.Write);
                    ustream.Write(cachedata, 0, cachedata.Length);
                    ustream.Close();
                }
                catch { }

    What I want to do is pass the value of IntPtr (cachePtr) to the IIS application so it can quickly retrieve the object from the memory cache. Here is the test code for the IIS side:

                unsafe
                {
                    IntPtr intptr = new IntPtr(5445856);
                    byte* memBytePtr = (byte*)intptr.ToPointer();
                    UnmanagedMemoryStream rstream = new UnmanagedMemoryStream(memBytePtr, 337, 337, FileAccess.Read);
                    byte[] _ByteArray = new byte[337];
                    rstream.Read(_ByteArray, 0, 337);
    
                    System.IO.MemoryStream _MemoryStream = new System.IO.MemoryStream(_ByteArray);
    
                    System.Runtime.Serialization.Formatters.Binary.BinaryFormatter _BinaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
    
                    _MemoryStream.Position = 0;
                    DialerCallData myobj = (DialerCallData)_BinaryFormatter.Deserialize(_MemoryStream);
    
                    rstream.Close();
                }

    For the pointer IntPtr value and size, I'm running the service in debug mode and breaking once the memory is written to so I can copy-paste the IntPtr Int value into the IIS application side.

    My question is, why can I get the int value of IntPtr when the data is written and paste it into the new IntPtr(xxxxxx) statement in the IIS application and it doesn't appear to point to the same memory location?

    • Moved by Leo Liu - MSFT Wednesday, February 8, 2012 7:40 AM Moved for better support. (From:Visual C# General)
    Tuesday, February 7, 2012 7:50 PM

Answers

  • It doesn't work like that, IntPtr's are only valid inside the process that obtained them, this is done to isolate processes and to keep buggy application A from messing up memory of Application B causing the whole system to crash.

    now there's several ways to deal with this issue:

    memory mapped files are an option, but if you insist on using the IntPtr obtained you'd have to pinvoke into Win32 API ReadProcessMemory  to copy the data from process A to process B (handy C# wrapper here)

    • Marked as answer by taylorjeffrey Thursday, February 9, 2012 2:22 PM
    Wednesday, February 8, 2012 9:57 PM

All replies

  • I've modified the code a bit to use Marshal.Copy to write the data and Marshal.PtrToStructure to get it from memory, but the structure has all null values on the read side. The revised code looks like this:

                IntPtr cachePtr = new IntPtr();
                BinaryFormatter binformatter = new BinaryFormatter();
                MemoryStream memstream = new MemoryStream();
                binformatter.Serialize(memstream, CacheData);
    
                try
                {
                    byte[] cachedata = memstream.ToArray();
                    cachePtr = Marshal.AllocHGlobal(cachedata.Length);
                    Marshal.Copy(cachedata, 0, cachePtr, cachedata.Length);
                }
                catch { }

                unsafe
                {
                    DialerCallData dialerCallData = new DialerCallData();
                    IntPtr intptr = new IntPtr(84605152);
                    dialerCallData = (DialerCallData)Marshal.PtrToStructure(intptr, typeof(DialerCallData));
                }
    This seems to be reading from a memory location (and seems faster even), but I'm convinced the IntPtr is wrong when I instantiate it from the int value on the create side. Any suggestions?

    Tuesday, February 7, 2012 9:14 PM
  • Hi taylorjeffrey,

      I have written these similiar codes.I do use this Bi-directional conversion about converting structure into buffer stream,and visa verse.

    #region 
            public static BinaryData ToStruct(byte[] pBuffer)
            {
                GCHandle pHandle = GCHandle.Alloc(pBuffer, GCHandleType.Pinned);
                BinaryData pResultStruct = (BinaryData)Marshal.PtrToStructure(pHandle.AddrOfPinnedObject(), typeof(BinaryData));
                pHandle.Free();
    
                pResultStruct.FieldValue = new byte[pBuffer.LongLength - StructSize.Size + VALUE_DEFAULT_SIZE];
                Array.Copy(pBuffer, StructSize.Size - VALUE_DEFAULT_SIZE, pResultStruct.FieldValue, 0, pResultStruct.FieldValue.LongLength);
    
                return pResultStruct;
            }
    
            public byte[] ToBuffer()
            {
                byte[] pResultBuffer = new byte[this.FieldValue.LongLength + StructSize.Size - VALUE_DEFAULT_SIZE];
    
                GCHandle pHandle = GCHandle.Alloc(pResultBuffer, GCHandleType.Pinned);
                Marshal.StructureToPtr(this, pHandle.AddrOfPinnedObject(), false);
                pHandle.Free();
    
                Array.Copy(this.FieldValue, 0, pResultBuffer, StructSize.Size - VALUE_DEFAULT_SIZE, this.FieldValue.LongLength);
    
                return pResultBuffer;
            }
            #endregion


      Certainly, I have its another writting format using BinaryFormatter object.

    #region

    public static SerialData ToStruct(byte[] pBuffer) { SerialData pResultStruct; using (MemoryStream pMemoryStream = new MemoryStream()) { pMemoryStream.Write(pBuffer, 0, pBuffer.Length); pMemoryStream.Position = 0; BinaryFormatter pBinaryFormatter = new BinaryFormatter(); pResultStruct = (SerialData)pBinaryFormatter.Deserialize(pMemoryStream); } return pResultStruct; } public byte[] ToBuffer() { byte[] pResultBuffer; using (MemoryStream pMemoryStream = new MemoryStream()) { BinaryFormatter pBinaryFormatter = new BinaryFormatter(); pBinaryFormatter.Serialize(pMemoryStream, this); pResultBuffer = pMemoryStream.ToArray(); } return pResultBuffer; } #endregion

    I hope it will resolve your problem.

    Sincerely,

    Jason Wang


    orichisonic http://blog.csdn.net/orichisonic If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".

    Wednesday, February 8, 2012 3:19 AM
  • Thanks for the code, Jason. I tried using GCHandle and a fixed block for my allocation but I don't think anything is overtly wrong with any of these approaches. The problem is taking the Int value of the IntPtr and trying to get the data from that location from another application. I know the data is properly serialized and written to memory, but I think there's an offset or something else in the Int value of the IntPtr that doesn't recreate the exact pointer in a new IntPtr([int value]) in the second application. Does that make sense?
    Wednesday, February 8, 2012 2:33 PM
  • It doesn't work like that, IntPtr's are only valid inside the process that obtained them, this is done to isolate processes and to keep buggy application A from messing up memory of Application B causing the whole system to crash.

    now there's several ways to deal with this issue:

    memory mapped files are an option, but if you insist on using the IntPtr obtained you'd have to pinvoke into Win32 API ReadProcessMemory  to copy the data from process A to process B (handy C# wrapper here)

    • Marked as answer by taylorjeffrey Thursday, February 9, 2012 2:22 PM
    Wednesday, February 8, 2012 9:57 PM
  • Great info - thanks!
    Thursday, February 9, 2012 2:22 PM