3

我有一个 Delphi 应用程序 A,我需要从 .NET 应用程序 B 控制它。

除其他外,我需要自动化这个过程:

  1. 用户从组合框中选择项目 X。
  2. 应用程序 A 注意到更改并通过显示某个面板做出反应。

如果我手动操作,这可以正常工作。

但是当应用程序 B 选择一个组合框值时,不会显示任何面板。

这就是问题。

它的潜在原因:

  1. 当我选择一个组合框项目时,会触发某个 Windows 消息。一些 Delphi 例程对此消息作出反应。
  2. 当我以编程方式选择组合框项时,我发送的唯一消息是CB_SETCURSELDelphi 应用程序似乎忽略了它。

因此,我假设我可以解决问题,如果我

  1. 了解使用哪些 Windows 消息作为组合框值更改通知的基础(例如OnChange)和
  2. 从 C# 应用程序发送该 windows 消息。

因此我的问题是:什么是 Windows 消息,在其发生时OnChange(以及通知 Delphi 应用程序更改组合框选择的其他事件)被触发?

更新 1:开始实施 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);

目前,它不起作用。

更新 2:

我注意到一件非常奇怪的事情。

  1. 如果我只调用CB_SETCURSEL,则在组合框中选择所需的项目。
  2. 如果我调用CB_SETCURSELand then (after 5 seconds) CN_COMMAND,则组合框中没有选择任何内容。

这意味着 -CB_SECURSEL选择项目并CN_COMMAND撤消它。

更新 3:根据 Spy++ 的组合框样式:

  1. WS_CHILDWINDOW
  2. WS_VISIBLE
  3. WS_CLIPSIBLINGS
  4. 00000243

扩展样式:

  1. WS_EX_LEFT
  2. WS_EX_LTRREADING
  3. WS_EX_RIGHTSCROLLBAR

课堂风格:

  1. CS_VREDRAW
  2. CS_HREDRAW
  3. CS_DBLCLKS

更新 4:当我手动选择组合框项目时,我在 Spy++ 输出中看到以下消息:

<00177> 0195085E S message:0xBD33 [Custom:WM_APP+15667] wParam:6801164A lParam:0195085E
<00178> 0195085E R message:0xBD33 [Custom:WM_APP+15667] lResult:4610165A

不幸的是,我找不到此消息的文档。

更新 5:我注意到对组合框选择更改的反应确实发生了,但只有在相对较长的时间(30 秒到 1 分钟)之后才会发生。当我手动做同样的事情时,反应会立即发生。

此行为的潜在原因:.NET 应用程序的线程使 Delphi 应用程序的线程等待它。请注意,.NET 应用程序中的 UI 交互代码在单独的线程(不是 UI 线程)中执行。

4

2 回答 2

4

CB_SETCURSEL您应该通过向组合框WM_COMMAND发送NotifyCode等于的消息来跟踪消息CBN_SELCHANGE。它CBN_SELCHANGE是触发OnChange事件的那个。

在 Delphi 中,代码如下所示:

SendMessage(ComboHandle, CB_SETCURSEL, NewSelectionIndex, 0);
SendMessage(ComboHandle, WM_COMMAND, MakeWParam(0, CBN_SELCHANGE), ComboHandle);

或者您可以改用该CN_COMMAND消息,这可能会更直接一些:

SendMessage(ComboHandle, CB_SETCURSEL, NewSelectionIndex, 0);
SendMessage(ComboHandle, CN_COMMAND, MakeWParam(0, CBN_SELCHANGE), 0);

你会想把它翻译成你使用的任何一种.net语言,但我相信这对你来说很容易。

于 2012-10-08T13:32:14.170 回答
4

当用户手动选择 ComboBox 项时,控件会收到CBN_SELCHANGE通知,然后触发TComboBox.OnChange事件。当您以可编程方式选择 ComboBox 项时,不会CBN_SELCHANGE发送任何通知。这是记录在案的行为:

http://msdn.microsoft.com/en-us/library/windows/desktop/bb775821.aspx

当使用 CB_SETCURSEL 消息设置当前选择时,不会发送 CBN_SELCHANGE 通知代码。

于 2012-10-08T19:05:40.360 回答