是否可以使用IntPtr激活另一个程序中的选项卡?

提前致谢。

是否可以使用IntPtr激活另一个程序中的选项卡? 如果是这样,怎么样?

SendKeys不是一个选项。

也许我需要的是钓鱼课程。 我已经筋疲力尽了谷歌和我的首席开发人员。 我希望得到彻底解决方案或建议继续我的Google努力。

基本过程是:

我将快捷方式图标拖到启动器上

启动窗口~C#源代码

这将打开目标应用程序(Notepad ++)并获取IntPtr等。

我想以编程方式在Notepad ++中选择各种项目,例如编辑,编辑下的菜单项或文档选项卡。

Notepad ++的屏幕抓取

我运行的基本代码是:

在此处输入图像描述

‘blob’

  • 第1项:项目的IntPtr
  • 第2项:itemsChild的IntPtr
  • 第3项:第1项的控制案文
  • 第4项:是第1项的矩形参数

在此处输入图像描述

root包含类似的信息:

在此处输入图像描述

正如其他人所指出的,这样做的标准方法是使用UI自动化 。 Notepad ++确实支持UI自动化(在某种程度上,因为它以某种方式由UI自动化Windows层自动提供)。

这是一个示例C#控制台应用程序,它演示了以下sceanrio(您需要引用UIAutomationClient.dll,UIAutomationProvider.dll和UIAutomationTypes.dll):

1)获取第一个运行的记事本++进程(必须至少启动一个)

2)打开两个文件(注意在记事本++中可能已经有其他打开的选项卡)

3)选择无限循环中的所有选项卡

class Program { static void Main(string[] args) { // this presumes notepad++ has been started somehow Process process = Process.GetProcessesByName("notepad++").FirstOrDefault(); if (process == null) { Console.WriteLine("Cannot find any notepad++ process."); return; } AutomateNpp(process.MainWindowHandle); } static void AutomateNpp(IntPtr handle) { // get main window handle AutomationElement window = AutomationElement.FromHandle(handle); // display the title Console.WriteLine("Title: " + window.Current.Name); // open two arbitrary files (change this!) OpenFile(window, @"d:\my path\file1.txt"); OpenFile(window, @"d:\my path\file2.txt"); // selects all tabs in sequence for demo purposes // note the user can interact with n++ (for example close tabs) while all this is working while (true) { var tabs = GetTabsNames(window); if (tabs.Count == 0) { Console.WriteLine("notepad++ process seems to have gone."); return; } for (int i = 0; i < tabs.Count; i++) { Console.WriteLine("Selecting tab:" + tabs[i]); SelectTab(window, tabs[i]); Thread.Sleep(1000); } } } static IList GetTabsNames(AutomationElement window) { List list = new List(); // get tab bar var tab = window.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Tab)); if (tab != null) { foreach (var item in tab.FindAll(TreeScope.Children, PropertyCondition.TrueCondition).OfType()) { list.Add(item.Current.Name); } } return list; } static void SelectTab(AutomationElement window, string name) { // get tab bar var tab = window.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Tab)); // get tab var item = tab.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, name)); if (item == null) { Console.WriteLine("Tab item '" + name + "' has been closed."); return; } // select it ((SelectionItemPattern)item.GetCurrentPattern(SelectionItemPattern.Pattern)).Select(); } static void OpenFile(AutomationElement window, string filePath) { // get menu bar var menu = window.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.MenuBar)); // get the "file" menu var fileMenu = menu.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, "File")); // open it SafeExpand(fileMenu); // get the new File menu that appears (this is quite specific to n++) var subFileMenu = fileMenu.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Menu)); // get the "open" menu var openMenu = subFileMenu.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, "Open...")); // click it ((InvokePattern)openMenu.GetCurrentPattern(InvokePattern.Pattern)).Invoke(); // get the new Open dialog (from root) var openDialog = WaitForDialog(window); // get the combobox var cb = openDialog.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ComboBox)); // fill the filename ((ValuePattern)cb.GetCurrentPattern(ValuePattern.Pattern)).SetValue(filePath); // get the open button var openButton = openDialog.FindFirst(TreeScope.Children, new AndCondition( new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button), new PropertyCondition(AutomationElement.NameProperty, "Open"))); // press it ((InvokePattern)openButton.GetCurrentPattern(InvokePattern.Pattern)).Invoke(); } static AutomationElement WaitForDialog(AutomationElement element) { // note: this should be improved for error checking (timeouts, etc.) while(true) { var openDialog = element.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window)); if (openDialog != null) return openDialog; } } static void SafeExpand(AutomationElement element) { // for some reason, menus in np++ behave badly while (true) { try { ((ExpandCollapsePattern)element.GetCurrentPattern(ExpandCollapsePattern.Pattern)).Expand(); return; } catch { } } } } 

如果您想知道如何做到这一点,那么您必须阅读有关UI自动化的内容。 所有工具的母亲称为Inspect: https ://msdn.microsoft.com/library/windows/desktop/dd318521.aspx确保您的版本至少为7.2.0.0。 请注意,还有一个名为UISpy,但检查更好。

请注意,遗憾的是,notepad ++标签文本内容 – 因为它基于自定义scintilla编辑器控件 – 不能正确支持自动化(我们无法轻松读取它,我想我们必须使用scintilla Windows消息),但是它可以添加到它(嘿,scintilla家伙,如果你读这个… :)。

除了Garath的答案之外,您可能还想研究Windows自动化API,即用于实现GUI应用程序的编码UI测试的技术。 作为常规function测试的一部分,我通常使用这些API从一组NUnit测试中控制外部应用程序。

像UIAVerify这样的工具可以指示应用程序中可用的控件,并且可以使用Invoke Pattern (以及许多其他控件)在运行时与控件进行交互。

如果您想要一个如何使用自动化API的详细示例,那么开源TestStack White项目非常方便。

如果SendKeys不是一个选项而是阅读更多,那几乎是不可能的

现在更重要的部分问题 – 原因:

我们必须看看win32应用程序是如何工作的:它有一个WndProc / WindowProc方法,可以从UI处理“事件”。 因此,Windows应用程序中的每个事件都必须通过上述方法。 SendKeys方法是一个特殊的SendMessage ( MSDN ),因此你可以使用SendMessage来控制其他exe而不是你的。

简单的代码可能如下所示:

 IntPtr hwnd = FindWindow("Notepad++", null); SendMessageA(hwnd, WM_COMMAND, SOMETHING1, SOMETHING2); 

StackOverflow示例已经有了如何使用chrome实现这一点: C# – 从C#应用程序向Google Chrome发送消息 ,但这只是一个开始。 您必须找出您要发送的确切消息。

在您描述的确切情况下,我将尝试将WM_MOUSE和WM_KEYBORD事件发送到Notepad ++事件,但这只是一个想法:)