title: Convert String to IntPtr, and Back Again
body: <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>