如何监听来自第 3 方 DLL 的表单的“Form.Shown”和“Window.Closing”?
Posted
技术标签:
【中文标题】如何监听来自第 3 方 DLL 的表单的“Form.Shown”和“Window.Closing”?【英文标题】:How to listen for "Form.Shown" and "Window.Closing" for a form from a 3rd party DLL? 【发布时间】:2019-10-25 02:22:57 【问题描述】:我的 C# 应用调用第 3 方 DLL。此 DLL 可能显示也可能不显示窗口(窗体)。我希望在显示此窗口时注册一个回调/通知/事件,并在窗口关闭时注册另一个(通过 X 或“关闭”按钮)。如果我能说出导致操作的按钮的名称(即:如果他们按“关闭”或“X”,而不是按“购买”,我会做一些不同的事情)
我无权访问此 DLL 的源代码,并且标头未指定表单。
我所需要的可能吗?
如果您想知道,请联系PaddleSDK
【问题讨论】:
您可以使用 SetWinEventHook, for example setting a callback for
EVENT_OBJECT_INVOKED, so when a Button is pressed (invoking its default action)
WinEventProc` 将通知 hWnd
和 ID
调用的子控件。您可以使用 UI 自动化来完成所有这些操作,以及拦截 Window 创建/销毁。 WindowPatter.WindowOpened
和 WindowPatter.WindowClosed
事件通知(任何)窗口何时打开/关闭。可以为任何 Window 子/后代控件引发特定事件(对于 Windows 窗体尤其简单,对于 WPF 窗口则更少)。
SeWinEventHook 实现参见此处Move window when external application's window moves(您只需更改通知的事件)。 This is a base implementation 使用 UI 自动化的 Window Watcher 过程;它展示了如何检测 Window Opened 事件并与该 Window 交互。
对我来说,EVENT_OBJECT_INVOKED 永远不会触发 :(。您似乎建议了两种不同的方法:1:SetWinEventHook() 和 2:UI 自动化。它们不相关,对吧?那么哪一个?我可以'找不到关于“WindowPatter.WindowOpened”的任何信息你的意思是模式吗?我需要做的是,当窗口第一次显示时,隐藏一个按钮(名为“输入许可证”),所以它消失了(用户不能“选项卡”)。然后,当窗口通过名为“关闭”或通过“X”的按钮关闭时,我需要知道。(如果我能区分该窗口和刚刚关闭的窗口,因为用户否则完成了他们的业务)
如果我确实使用 UI 自动化来捕捉显示的窗口,并找到我想要隐藏的按钮,那么我该如何隐藏它?
是的,抱歉,拼错了(或者平板电脑拼错了:)WindowPattern.WindowOpenedEvent,WindowPattern.WindowClosedEvent。您可以通过 UIAutomation 获得 WinForms 中的任何控件。但是本机 UIA 的 .Net 实现是,比如说,部分。一旦你找到了你想要的元素(通常是通过名字和ControlType
),你可以调用ShowWindow([hWnd], SW_HIDE)
来隐藏元素。
【参考方案1】:
使用 SetWinEventHook
互联网充满了愚蠢的方法,但这是正确的方法。轮询很糟糕(可以吗?)。
如果您在 *** 上搜索 SetWinEventHook 并查找 c# 匹配项,您会发现很多示例可供使用。
【讨论】:
looking here 我找不到“开窗”和“关窗”或“按下按钮”的事件。我看到“EVENT_OBJECT_INVOKED”,但不会触发出现的窗口中的按钮,也不会触发“X”。我可以获取“前窗已更改”(EVENT_SYSTEM_FOREGROUND)的事件,但这并没有说明打开或关闭。请注意“EVENT_SYSTEM_DIALOGSTART / END”事件似乎没有被触发,大概是因为窗口不是对话框。我听说过使用 UI 自动化的建议,这是更好的选择吗?【参考方案2】:好的哇,这似乎工作:(感谢大家的提示!)
private int[] i_checkoutWindID;
private void RegisterEventListener()
Automation.AddAutomationEventHandler(
WindowPattern.WindowOpenedEvent,
AutomationElement.RootElement,
TreeScope.Children,
(sender, e) =>
AutomationElement element = sender as AutomationElement;
string automationID = element.Current.AutomationId;
if (automationID != kLicenseWindowAutomationID) return;
i_checkoutWindID = element.GetRuntimeId();
AutomationElement licenseButton = element.FindFirst(
TreeScope.Descendants,
new PropertyCondition(AutomationElement.AutomationIdProperty, kLicenseButtonAutomationID));
if (licenseButton != null)
IntPtr hwnd = new IntPtr(licenseButton.Current.NativeWindowHandle);
Control buttonRef = Control.FromHandle(hwnd);
HideButton_Safe(buttonRef);
);
Automation.AddAutomationEventHandler(
WindowPattern.WindowClosedEvent,
AutomationElement.RootElement,
TreeScope.Subtree,
(sender, e) =>
WindowClosedEventArgs args = e as WindowClosedEventArgs;
if (Automation.Compare(args.GetRuntimeId(), i_checkoutWindID))
Array.Clear(i_checkoutWindID, 0, i_checkoutWindID.Length);
<do your "window closed" callback here>;
);
private void HideButton_Safe(Control buttonRef)
if (buttonRef.InvokeRequired)
var d = new SafeCallDelegate_ButtonHide(HideButton_Safe);
buttonRef.Invoke(d, new object[] buttonRef );
else
buttonRef.Hide();
【讨论】:
以上是关于如何监听来自第 3 方 DLL 的表单的“Form.Shown”和“Window.Closing”?的主要内容,如果未能解决你的问题,请参考以下文章
Visual C++:插件 DLL 使用的第 3 方 DLL 的位置?