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