locked
PostMessage can't send self-defined struct while SendMessage can RRS feed

  • Question

  • Hi, everyone
      I'm using Win32-style API to send windows message. If I use PostMessage() from User32.dll to send an int as wParam and a struct as lParam(with a string member), the receiver can't get lParam while can get wParam. If I use SendMessage() instead, lParam/wParam both work ok.
     
      But my app needs PostMessage(), please do help me check where the error is. Thank you very much!
     
      Sun
     

    //Win32 API Class

    using System;
    using System.Runtime.InteropServices;

    namespace TestHwnd
    {
        public class Win32API
        {
           


            [DllImport("User32.dll", EntryPoint = "FindWindow")]
            public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

            [DllImport("User32.dll", EntryPoint = "FindWindowEx")]
            public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpClassName, string lpWindowName);

            /// <summary>
            /// self-defined struct
            /// </summary>
            public struct My_lParam
            {
                public int i;
                public string s;
            }
            /// <summary>
            /// use COPYDATASTRUCT to send a string
            /// </summary>
            [StructLayout(LayoutKind.Sequential)]
            public struct COPYDATASTRUCT
            {
                public IntPtr dwData;
                public int cbData;
                [MarshalAs(UnmanagedType.LPStr)]
                public string lpData;
            }
            //message delivery API
            [DllImport("User32.dll", EntryPoint = "SendMessage")]
            public static extern int SendMessage(
                IntPtr hWnd,        // the target windows's handle
                int Msg,            // message ID
                int wParam,         // parameter 1
                int lParam          //parameter 2
            );

           
            //message delivery API
            [DllImport("User32.dll", EntryPoint = "SendMessage")]
            public static extern int SendMessage(
                IntPtr hWnd,        // the target windows's handle
                int Msg,            // message ID
                int wParam,         // parameter 1
                ref My_lParam lParam //parameter 2
            );
           
            //message delivery API
            [DllImport("User32.dll", EntryPoint = "SendMessage")]
            public static extern int SendMessage(
                IntPtr hWnd,        // the target windows's handle
                int Msg,            // message ID
                int wParam,         // parameter 1
                ref  COPYDATASTRUCT lParam  //parameter 2
            );

            //message delivery API
            [DllImport("User32.dll", EntryPoint = "PostMessage")]
            public static extern int PostMessage(
                IntPtr hWnd,        // the target windows's handle
                int Msg,            // message ID
                int wParam,         // parameter 1
                int lParam            // parameter 2
            );
           
           
           
            //message delivery API
            [DllImport("User32.dll", EntryPoint = "PostMessage")]
            public static extern int PostMessage(
                IntPtr hWnd,        // the target windows's handle
                int Msg,            // message ID
                int wParam,         // parameter 1
                ref My_lParam lParam // parameter 2
            );
           
            //message delivery API
            [DllImport("User32.dll", EntryPoint = "PostMessage")]
            public static extern int PostMessage(
                IntPtr hWnd,        // the target windows's handle
                int Msg,            // message ID
                int wParam,         // parameter 1
                ref  COPYDATASTRUCT lParam  // parameter 2
            );

        }
    }

    //the main form to send message

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;

    namespace TestHwnd
    {
        public partial class Main : Form
        {

            public IntPtr hwndTest;
            public int IwndTest;
            public IntPtr hwndfrmTest;
           

            public Main()
            {
                InitializeComponent();
            }

            private void button1_Click(object sender, EventArgs e)
            {
                Test test = new Test();
                test.Show(this);
            }

            private void timer1_Tick(object sender, EventArgs e)
            {
                string strTest = "25425";
                Win32API.COPYDATASTRUCT cds;
                cds.dwData = (IntPtr)100;
                cds.lpData = strTest;
                byte[] sarr = System.Text.Encoding.UTF8.GetBytes(strTest);
                int len = sarr.Length;
                cds.cbData = len + 1;
               
                Win32API.My_lParam lp=new Win32API.My_lParam();
                lp.i=3;
                lp.s="test";
               
                if(hwndTest!=(IntPtr)0)
                {
                    if (DateTime.Now.Second % 2 == 0)
                    {
                        Win32API.SendMessage(hwndTest, 0x60, 1, 3);//send 2 int params, successful
                    }
                    if(DateTime.Now.Second % 3 == 0)
                    {
                        Win32API.SendMessage(hwndTest, 0x61, 5, ref lp);//send an int and a struct, successful
                    }
                    if(DateTime.Now.Second % 5 == 0)
                    {
                        Win32API.SendMessage(hwndTest, 0x62, 5, ref cds);//send an int and a struct with a variable length string, successful
                    }
                    if(DateTime.Now.Second % 7 == 0)
                    {
                        Win32API.PostMessage(hwndTest, 0x63, 5, 6);//send 2 int params, successful
                    }
                    if(DateTime.Now.Second % 9 == 0)
                    {
                        Win32API.PostMessage(hwndTest, 0x64, 3, ref lp);//send an int - successful, and a struct - failed
                    }
                    if(DateTime.Now.Second % 11 == 0)
                    {
                        Win32API.PostMessage(hwndTest, 0x65, 3, ref cds);//send an int - successful, and cds - failed
                    }
                }
            }
        }
    }

     


    //the child form to get the message and parameters

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;

    namespace TestHwnd
    {
        public partial class Test : Form
        {
            Main main;
            public Test()
            {
                InitializeComponent();
            }

            private void Test_Load(object sender, EventArgs e)
            {
                main = this.Owner as Main;
                main.hwndTest = this.Handle;
               
            }

           

            ///rewrite DefWndProc to process special messages
            protected override void DefWndProc(ref Message m)
            {
                switch (m.Msg)
                {
                        //get self-defined MYMESSAGE, and show its parameters
                    case 0x60:
                        {
                            label1.Text = DateTime.Now.ToString() + "-" + m.WParam.ToInt32().ToString() + "-" + m.LParam.ToInt32().ToString();
                        }
                        break;
                    case 0x61:
                        {
                            Win32API.My_lParam ml = new Win32API.My_lParam();
                            Type t = ml.GetType();
                            ml = (Win32API.My_lParam)m.GetLParam(t);
                            label2.Text = DateTime.Now.ToString() + "-" + m.WParam.ToInt32().ToString() + "-" + ml.i.ToString()+":"+ml.s;
                        }
                        break;
                        case 0x62:
                        {
                            Win32API.COPYDATASTRUCT mystr = new Win32API.COPYDATASTRUCT();
                            Type mytype = mystr.GetType();
                            mystr = (Win32API.COPYDATASTRUCT)m.GetLParam(mytype);
                            string str2 = mystr.lpData;
                            label3.Text = DateTime.Now.ToString() + "-" + m.WParam.ToInt32().ToString() + "-" + str2;
                        }
                        break;
                        case 0x63:
                        {
                            label4.Text = DateTime.Now.ToString() + "-" + m.WParam.ToInt32().ToString() + "-" + m.LParam.ToInt32().ToString();
                        }
                        break;
                        case 0x64:
                        {
                            Win32API.My_lParam ml = new Win32API.My_lParam();
                            Type t = ml.GetType();
                            ml = (Win32API.My_lParam)m.GetLParam(t);
                            label5.Text = DateTime.Now.ToString() + "-" + m.WParam.ToInt32().ToString() + "-" + ml.i.ToString()+":"+ml.s;
                        }
                        break;
                        case 0x65:
                        {
                            Win32API.COPYDATASTRUCT mystr = new Win32API.COPYDATASTRUCT();
                            Type mytype = mystr.GetType();
                            mystr = (Win32API.COPYDATASTRUCT)m.GetLParam(mytype);
                            string str2 = mystr.lpData;
                            label6.Text = DateTime.Now.ToString() + "-" + m.WParam.ToInt32().ToString() + "-" + str2;
                        }
                        break;
                    default:
                        base.DefWndProc(ref m);
                        break;
                }
            }

           
            private void button1_Click(object sender, EventArgs e)
            {
                main.hwndTest = (IntPtr) (0);
                this.Close();
            }

        }

    }

    • Moved by Leo Liu - MSFT Tuesday, January 10, 2012 7:43 AM Moved for better support. (From:Visual C# General)
    Monday, January 9, 2012 1:17 PM

Answers

  • Hi,

    can you give more details, what kind of error you get?

    Did you check the PostMessage description on MSDN Library (http://msdn.microsoft.com/en-us/library/windows/desktop/ms644944(v=vs.85).aspx):

    If you send a message in the range below WM_USER to the asynchronous message functions (PostMessage, SendNotifyMessage, and SendMessageCallback), its message parameters cannot include pointers. Otherwise, the operation will fail. The functions will return before the receiving thread has had a chance to process the message and the sender will free the memory before it is used.

    0x6x < 0x0400 (WM_USER) so regarding this documentation, the operationwill fail if you send pointers.

    With kind regards,

    Konrad

    • Proposed as answer by Paul Zhou Wednesday, January 11, 2012 9:45 AM
    • Marked as answer by Paul Zhou Tuesday, January 17, 2012 8:53 AM
    Monday, January 9, 2012 2:14 PM
  • For this reason, you should always define custom messages as WM_USER + some value. It prevents some of these hard-to-track-down issues.
    Check out My Blog for tech news, development tips, and other information for geeks like me.
    • Marked as answer by Paul Zhou Tuesday, January 17, 2012 8:53 AM
    Monday, January 9, 2012 2:29 PM

All replies

  • Hi, everyone
      I'm using Win32-style API to send windows message. If I use PostMessage() from User32.dll to send an int as wParam and a struct as lParam(with a string member), the receiver can't get lParam while can get wParam. If I use SendMessage() instead, lParam/wParam both work ok.
     
      But my app needs PostMessage(), please do help me check where the error is. Thank you very much!

      Sun
     

    //Win32 API Class

    using System;
    using System.Runtime.InteropServices;

    namespace TestHwnd
    {
        public class Win32API
        {
           


            [DllImport("User32.dll", EntryPoint = "FindWindow")]
            public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

            [DllImport("User32.dll", EntryPoint = "FindWindowEx")]
            public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpClassName, string lpWindowName);

            /// <summary>
            /// self-defined struct
            /// </summary>
            public struct My_lParam
            {
                public int i;
                public string s;
            }
            /// <summary>
            /// use COPYDATASTRUCT to send a string
            /// </summary>
            [StructLayout(LayoutKind.Sequential)]
            public struct COPYDATASTRUCT
            {
                public IntPtr dwData;
                public int cbData;
                [MarshalAs(UnmanagedType.LPStr)]
                public string lpData;
            }
            //message delivery API
            [DllImport("User32.dll", EntryPoint = "SendMessage")]
            public static extern int SendMessage(
                IntPtr hWnd,        // the target windows's handle
                int Msg,            // message ID
                int wParam,         // parameter 1
                int lParam          //parameter 2
            );

           
            //message delivery API
            [DllImport("User32.dll", EntryPoint = "SendMessage")]
            public static extern int SendMessage(
                IntPtr hWnd,        // the target windows's handle
                int Msg,            // message ID
                int wParam,         // parameter 1
                ref My_lParam lParam //parameter 2
            );
           
            //message delivery API
            [DllImport("User32.dll", EntryPoint = "SendMessage")]
            public static extern int SendMessage(
                IntPtr hWnd,        // the target windows's handle
                int Msg,            // message ID
                int wParam,         // parameter 1
                ref  COPYDATASTRUCT lParam  //parameter 2
            );

            //message delivery API
            [DllImport("User32.dll", EntryPoint = "PostMessage")]
            public static extern int PostMessage(
                IntPtr hWnd,        // the target windows's handle
                int Msg,            // message ID
                int wParam,         // parameter 1
                int lParam            // parameter 2
            );
           
           
           
            //message delivery API
            [DllImport("User32.dll", EntryPoint = "PostMessage")]
            public static extern int PostMessage(
                IntPtr hWnd,        // the target windows's handle
                int Msg,            // message ID
                int wParam,         // parameter 1
                ref My_lParam lParam // parameter 2
            );
           
            //message delivery API
            [DllImport("User32.dll", EntryPoint = "PostMessage")]
            public static extern int PostMessage(
                IntPtr hWnd,        // the target windows's handle
                int Msg,            // message ID
                int wParam,         // parameter 1
                ref  COPYDATASTRUCT lParam  // parameter 2
            );

        }
    }

    //the main form to send message

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;

    namespace TestHwnd
    {
        public partial class Main : Form
        {

            public IntPtr hwndTest;
            public int IwndTest;
            public IntPtr hwndfrmTest;
           

            public Main()
            {
                InitializeComponent();
            }

            private void button1_Click(object sender, EventArgs e)
            {
                Test test = new Test();
                test.Show(this);
            }

            private void timer1_Tick(object sender, EventArgs e)
            {
                string strTest = "25425";
                Win32API.COPYDATASTRUCT cds;
                cds.dwData = (IntPtr)100;
                cds.lpData = strTest;
                byte[] sarr = System.Text.Encoding.UTF8.GetBytes(strTest);
                int len = sarr.Length;
                cds.cbData = len + 1;
               
                Win32API.My_lParam lp=new Win32API.My_lParam();
                lp.i=3;
                lp.s="test";
               
                if(hwndTest!=(IntPtr)0)
                {
                    if (DateTime.Now.Second % 2 == 0)
                    {
                        Win32API.SendMessage(hwndTest, 0x60, 1, 3);//send 2 int params, successful
                    }
                    if(DateTime.Now.Second % 3 == 0)
                    {
                        Win32API.SendMessage(hwndTest, 0x61, 5, ref lp);//send an int and a struct, successful
                    }
                    if(DateTime.Now.Second % 5 == 0)
                    {
                        Win32API.SendMessage(hwndTest, 0x62, 5, ref cds);//send an int and a struct with a variable length string, successful
                    }
                    if(DateTime.Now.Second % 7 == 0)
                    {
                        Win32API.PostMessage(hwndTest, 0x63, 5, 6);//send 2 int params, successful
                    }
                    if(DateTime.Now.Second % 9 == 0)
                    {
                        Win32API.PostMessage(hwndTest, 0x64, 3, ref lp);//send an int - successful, and a struct - failed
                    }
                    if(DateTime.Now.Second % 11 == 0)
                    {
                        Win32API.PostMessage(hwndTest, 0x65, 3, ref cds);//send an int - successful, and cds - failed
                    }
                }
            }
        }
    }

     


    //the child form to get the message and parameters

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;

    namespace TestHwnd
    {
        public partial class Test : Form
        {
            Main main;
            public Test()
            {
                InitializeComponent();
            }

            private void Test_Load(object sender, EventArgs e)
            {
                main = this.Owner as Main;
                main.hwndTest = this.Handle;
               
            }

           

            ///rewrite DefWndProc to process special messages
            protected override void DefWndProc(ref Message m)
            {
                switch (m.Msg)
                {
                        //get self-defined MYMESSAGE, and show its parameters
                    case 0x60:
                        {
                            label1.Text = DateTime.Now.ToString() + "-" + m.WParam.ToInt32().ToString() + "-" + m.LParam.ToInt32().ToString();
                        }
                        break;
                    case 0x61:
                        {
                            Win32API.My_lParam ml = new Win32API.My_lParam();
                            Type t = ml.GetType();
                            ml = (Win32API.My_lParam)m.GetLParam(t);
                            label2.Text = DateTime.Now.ToString() + "-" + m.WParam.ToInt32().ToString() + "-" + ml.i.ToString()+":"+ml.s;
                        }
                        break;
                        case 0x62:
                        {
                            Win32API.COPYDATASTRUCT mystr = new Win32API.COPYDATASTRUCT();
                            Type mytype = mystr.GetType();
                            mystr = (Win32API.COPYDATASTRUCT)m.GetLParam(mytype);
                            string str2 = mystr.lpData;
                            label3.Text = DateTime.Now.ToString() + "-" + m.WParam.ToInt32().ToString() + "-" + str2;
                        }
                        break;
                        case 0x63:
                        {
                            label4.Text = DateTime.Now.ToString() + "-" + m.WParam.ToInt32().ToString() + "-" + m.LParam.ToInt32().ToString();
                        }
                        break;
                        case 0x64:
                        {
                            Win32API.My_lParam ml = new Win32API.My_lParam();
                            Type t = ml.GetType();
                            ml = (Win32API.My_lParam)m.GetLParam(t);
                            label5.Text = DateTime.Now.ToString() + "-" + m.WParam.ToInt32().ToString() + "-" + ml.i.ToString()+":"+ml.s;
                        }
                        break;
                        case 0x65:
                        {
                            Win32API.COPYDATASTRUCT mystr = new Win32API.COPYDATASTRUCT();
                            Type mytype = mystr.GetType();
                            mystr = (Win32API.COPYDATASTRUCT)m.GetLParam(mytype);
                            string str2 = mystr.lpData;
                            label6.Text = DateTime.Now.ToString() + "-" + m.WParam.ToInt32().ToString() + "-" + str2;
                        }
                        break;
                    default:
                        base.DefWndProc(ref m);
                        break;
                }
            }

           
            private void button1_Click(object sender, EventArgs e)
            {
                main.hwndTest = (IntPtr) (0);
                this.Close();
            }

        }

    }


    • Edited by China Sun Monday, January 9, 2012 1:17 PM
    • Merged by Leo Liu - MSFT Tuesday, January 10, 2012 7:11 AM Totally the same.
    Monday, January 9, 2012 1:17 PM
  • Hi,

    can you give more details, what kind of error you get?

    Did you check the PostMessage description on MSDN Library (http://msdn.microsoft.com/en-us/library/windows/desktop/ms644944(v=vs.85).aspx):

    If you send a message in the range below WM_USER to the asynchronous message functions (PostMessage, SendNotifyMessage, and SendMessageCallback), its message parameters cannot include pointers. Otherwise, the operation will fail. The functions will return before the receiving thread has had a chance to process the message and the sender will free the memory before it is used.

    0x6x < 0x0400 (WM_USER) so regarding this documentation, the operationwill fail if you send pointers.

    With kind regards,

    Konrad

    • Proposed as answer by Paul Zhou Wednesday, January 11, 2012 9:45 AM
    • Marked as answer by Paul Zhou Tuesday, January 17, 2012 8:53 AM
    Monday, January 9, 2012 2:14 PM
  • Monday, January 9, 2012 2:15 PM
  • For this reason, you should always define custom messages as WM_USER + some value. It prevents some of these hard-to-track-down issues.
    Check out My Blog for tech news, development tips, and other information for geeks like me.
    • Marked as answer by Paul Zhou Tuesday, January 17, 2012 8:53 AM
    Monday, January 9, 2012 2:29 PM
  • Yeah, great addition Tim!

    With kind regards,

    Konrad

    Monday, January 9, 2012 2:34 PM