views:

767

answers:

2

When using the CB_SETCURSEL message, the CBN_SELCHANGE message is not sent.

How to notify a control that the selection was changed ?

P.S.

I found on the Sexchange site, a very ugly hack :

SendMessage( hwnd, 0x014F/*CB_SHOWDROPDOWN*/, 1, 0 );
SendMessage( hwnd, 0x014E/*CB_SETCURSEL*/, ItemIndex, 0 );
SendMessage( hwnd, 0x0201/*WM_LBUTTONDOWN*/, 0, -1 );
SendMessage( hwnd, 0x0202/*WM_LBUTTONUP*/, 0, -1 );

Will do for now... Not really.

P.S.2

For resolving my problem, I'll follow Ken's suggestion in the comments.

+2  A: 

You're not supposed to use CBN_SELCHANGE unless the change in selection was made by the user.

You don't indicate what language you're using; it would make it easier to provide you with a workaround if you did so.

In Delphi, where an OnChange() would be associated with the combobox, you just call the event method directly:

// Send the CB_SETCURSEL message to the combobox
PostMessage(ComboBox1.Handle, CB_SETCURSEL, Whatever, WhateverElse);

// Directly call the OnChange() handler, which is the equivalent to CBN_SELCHANGE
ComboBox1Change(nil);
Ken White
Sorry, C or C++
anno
Are you using a GUI library like MFC, or straight Win32 calls? If it's straight Win32, use the debugger in your message handler loop. Set it on your code for handling CBN_SELCHANGE, and look at the values that are passed in as the WPARAM and LPARAM when you change an item in the combobox (as the normal user). You can then use basically the same Delphi PostMessage() code I showed above, passing the appropriate values for WPARAM and LPARAM, programatically in your code right after posting the CBN_SETCURSEL message. If you're using MFC, I can't help (and you have my sympathy <g>).
Ken White
I'm not using MFC but I have found a lot of code in MFC :( (http://stackoverflow.com/questions/59280/programmatically-change-combobox).
anno
As I said, you have my sympathy. <g> An alternative to my last suggestion would be to use a separate function that you call in your event handler for responding to CBN_SELCHANGE; instead of posting CBN_SELCHANGE yourself after posting CBN_SETCURSEL, you can then directly call that function.
Ken White
Yes, I think I’m gonna refactor my code so that I have the same action when sending a CB_SETCURSEL message and when the user makes a selection. Thanks for a helpful answer.
anno
A: 

This might help the next person out:

[DllImport("User32.dll", EntryPoint = "SendMessage")] private static extern int SendMessage(IntPtr hwnd, int msg, int wParam, int lParam);

[DllImport("user32.dll", EntryPoint = "GetWindowLong")] private static extern IntPtr GetWindowLongPtr32(IntPtr hWnd, int nIndex);

[DllImport("user32.dll", EntryPoint = "GetWindowLongPtr")] private static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, int nIndex);

public static IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex) { if (IntPtr.Size == 8) return GetWindowLongPtr64(hWnd, nIndex); else return GetWindowLongPtr32(hWnd, nIndex); }

static int MakeWParam(int loWord, int hiWord) { return (loWord & 0xFFFF) + ((hiWord & 0xFFFF) << 16); }

public const int CB_SETCURSEL = 0x014E; public const int CBN_SELCHANGE = 0x0001;

public enum GWL { GWL_WNDPROC = (-4), GWL_HINSTANCE = (-6), GWL_HWNDPARENT = (-8), GWL_STYLE = (-16), GWL_EXSTYLE = (-20), GWL_USERDATA = (-21), GWL_ID = (-12) }

public static IntPtr Hwnd_select_control_parent = IntPtr.Zero; public static IntPtr Hwnd_select_control = IntPtr.Zero;

static void changeit()

{

// Google WinSpy for tips on how to figure out how to get window handles from known ctrl_id

Hwnd_select_control = 14298; // or whatever the handle of the combo box is

// Get the parent of the selectbox control

Hwnd_select_control_parent = GetWindowLongPtr(service_window_control, (int)GWL.GWL_HWNDPARENT);

// Get the control id of the selectbox if you don't already have it

IntPtr nID = GetWindowLongPtr(Hwnd_select_control, (int)GWL.GWL_ID); int ctrl_id = nID.ToInt32();

// Change the combo box to the value "My Value"

SendMessage(Hwnd_select_control, CB_SETCURSEL, "My Value", null);

// low ID is the ctrl_id of the combo box, high id is CBN_SELCHANGE

int send_cbn_selchange = MakeWParam(ctrl_id, CBN_SELCHANGE);

// Send the WM_COMMAND to the parent, not the control itself

SendMessage(Hwnd_serviceselect_control_parent, 0x111 /* WM_COMMAND */, send_cbn_selchange, Hwnd_serviceselect_control.ToInt32());

}

Keith McCall