What windows messages are used by Delphi to notice changes in a combo box?
-
05-07-2021 - |
Вопрос
I have a Delphi application A, which I need to control from a .NET application B.
Among other things, I need to automate this process:
- User selects item X from a combo box.
- Application A notices the change and reacts by displaying a certain panel.
This works fine, if I do it manually.
But when the application B selects a combo box value, no panel is displayed.
This is the problem.
Potential cause of it:
- When I select a combo box item, a certain windows message is fired. Some Delphi routine reacts to this message.
- When I select a combo box item programmatically, the only message I send is
CB_SETCURSEL
and the Delphi app seems to ignore it.
Hence I assume that I can fix the problem, if I
- get to know what windows messages are used as a basis for notification about combo box value changes (e. g.
OnChange
) and - send that windows message from C# application.
Therefore my question: What are the windows messages, on whose occurrence OnChange
(and other events that notify the Delphi application on changed combo box selection) are fired?
Update 1: Started to implement the solution proposed by David Heffernan
private const int CB_SETCURSEL = 0x14E;
private const int WM_COMMAND = 0x0111;
private const int CBN_SELCHANGE = 0x001;
private const int CN_COMMAND = 0xBD11;
private int MakeWParam(int l, int h)
{
return (l & 0xFFFF) | (h << 16);
}
...
IntPtr comboBoxHandle = new IntPtr(comboBox.Current.NativeWindowHandle);
SendMessage(comboBoxHandle, CB_SETCURSEL, (Int32)myIndexInComboBox, 0);
SendMessage(comboBoxHandle, CN_COMMAND, MakeWParam(0, CBN_SELCHANGE), 0);
At the moment, it doesn't work.
Update 2:
I noticed a very strange thing.
- If I invoke
CB_SETCURSEL
only, the desired item is selected in the combo box. - If I invoke
CB_SETCURSEL
and then (after 5 seconds)CN_COMMAND
, then nothing is selected in the combo box.
This means - CB_SECURSEL
selects the item and CN_COMMAND
undoes it.
Update 3: Styles of the combo box according to Spy++:
- WS_CHILDWINDOW
- WS_VISIBLE
- WS_CLIPSIBLINGS
- 00000243
Extended styles:
- WS_EX_LEFT
- WS_EX_LTRREADING
- WS_EX_RIGHTSCROLLBAR
Class styles:
- CS_VREDRAW
- CS_HREDRAW
- CS_DBLCLKS
Update 4: When I select the combo box item manually, I see following messages in the Spy++ output:
<00177> 0195085E S message:0xBD33 [Custom:WM_APP+15667] wParam:6801164A lParam:0195085E
<00178> 0195085E R message:0xBD33 [Custom:WM_APP+15667] lResult:4610165A
Unfortunately, I couldn't find documentation for this message.
Update 5: I noticed that the reaction to combo box selection change does occur, but only after a relatively long time (30 seconds to 1 minute). When I do the same thing manually, the reaction occurs instantaneously.
Potential cause of this behaviour: The thread of the .NET application makes the thread of the Delphi application wait for it. Note that the UI interaction code in the .NET app is executed in a separate thread (not the UI thread).
Решение
You should follow the CB_SETCURSEL
message by sending the combo box a WM_COMMAND
message with NotifyCode
equal to CBN_SELCHANGE
. It's the CBN_SELCHANGE
that triggers the OnChange
event.
In Delphi the code would look like this:
SendMessage(ComboHandle, CB_SETCURSEL, NewSelectionIndex, 0);
SendMessage(ComboHandle, WM_COMMAND, MakeWParam(0, CBN_SELCHANGE), ComboHandle);
Or you could use the CN_COMMAND
message instead which would perhaps be a little more direct:
SendMessage(ComboHandle, CB_SETCURSEL, NewSelectionIndex, 0);
SendMessage(ComboHandle, CN_COMMAND, MakeWParam(0, CBN_SELCHANGE), 0);
You'll want to translate that into whichever .net language you are using, but I'm sure that's easy for you.
Другие советы
When the user selects a ComboBox item by hand, the control receives a CBN_SELCHANGE
notification, which then triggers the TComboBox.OnChange
event. When you select a ComboBox item programmably, no CBN_SELCHANGE
notification is sent. This is documented behavior:
http://msdn.microsoft.com/en-us/library/windows/desktop/bb775821.aspx
The CBN_SELCHANGE notification code is not sent when the current selection is set using the CB_SETCURSEL message.