Search code examples
c#winformswinapipinvoke

Windows Forms, Syntax error in SendMessage line


I am using Windows Forms and I am attempting to use SendMessage to get the ComboBox dropdown rectangle. However I can't seem to find the correct parameter combination that will allow the code to compile.

I have tried copying examples I found, but nothing seems to compile.

Here are some examples of lines that do not compile:

var z1 = SendMessage(hWnd, CB_GETDROPPEDCONTROLRECT, (IntPtr)1, (IntPtr)0);  // The best overloaded match has some invalid arguments.

var z2 = SendMessage(hWnd, 0x0152, (IntPtr)1, (IntPtr)0); 

var z3 = SendMessage(hWnd, CB_GETDROPPEDCONTROLRECT, 1, 0); 

var z4 = SendMessage(hWnd, 0x0152, 1, 0);

Thanks in advance to anyone who has any ideas to make this work.

Here is my complete code:

public partial class Form1 : Form
{
    [DllImport("user32.dll")]
    public static extern int SendMessage(
          int hWnd,      // handle to destination window
          uint Msg,       // message
          long wParam,  // first message parameter
          long lParam   // second message parameter
          );

    public Form1()
    {
        InitializeComponent();
        List<string> itms = new List<string>();
        itms.Add("Choice 1");
        itms.Add("Choice 2");
        itms.Add("Choice 3");
        itms.Add("Choice 4");
        itms.Add("Choice 5");

        this.comboBox1.Items.AddRange(itms.ToArray());
    }

    private void comboBox1_DropDown(object sender, EventArgs e)
    {
        const int CB_GETDROPPEDCONTROLRECT = 0x0152;
        IntPtr hWnd = comboBox1.Handle;

        var z = SendMessage(hWnd, CB_GETDROPPEDCONTROLRECT, (IntPtr)1, (IntPtr)0);  // The best overloaded match has some invalid arguments.

        var z1 = SendMessage(hWnd, 0x0152, (IntPtr)1, (IntPtr)0); 
    }
}

Solution

  • To get the dropdown rectangle of a combobox you can do this:

    First, declare the RECT struct:

    [StructLayout(LayoutKind.Sequential)]
    public struct RECT
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
    }
    

    Note: the Microsoft documentation states these fields should be long, but I tested it and for some strange reason SendMessage answers with int's here.

    Second, the correct SendMessage declaration: For this special case you can now use a ref RECT parameter. Note that in your versions there are mistakes: hWnd needs to be an IntPtr while wParam is only int and not long:

    [DllImport("user32.dll")]
    public static extern int SendMessage(
        IntPtr hWnd,    // handle to destination window (combobox in this case)
        int Msg,    // message
        int wParam, // first message parameter
        ref RECT lParam  // second message parameter
    );
    

    Third, the usage:

    RECT rect = default;
    int result = SendMessage(comboBox1.Handle, 0x0152, 1, ref rect);
    

    Where comboBox1 is of course your ComboBox. If result is zero, the call failed, otherwise it succeeded and rect should contain the desired values.