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