Convert String to IntPtr, and Back Again
<p>I'm trying to use the RegisteredWindowMessage API function to send text from one application to another, and I have the following code:</p>

<pre><code>using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace Common
{
    public static class RegisteredMsg
    {
        private const string     MyMessage         = "9C7EDA65363F4fdaAF32";
        private static IntPtr    m_targetWindow    = new IntPtr(0xFFFF);
        private static object    m_object          = new object();
        private static HandleRef m_handleRef;
        private static HandleRef m_handleRef;
        public  static uint      RegisteredMessage 
        {
            get { return m_regMsg; }
            private set 
            { 
                m_regMsg = RegisterWindowMessage(SynchroMessage); 
            }
        }

        //-----------------------------------------------------------------
        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)]
        static extern bool PostMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        //-----------------------------------------------------------------
        [DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)]
        static extern uint RegisterWindowMessage(string lpString);

        //-----------------------------------------------------------------
        static RegisteredMsg()
        {
            m_handleRef = new HandleRef(m_object, m_targetWindow);
        }

        //-----------------------------------------------------------------
        public static void PostUpdateMsg(string text)
        {
            IntPtr    lpData    = Marshal.StringToHGlobalAuto(text);
            IntPtr    lpLength  = new IntPtr(text.Length);
            if (!PostMessage(m_handleRef, RegisteredMessage, lpData, lpLength))
            {
                throw new Exception("Could not post message.");
            }
        }

        //-----------------------------------------------------------------
        public static string GetMessageText(Message msg)
        {
            string text = "";
            int length = msg.LParam.ToInt32();
            text       = Marshal.PtrToStringAuto(msg.WParam, length);
            Marshal.FreeHGlobal(msg.WParam);
            return text;
        }
    }
}
</code></pre>

<p>Posting the message works find, but when the receiving application calls GetMessageText, the string contains "\0\0\0\0" (which is NOT what the sending application sent).</p>

<p>I'm calling it like this:</p>

<pre><code>RegisteredMsg.PostUpdateMsg("test");
</code></pre>

<p>and receiving it like this:</p>

<pre><code>protected override void WndProc(ref Message msg)
{
    base.WndProc(ref msg);
    if (Convert.ToUInt32(msg.Msg) == RegisteredMsg.RegisteredMessage)
    {
        string text = RegisteredMsg.GetMessageText(msg);
    }
}
</code></pre>

<p>EDIT #0</p>

<p>I also tried it this way, and all of the bytes in the received array are '\0':</p>

<pre><code>//-------------------------------------------------------------------------
public static void PostUpdateMsg(string text)
{
    byte[] array  = StringToByteArray(text);
    IntPtr lpData = Marshal.AllocHGlobal(array.Length);
    Marshal.Copy(array, 0, lpData, array.Length);
    IntPtr lpLength = new IntPtr(text.Length);
    if (!PostMessage(m_handleRef, RegisteredMessage, lpData, lpLength))
    {
        throw new Exception("Could not post message.");
    }
}

//-------------------------------------------------------------------------public static string GetMessageText(Message msg)
{
    string text   = "";
    int    length = msg.LParam.ToInt32();
    byte[] array  = new byte[length];
    Marshal.Copy(msg.WParam, array, 0, length);
    text          = RegisteredMsg.ByteArrayToString(array);
    return text;
}
</code></pre>

<p>EDIT #1 </p>

<p>I also called this method from PostUpdateMessage, just to make sure what I was sending was what I thought I was sending:</p>

<pre><code>private static void TestIntPtr(IntPtr ptr, int length)
{
    string text = "";
    byte[] array = new byte[length];
    Marshal.Copy(ptr, array, 0, length);
    text       = ByteArrayToString(array);  // &lt;&lt;------------
}
</code></pre>

<p>When the indicated line is executed, the <code>text</code> variablle is indeed = "test", so I'm doing it right on the sending side. It looks like the memory is getting cleared before it gets to the receiving application.</p>

<p>EDIT #2</p>

<p>I also tried making the <code>IntPtr</code> (pointing to the string I want to send) global to its parent class to make sure it would live long enough to be viable at the other end. No joy there, either.</p>

<p>EDIT #3 </p>

<p>I also reverted back to using the <code>StringToHGlobalAuto</code>, and ran the "is it still okay in the sending app" test (see Edit #1 above), and that test proved that the way I was building the <code>IntPtr</code> was fine as well.</p>
