none
How to send an object with SendMessage RRS feed

  • Question

  • Hello,

    I have a perfect working example below that can pass a "String" with SendMessage.

    I wonder how it is possible to pass an object instead of a String. I beleive an object for example can represent anything from an int, double, string to objects and Lists?

    How to modify the working example below to pass along "TWOlists" with SendMessage as an object?

            private void button1_Click(object sender, EventArgs e)
            {
                //How can we send "TWOlists" as an object?
                List<String> list1 = new List<String>(); List<String> list2 = new List<String>(); List<List<String>> TWOlists = new List<List<String>>();
                list1.Add("hello1"); list2.Add("hello2");
                TWOlists.Add(list1);
                TWOlists.Add(list2);
    
                sendFunction(TWOlists); //How to send this?
            }

    Complete working example of how to pass a string with SendMessage

            private void button1_Click(object sender, EventArgs e)
            {
                String str = "hello";
                sendFunction(str);
            }
    
            private const int WM_COPYDATA = 0x004A;
            [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, ref COPYDATASTRUCT lParam);
            [StructLayout(LayoutKind.Sequential)]
            public struct COPYDATASTRUCT
            {
                public IntPtr dwData;
                public Int32 cbData;
                public IntPtr lpData;
            }
            //This function gets info about what request to do from "APPLICATION1"
            protected override void WndProc(ref Message message)
            {
                switch (message.Msg)
                {
                    case WM_COPYDATA:
    
                        COPYDATASTRUCT CD = (COPYDATASTRUCT)message.GetLParam(typeof(COPYDATASTRUCT));
                        byte[] B = new byte[CD.cbData];
                        IntPtr lpData = CD.lpData;
                        Marshal.Copy(lpData, B, 0, CD.cbData);
                        string getINFO = Encoding.ASCII.GetString(B);
    
                        MessageBox.Show(getINFO);
                        break;
    
                    default: base.WndProc(ref message); break;
                }
            }       
            void sendFunction(String str)
            {
                //Here send back the information to "APPLICATION1"
                Process proc = Process.GetCurrentProcess();
                Process[] processes = Process.GetProcesses();
                foreach (Process p in processes)
                {
                    if (proc.Id == p.Id)
                    {
                        //Send this strin
                        COPYDATASTRUCT cds;
                        cds.dwData = IntPtr.Zero;
                        cds.lpData = Marshal.StringToHGlobalAnsi(str);
                        cds.cbData = str.Length;
    
                        //now send the RF_TESTMESSAGE to the running instance
                        SendMessage(p.MainWindowHandle, WM_COPYDATA, IntPtr.Zero, ref cds);
                        break;
                    }
                }
            }






    • Edited by Silvers2 Saturday, March 12, 2016 4:59 PM
    Wednesday, March 9, 2016 11:49 PM

Answers

  • I found a solution to the problem. It seems that it is needed to refer to the very same class for the dimensions.

    So I created a new project/library and created a .DLL file which I referenced to in both APPLICATION1 and APPLICATION2. 

    Then it worked fine.

    DLL file

     [Serializable] public class Dims1 : List<String> { };
            [Serializable] public class Dims2 : List<Dims1> { };
            [Serializable] public class Dims3 : List<Dims2> { };
            [Serializable] public class Dims4 : List<Dims3> { };

    • Marked as answer by Silvers2 Saturday, March 12, 2016 8:20 PM
    Saturday, March 12, 2016 8:20 PM

All replies

  • In the particular case of lists of strings, the simplest way is probably to join all of the strings, send them using the available sendFunction, then receive, split them, and restore the list. The sender can join the strings in this manner:

    string special_string = string.Join( "\x1E", TWOlists.Select( lst => string.Join( "\x1F", lst ) ) );

    Then call sendFunction(special_string).

    After obtaining this string, the receiver will build the lists:

    List<List<String>> TWOlists = getINFO.Split( '\x1E' ).Select( p => p.Split( '\x1F' ).ToList() ).ToList();

    Another solution is to transform the object to array of bytes using Serialisation. Many kinds of objects can be serialized, including lists. The array can be then transmitted using WM_COPYDATA. In order to reuse sendFunction, then array can be converted to a special string:

    using( var ms = new MemoryStream() )

    {

           var bf = new BinaryFormatter();

           bf.Serialize( ms, TWOlists );

           special_string = Convert.ToBase64String( ms.ToArray() );

    }

    Then call sendFunction(special_string).

    The receiver will deserialise the data:

    using( var ms = new MemoryStream( Convert.FromBase64String( getINFO ) ) )

    {

           var bf = new BinaryFormatter();

           TWOlists = (dynamic)bf.Deserialize( ms );

    }


    Thursday, March 10, 2016 6:41 AM
  • Thank you for answer,

    The approach to serialise /deserialise is something that is a good idéa.

    I have successfully used that to pass along ordinary List<String> from APPLICATION1 to APPLICATION2. However, I have a problem when I try to pass along a four dimensional list which I also would need to do. As a test I did, If I send the four dimensional list in APPLICATION1 and also gets that four dimensional list in APPLICATION1 then it works.

    The problem and error comes in APPLICATION2 when I try to send it from APPLICATION1 to APPLICATION2:

    System.Runtime.Serialization.SerializationException: Unable to find assembly 'APPLICATION1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.

    As seen in somehow APPLICATION2 looks for assembly APPLICATION1. I dont know what this means really and what the problem can be?

    The error occurs on this line:

    objectLIST = (dynamic)bf.Deserialize(ms);

    The code I now use is the below where the first code is put in APPLICATION1 and the second in APPLICATION2.

    code in APPLICATION1

            //Send function in APPLICATION1
            [Serializable] class Dims1 : List<String> { };
            [Serializable] class Dims2 : List<Dims1> { };
            [Serializable] class Dims3 : List<Dims2> { };
            [Serializable] class Dims4 : List<Dims3> { };
            private void button1_Click(object sender, EventArgs e)
            {
                List<object> objectLIST = new List<object>(); Dims4 fourDimensionLIST = new Dims4(); String objects = "";
                fourDimensionLIST.Add(new Dims3());
                fourDimensionLIST[0].Add(new Dims2());
                fourDimensionLIST[0][0].Add(new Dims1());
                fourDimensionLIST[0][0][0].Add("hello");
    
                //Add "fourDimensionLIST"
                objectLIST.Add(fourDimensionLIST);
    
                using (var ms = new MemoryStream())
                {
                    var bf = new BinaryFormatter();
                    bf.Serialize(ms, objectLIST);
                    objects = Convert.ToBase64String(ms.ToArray());
                }
                //Send
                //Process proc = Process.GetCurrentProcess();
                Process[] processes = Process.GetProcesses(); int applicationProcessID = 12345;
                foreach (Process p in processes)
                {
                    //"applicationProcessID" is the ID of "APPLICATION2" which needs to be known
                    if (applicationProcessID == p.Id)
                    {
                        COPYDATASTRUCT cds;
                        cds.dwData = IntPtr.Zero;
                        cds.lpData = Marshal.StringToHGlobalAnsi(objects);
                        cds.cbData = objects.Length;
    
                        //Send the "fourDimensionLIST" to APPLICATION2
                        SendMessage(p.MainWindowHandle, WM_COPYDATA, IntPtr.Zero, ref cds);
                    }
                }
            }

    code in: APPLICATION2

            //Get "fourDimensionLIST" in APPLICATION2
            
            [Serializable] class Dims1 : List<String> { };
            [Serializable] class Dims2 : List<Dims1> { };
            [Serializable] class Dims3 : List<Dims2> { };
            [Serializable] class Dims4 : List<Dims3> { };
            protected override void WndProc(ref Message message)
            {
                //Here we will get the "fourDimensionLIST"
                switch (message.Msg)
                {
                    case WM_COPYDATA:
    
                        COPYDATASTRUCT CD = (COPYDATASTRUCT)message.GetLParam(typeof(COPYDATASTRUCT));
                        byte[] B = new byte[CD.cbData];
                        IntPtr lpData = CD.lpData;
                        Marshal.Copy(lpData, B, 0, CD.cbData);
                        string getINFO = Encoding.ASCII.GetString(B);
    
    
                        using (var ms = new MemoryStream(Convert.FromBase64String(getINFO)))
                        {
                            List<object> objectLIST = new List<object>();
                            var bf = new BinaryFormatter();
    
                            //System.Runtime.Serialization.SerializationException: 
                            //Unable to find assembly 'APPLICATION1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
                            objectLIST = (dynamic)bf.Deserialize(ms);
                        }
                        break;
    
                    default: base.WndProc(ref message); break;
                }
            }


    • Edited by Silvers2 Saturday, March 12, 2016 5:46 PM
    Saturday, March 12, 2016 5:22 PM
  • I found a solution to the problem. It seems that it is needed to refer to the very same class for the dimensions.

    So I created a new project/library and created a .DLL file which I referenced to in both APPLICATION1 and APPLICATION2. 

    Then it worked fine.

    DLL file

     [Serializable] public class Dims1 : List<String> { };
            [Serializable] public class Dims2 : List<Dims1> { };
            [Serializable] public class Dims3 : List<Dims2> { };
            [Serializable] public class Dims4 : List<Dims3> { };

    • Marked as answer by Silvers2 Saturday, March 12, 2016 8:20 PM
    Saturday, March 12, 2016 8:20 PM