Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. Sending a String using SendMessage

Sending a String using SendMessage

Scheduled Pinned Locked Moved C#
csharpc++json
14 Posts 5 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • E Offline
    E Offline
    eyalbi007
    wrote on last edited by
    #1

    Hi all, I'm looking for an easy way to send message containing String data from C# application to C++ application, using the SendMessage API call. Please refer to both sending the message and receiving it (in C++). Thanks a lot! Eyal.

    L M O 3 Replies Last reply
    0
    • E eyalbi007

      Hi all, I'm looking for an easy way to send message containing String data from C# application to C++ application, using the SendMessage API call. Please refer to both sending the message and receiving it (in C++). Thanks a lot! Eyal.

      L Offline
      L Offline
      lisan_al_ghaib
      wrote on last edited by
      #2

      are both applications exe ?

      E 1 Reply Last reply
      0
      • E eyalbi007

        Hi all, I'm looking for an easy way to send message containing String data from C# application to C++ application, using the SendMessage API call. Please refer to both sending the message and receiving it (in C++). Thanks a lot! Eyal.

        M Offline
        M Offline
        Mark Salsbery
        wrote on last edited by
        #3

        On the C# side, something like this maybe:

        [DllImport("User32", SetLastError = true)]
        public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
        ...

        string ManagedString = "A string!";
        IntPtr PtrToUnmanagedString = Marshal.StringToHGlobalAnsi(ManagedString);
        SendMessage(hwnd, WM_SOMEMESSAGE, IntPtr.Zero, PtrToUnmanagedString);
        Marshal.FreeHGlobal(PtrToUnmanagedString);

        On the C++ side, handle messages in the app's message loop as usual (kind of a big topic for here). Mark

        Mark Salsbery Microsoft MVP - Visual C++ :java:

        E 1 Reply Last reply
        0
        • L lisan_al_ghaib

          are both applications exe ?

          E Offline
          E Offline
          eyalbi007
          wrote on last edited by
          #4

          Yes, both Windows applications. One's GUI is written on .NET 2 C# and the second is C++ application with GUI designed using FLTK. Thank you.

          1 Reply Last reply
          0
          • M Mark Salsbery

            On the C# side, something like this maybe:

            [DllImport("User32", SetLastError = true)]
            public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
            ...

            string ManagedString = "A string!";
            IntPtr PtrToUnmanagedString = Marshal.StringToHGlobalAnsi(ManagedString);
            SendMessage(hwnd, WM_SOMEMESSAGE, IntPtr.Zero, PtrToUnmanagedString);
            Marshal.FreeHGlobal(PtrToUnmanagedString);

            On the C++ side, handle messages in the app's message loop as usual (kind of a big topic for here). Mark

            Mark Salsbery Microsoft MVP - Visual C++ :java:

            E Offline
            E Offline
            eyalbi007
            wrote on last edited by
            #5

            On the C++ side I have lparam of type int. How should I refer to it in order to get my string? Thanks!

            M 1 Reply Last reply
            0
            • E eyalbi007

              On the C++ side I have lparam of type int. How should I refer to it in order to get my string? Thanks!

              M Offline
              M Offline
              Mark Salsbery
              wrote on last edited by
              #6

              For the ANSI string sample I showed, something like this:

              const char *pANSIstring = (const char *)lParam;

              For Unicode, you could change the StringToHGlobalAnsi to StringToHGlobalUni on the C# side, and on the C++ side, something like:

              const wchar_t *pUnicodestring = (const wchar_t *)lParam;

              Mark

              Mark Salsbery Microsoft MVP - Visual C++ :java:

              E 1 Reply Last reply
              0
              • M Mark Salsbery

                For the ANSI string sample I showed, something like this:

                const char *pANSIstring = (const char *)lParam;

                For Unicode, you could change the StringToHGlobalAnsi to StringToHGlobalUni on the C# side, and on the C++ side, something like:

                const wchar_t *pUnicodestring = (const wchar_t *)lParam;

                Mark

                Mark Salsbery Microsoft MVP - Visual C++ :java:

                E Offline
                E Offline
                eyalbi007
                wrote on last edited by
                #7

                Hi Mark, The two options you suggested doesn't work: At both cases I get 'Bad Ptr' at the C++ side (I get junk and not string). Maybe the reason is that each one of the applications (C# and C++) uses different memory space, so passing pointers from one to another is meaningless. Or am I missing something? Thanks a lot, Eyal.

                M 1 Reply Last reply
                0
                • E eyalbi007

                  Hi all, I'm looking for an easy way to send message containing String data from C# application to C++ application, using the SendMessage API call. Please refer to both sending the message and receiving it (in C++). Thanks a lot! Eyal.

                  O Offline
                  O Offline
                  oobimoo
                  wrote on last edited by
                  #8

                  You must use the WM_COPYDATA msg in the c# proj declare the following

                  [StructLayout(LayoutKind.Sequential)]
                  struct CopyDataStruct
                  {
                  public IntPtr dwData;
                  public int dataSize;
                  public IntPtr data;
                  }

                  enum WinMessage
                  {
                      WM\_COPYDATA = 0x4A
                  }
                  
                  class NativeAPI
                  {
                      \[DllImport("User32.dll")\]
                      public static extern int SendMessage(IntPtr hWnd, WinMessage msg, IntPtr wParam, IntPtr lParam);
                      \[DllImport("User32.dll", CharSet = CharSet.Auto)\]
                      public static extern IntPtr FindWindow(string className, string windowName);
                  }
                  

                  and when you press a button for example

                  private void button1_Click(object sender, EventArgs e)
                  {
                  string s = "This is a message from sharp"; // string to send to the native application
                  // native window handle
                  IntPtr hCWindow = NativeAPI.FindWindow("RECIEVE_DATA", "Recieve_Data");
                  // check and handle the not found (null) case here...

                          // GetBytes returns the bytes of the string but not the terminating null char
                          byte\[\] tmpStringData = System.Text.Encoding.Unicode.GetBytes(s);
                          // so we copy to a new byte array and adding 2 zeros (for unicode)
                          byte\[\] stringData = new byte\[tmpStringData.Length + 2\];
                          Array.Copy(tmpStringData, stringData, tmpStringData.Length);
                          stringData\[stringData.Length - 2\] = stringData\[stringData.Length - 1\] = 0;
                          
                          CopyDataStruct cds = new CopyDataStruct();
                          cds.dwData = IntPtr.Zero;  // no need for this example
                          cds.dataSize = stringData.Length; 
                          // pinning the managed array and getting the address
                          GCHandle gch\_data = GCHandle.Alloc(stringData, GCHandleType.Pinned);
                          cds.data = gch\_data.AddrOfPinnedObject();
                          // pinning the struct also
                          GCHandle gch\_cds = GCHandle.Alloc(cds, GCHandleType.Pinned); 
                          // when sending a WM\_COPYDATA msg wParam is the hWnd of the 
                          // sender and lParam a pointer to a COPYDATASTRUCT                   
                          NativeAPI.SendMessage(hCWindow, WinMessage.WM\_COPYDATA, this.Handle, gch\_cds.AddrOfPinnedObject());
                          // free the handles
                          gch\_data.Free();
                          gch\_cds.Free();
                      }
                  

                  and in the windowproc of the native app

                  case WM\_COPYDATA:
                  	{
                  	PCOPYDATASTRUCT pcds = (PCOPYDATASTRUCT)lParam;
                  	MessageBox(0, (LPC
                  
                  E A 2 Replies Last reply
                  0
                  • O oobimoo

                    You must use the WM_COPYDATA msg in the c# proj declare the following

                    [StructLayout(LayoutKind.Sequential)]
                    struct CopyDataStruct
                    {
                    public IntPtr dwData;
                    public int dataSize;
                    public IntPtr data;
                    }

                    enum WinMessage
                    {
                        WM\_COPYDATA = 0x4A
                    }
                    
                    class NativeAPI
                    {
                        \[DllImport("User32.dll")\]
                        public static extern int SendMessage(IntPtr hWnd, WinMessage msg, IntPtr wParam, IntPtr lParam);
                        \[DllImport("User32.dll", CharSet = CharSet.Auto)\]
                        public static extern IntPtr FindWindow(string className, string windowName);
                    }
                    

                    and when you press a button for example

                    private void button1_Click(object sender, EventArgs e)
                    {
                    string s = "This is a message from sharp"; // string to send to the native application
                    // native window handle
                    IntPtr hCWindow = NativeAPI.FindWindow("RECIEVE_DATA", "Recieve_Data");
                    // check and handle the not found (null) case here...

                            // GetBytes returns the bytes of the string but not the terminating null char
                            byte\[\] tmpStringData = System.Text.Encoding.Unicode.GetBytes(s);
                            // so we copy to a new byte array and adding 2 zeros (for unicode)
                            byte\[\] stringData = new byte\[tmpStringData.Length + 2\];
                            Array.Copy(tmpStringData, stringData, tmpStringData.Length);
                            stringData\[stringData.Length - 2\] = stringData\[stringData.Length - 1\] = 0;
                            
                            CopyDataStruct cds = new CopyDataStruct();
                            cds.dwData = IntPtr.Zero;  // no need for this example
                            cds.dataSize = stringData.Length; 
                            // pinning the managed array and getting the address
                            GCHandle gch\_data = GCHandle.Alloc(stringData, GCHandleType.Pinned);
                            cds.data = gch\_data.AddrOfPinnedObject();
                            // pinning the struct also
                            GCHandle gch\_cds = GCHandle.Alloc(cds, GCHandleType.Pinned); 
                            // when sending a WM\_COPYDATA msg wParam is the hWnd of the 
                            // sender and lParam a pointer to a COPYDATASTRUCT                   
                            NativeAPI.SendMessage(hCWindow, WinMessage.WM\_COPYDATA, this.Handle, gch\_cds.AddrOfPinnedObject());
                            // free the handles
                            gch\_data.Free();
                            gch\_cds.Free();
                        }
                    

                    and in the windowproc of the native app

                    case WM\_COPYDATA:
                    	{
                    	PCOPYDATASTRUCT pcds = (PCOPYDATASTRUCT)lParam;
                    	MessageBox(0, (LPC
                    
                    E Offline
                    E Offline
                    eyalbi007
                    wrote on last edited by
                    #9

                    Hi oobimoo, Thanks for you reply. The C# part works fine, however, at the C++ side I can retrieve only the first character of the string ((LPCTSTR)pcds->lpData equals to "T"). I tried some other castings (string and char*) but I only get the first character. Any ideas? Thanks! Eyal.

                    O 1 Reply Last reply
                    0
                    • E eyalbi007

                      Hi oobimoo, Thanks for you reply. The C# part works fine, however, at the C++ side I can retrieve only the first character of the string ((LPCTSTR)pcds->lpData equals to "T"). I tried some other castings (string and char*) but I only get the first character. Any ideas? Thanks! Eyal.

                      O Offline
                      O Offline
                      oobimoo
                      wrote on last edited by
                      #10

                      Your encoding at the c++ side is ascii. As i mentioned you must use the System.Text.Encoding.ASCII.GetBytes(s) instead of the unicode that i use in my example.

                      E 1 Reply Last reply
                      0
                      • E eyalbi007

                        Hi Mark, The two options you suggested doesn't work: At both cases I get 'Bad Ptr' at the C++ side (I get junk and not string). Maybe the reason is that each one of the applications (C# and C++) uses different memory space, so passing pointers from one to another is meaningless. Or am I missing something? Thanks a lot, Eyal.

                        M Offline
                        M Offline
                        Mark Salsbery
                        wrote on last edited by
                        #11

                        eyalbi007 wrote:

                        Maybe the reason is that each one of the applications (C# and C++) uses different memory space

                        You're absolutely right! I'm an idiot :) Sorry about that - I totally spaced on the inter-process requirement. Looks like oobimoo showed you a solution. Mark

                        Mark Salsbery Microsoft MVP - Visual C++ :java:

                        1 Reply Last reply
                        0
                        • O oobimoo

                          Your encoding at the c++ side is ascii. As i mentioned you must use the System.Text.Encoding.ASCII.GetBytes(s) instead of the unicode that i use in my example.

                          E Offline
                          E Offline
                          eyalbi007
                          wrote on last edited by
                          #12

                          Dear oobimoo, Indeed, now it works. However, I'm still concerned about something: if I'm getting this correctly, the calls gch_data.Free() and gch_cds.Free() are responsible for freeing the pinned memory. However, what if the receiving side didn't get the information before this release? Isn't it better to (somehow) release this pinned memory at the receiving side? Consider the following chain of events: 1. Sending the message at C# application. 2. Receiving the message at the C++ application, but right before extracting the sent string: 3. Context switch at the C++ application. 4. The C# application releases the pinned memory. 5. Context switch back to the C++ application. The pinned memory is released and we can't extract the string message. Or maybe these can't happen since SendMessage is blocking? Thanks!

                          O 1 Reply Last reply
                          0
                          • E eyalbi007

                            Dear oobimoo, Indeed, now it works. However, I'm still concerned about something: if I'm getting this correctly, the calls gch_data.Free() and gch_cds.Free() are responsible for freeing the pinned memory. However, what if the receiving side didn't get the information before this release? Isn't it better to (somehow) release this pinned memory at the receiving side? Consider the following chain of events: 1. Sending the message at C# application. 2. Receiving the message at the C++ application, but right before extracting the sent string: 3. Context switch at the C++ application. 4. The C# application releases the pinned memory. 5. Context switch back to the C++ application. The pinned memory is released and we can't extract the string message. Or maybe these can't happen since SendMessage is blocking? Thanks!

                            O Offline
                            O Offline
                            oobimoo
                            wrote on last edited by
                            #13

                            Your are welcome From the msdn (WM_COPYDATA) : "The receiving application should consider the data read-only. The lParam parameter is valid only during the processing of the message. The receiving application should not free the memory referenced by lParam. If the receiving application must access the data after SendMessage returns, it must copy the data into a local buffer. " From the msdn (SendMessage) : "The SendMessage function sends the specified message to a window or windows. It calls the window procedure for the specified window and does not return until the window procedure has processed the message. "

                            modified on Monday, August 25, 2008 1:08 PM

                            1 Reply Last reply
                            0
                            • O oobimoo

                              You must use the WM_COPYDATA msg in the c# proj declare the following

                              [StructLayout(LayoutKind.Sequential)]
                              struct CopyDataStruct
                              {
                              public IntPtr dwData;
                              public int dataSize;
                              public IntPtr data;
                              }

                              enum WinMessage
                              {
                                  WM\_COPYDATA = 0x4A
                              }
                              
                              class NativeAPI
                              {
                                  \[DllImport("User32.dll")\]
                                  public static extern int SendMessage(IntPtr hWnd, WinMessage msg, IntPtr wParam, IntPtr lParam);
                                  \[DllImport("User32.dll", CharSet = CharSet.Auto)\]
                                  public static extern IntPtr FindWindow(string className, string windowName);
                              }
                              

                              and when you press a button for example

                              private void button1_Click(object sender, EventArgs e)
                              {
                              string s = "This is a message from sharp"; // string to send to the native application
                              // native window handle
                              IntPtr hCWindow = NativeAPI.FindWindow("RECIEVE_DATA", "Recieve_Data");
                              // check and handle the not found (null) case here...

                                      // GetBytes returns the bytes of the string but not the terminating null char
                                      byte\[\] tmpStringData = System.Text.Encoding.Unicode.GetBytes(s);
                                      // so we copy to a new byte array and adding 2 zeros (for unicode)
                                      byte\[\] stringData = new byte\[tmpStringData.Length + 2\];
                                      Array.Copy(tmpStringData, stringData, tmpStringData.Length);
                                      stringData\[stringData.Length - 2\] = stringData\[stringData.Length - 1\] = 0;
                                      
                                      CopyDataStruct cds = new CopyDataStruct();
                                      cds.dwData = IntPtr.Zero;  // no need for this example
                                      cds.dataSize = stringData.Length; 
                                      // pinning the managed array and getting the address
                                      GCHandle gch\_data = GCHandle.Alloc(stringData, GCHandleType.Pinned);
                                      cds.data = gch\_data.AddrOfPinnedObject();
                                      // pinning the struct also
                                      GCHandle gch\_cds = GCHandle.Alloc(cds, GCHandleType.Pinned); 
                                      // when sending a WM\_COPYDATA msg wParam is the hWnd of the 
                                      // sender and lParam a pointer to a COPYDATASTRUCT                   
                                      NativeAPI.SendMessage(hCWindow, WinMessage.WM\_COPYDATA, this.Handle, gch\_cds.AddrOfPinnedObject());
                                      // free the handles
                                      gch\_data.Free();
                                      gch\_cds.Free();
                                  }
                              

                              and in the windowproc of the native app

                              case WM\_COPYDATA:
                              	{
                              	PCOPYDATASTRUCT pcds = (PCOPYDATASTRUCT)lParam;
                              	MessageBox(0, (LPC
                              
                              A Offline
                              A Offline
                              Alexandro Maceiras
                              wrote on last edited by
                              #14

                              Yeah! Tks a lot!

                              1 Reply Last reply
                              0
                              Reply
                              • Reply as topic
                              Log in to reply
                              • Oldest to Newest
                              • Newest to Oldest
                              • Most Votes


                              • Login

                              • Don't have an account? Register

                              • Login or register to search.
                              • First post
                                Last post
                              0
                              • Categories
                              • Recent
                              • Tags
                              • Popular
                              • World
                              • Users
                              • Groups