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.

    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