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 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