我正在尝试关闭特定的MessageBox
(如果它根据标题和文本显示)。 MessageBox
没有图标时,它可以正常工作。
IntPtr handle = FindWindowByCaption(IntPtr.Zero, "Caption");
if (handle == IntPtr.Zero)
return;
//Get the Text window handle
IntPtr txtHandle = FindWindowEx(handle, IntPtr.Zero, "Static", null);
int len = GetWindowTextLength(txtHandle);
//Get the text
StringBuilder sb = new StringBuilder(len + 1);
GetWindowText(txtHandle, sb, len + 1);
//close the messagebox
if (sb.ToString() == "Original message")
{
SendMessage(new HandleRef(null, handle), WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
}
当显示MessageBox
且没有图标时,上面的代码可以正常工作,如下所示。
MessageBox.Show("Original message", "Caption");
但是,如果它包含如下所示的图标(来自MessageBoxIcon
),则它不起作用; GetWindowTextLength
返回0,什么也没有发生。
MessageBox.Show("Original message", "Caption", MessageBoxButtons.OK, MessageBoxIcon.Information);
我的最佳猜测是FindWindowEx
的第三和/或第四参数需要更改,但是我不确定该通过什么。还是可能需要更改第二个参数才能跳过图标?我不太确定。
答案 0 :(得分:3)
当MessageBox带有图标时,FindWindowEx
会返回第一个子项的文本(在这种情况下为图标),因此返回零长度。现在,在this answer的帮助下,我有了一个要遍历孩子的想法,直到找到一个带有文字的孩子。这应该起作用:
IntPtr handle = FindWindowByCaption(IntPtr.Zero, "Caption");
if (handle == IntPtr.Zero)
return;
//Get the Text window handle
IntPtr txtHandle = IntPtr.Zero;
int len;
do
{
txtHandle = FindWindowEx(handle, txtHandle, "Static", null);
len = GetWindowTextLength(txtHandle);
} while (len == 0 && txtHandle != IntPtr.Zero);
//Get the text
StringBuilder sb = new StringBuilder(len + 1);
GetWindowText(txtHandle, sb, len + 1);
//close the messagebox
if (sb.ToString() == "Original message")
{
SendMessage(new HandleRef(null, handle), WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
}
很明显,您可以对其进行调整以适合您的特定情况(例如,不断进行迭代,直到找到您要查找的实际文本为止),尽管我认为带有文本的孩子可能永远是第二个孩子:
答案 1 :(得分:2)
这是一种UI自动化方法,可以检测系统中任何位置的Window Opened事件,使用其子元素之一的Text识别Window,并在确定后关闭Window。
使用Automation.AddAutomationEventHandler将WindowPattern.WindowOpenedEvent设置为AutomationElement.RootElement,并将Automation Element参数设置为Ahmed Abdelhameed noted in the comments来初始化检测,该参数在没有其他祖先的情况下标识整个Desktop(任何窗口)。
WindowWatcher
类公开了一个公共方法(WatchWindowBySubElementText
),该方法可以指定包含在刚打开的Window的子元素之一中的Text。如果找到了指定的Text,则该方法将关闭Window并使用自定义事件处理程序通知操作,订阅者可以使用该事件处理程序来确定已检测到并关闭了监视的Window。
使用问题中提供的文本字符串作为示例用法:
WindowWatcher watcher = new WindowWatcher();
watcher.ElementFound += (obj, evt) => { MessageBox.Show("Found and Closed!"); };
watcher.WatchWindowBySubElementText("Original message");
WindowWatcher
类:
此类需要对这些程序集的项目引用:
UIAutomationClient
UIAutomationTypes
请注意,识别后,类事件将删除自动化 通知订阅者之前的事件处理程序。这只是一个 示例:它指出需要在某些时候删除处理程序 点。该类可以实现
IDisposable
并删除 处理程序。
编辑:
更改了不考虑在当前流程中创建的窗口的条件:
if (element is null || element.Current.ProcessId != Process.GetCurrentProcess().Id)
与一样,它施加了一个可能不必要的限制:该Dialod也可能属于当前Process。我只留下了null
支票。
using System;
using System.Diagnostics;
using System.Windows.Automation;
public class WindowWatcher
{
public delegate void ElementFoundEventHandler(object sender, EventArgs e);
public event ElementFoundEventHandler ElementFound;
public WindowWatcher() { }
public void WatchWindowBySubElementText(string ElementText) =>
Automation.AddAutomationEventHandler(WindowPattern.WindowOpenedEvent,
AutomationElement.RootElement, TreeScope.Subtree, (UIElm, evt) =>
{
AutomationElement element = UIElm as AutomationElement;
if (element is null) return;
AutomationElement childElm = element.FindFirst(TreeScope.Children,
new PropertyCondition(AutomationElement.NameProperty, ElementText));
if (childElm != null)
{
(element.GetCurrentPattern(WindowPattern.Pattern) as WindowPattern).Close();
this.OnElementFound(new EventArgs());
}
});
public void OnElementFound(EventArgs e)
{
Automation.RemoveAllEventHandlers();
ElementFound?.Invoke(this, e);
}
}