A standard micro-UI Automation is quite suitable for your task. Here is an example without P / Invoke:
var notepadProcess = Process.GetProcessesByName("Notepad").FirstOrDefault(); var window = AutomationElement.FromHandle(notepadProcess.MainWindowHandle); var transformPattern = (TransformPattern)window.GetCurrentPattern(TransformPattern.Pattern); transformPattern.Resize(300, 300);
(changes the size of the notepad.exe window to 300x300).
Do not forget to connect the UIAutomationClient
and UIAutomationTypes
assemblies and add error control.
MSDN has documentation on the rest of the UI Automation functionality. For example, how to activate the control (click on the button, select the menu item, etc.).
The list of all subwindows and their available properties can be easily found using the Inspect.exe utility from the Windows SDK.
After a little exercise in a google search on a stack flow, hereβs a more serious example:
// Π½Π°Ρ
ΠΎΠ΄ΠΈΠΌ Π±Π΅Π³ΡΡΠΈΠΉ notepad var notepadProcess = Process.GetProcessesByName("Notepad").FirstOrDefault(); var window = AutomationElement.FromHandle(notepadProcess.MainWindowHandle); // ΠΌΠ΅Π½ΡΠ΅ΠΌ ΡΠ°Π·ΠΌΠ΅Ρ ΠΎΠΊΠ½Π° window.GetPattern<TransformPattern>().Resize(300, 300); // ΠΏΠΎΠ»ΡΡΠ°Π΅ΠΌ ΡΡΠ°ΡΡΠΉ ΡΠ΅ΠΊΡΡ var edit = window.FirstChildByType(ControlType.Document); TextPattern textPattern = edit.GetPattern<TextPattern>(); var oldText = textPattern.DocumentRange.GetText(-1); // Π·Π°ΠΌΠ΅Π½ΡΠ΅ΠΌ Π΅Π³ΠΎ Π½Π° Π½ΠΎΠ²ΡΠΉ. Π΄Π»Ρ ΡΡΠΎΠ³ΠΎ ΠΏΡΠΈΠ΄ΡΡΡΡ ΠΏΠΎΡΡΠ»Π°ΡΡ Π½Π°ΠΆΠ°ΡΠΈΡ Π½Π° ΠΊΠ»Π°Π²ΠΈΠ°ΡΡΡΡ // ΠΎΡΠ½ΠΎΠ²Π°Π½ΠΎ Π½Π° ΡΡΠΎΠΌ ΠΏΡΠΈΠΌΠ΅ΡΠ΅: https://msdn.microsoft.com/en-us/library/ms750582.aspx textPattern.DocumentRange.Select(); edit.SetFocus(); Thread.Sleep(100); System.Windows.Forms.SendKeys.SendWait("{DEL}"); System.Windows.Forms.SendKeys.SendWait( "Π’ΠΎΡΠΌΠΎΠ·ΠΈΡΠ΅ ΠΏΡΡΠΌΠΎ Π² ΠΏΠ°ΠΏΡ. ΠΠ°ΠΏΠ° ΠΌΡΠ³ΠΊΠΈΠΉ. ΠΠ½ ΠΏΡΠΎΡΡΠΈΡ."); // ΡΠΎΡ
ΡΠ°Π½ΠΈΠΌ ΠΈΠ·ΠΌΠ΅Π½ΡΠ½Π½ΡΠΉ ΡΠ°ΠΉΠ» ΠΏΠΎΠ΄ Π½ΠΎΠ²ΡΠΌ ΠΈΠΌΠ΅Π½Π΅ΠΌ // Π²ΡΠ·ΠΎΠ²Π΅ΠΌ File -> Save as... (Π½Π° ΡΡΡΡΠΊΠΎΡΠ·ΡΡΠ½ΠΎΠΉ ΡΠΈΡΡΠ΅ΠΌΠ΅ ΠΏΠΎΠ½Π°Π΄ΠΎΠ±ΡΡΡΡ Π΄ΡΡΠ³ΠΈΠ΅ ΡΡΡΠΎΠΊΠΈ!) var menuBar = window.FirstChildByType(ControlType.MenuBar); var fileMenu = menuBar.FirstDescendantByTypeAndName(ControlType.MenuItem, "File"); // ΡΠ°ΡΠΊΡΡΠ»ΠΈ ΠΌΠ΅Π½Ρ File: fileMenu.GetPattern<ExpandCollapsePattern>().Expand(); Thread.Sleep(100); // Π½Π°ΡΠ»ΠΈ ΠΏΡΠ½ΠΊΡ Save As var saveAsMenu = fileMenu.FirstDescendantByTypeAndName(ControlType.MenuItem, "Save As..."); // ΠΈ Π²ΡΠΏΠΎΠ»Π½ΠΈΠ»ΠΈ Π΅Π³ΠΎ saveAsMenu.GetPattern<InvokePattern>().Invoke(); Thread.Sleep(100); // Π·Π°ΠΏΠΎΠΌΠ½ΠΈΠ»ΠΈ ΡΠ»Π΅ΠΌΠ΅Π½Ρ Ρ ΡΠΎΠΊΡΡΠΎΠΌ, ΡΡΠΎ edit box Π΄Π»Ρ Π²Π²ΠΎΠ΄Π° ΠΈΠΌΠ΅Π½ΠΈ ΡΠ°ΠΉΠ»Π° var saveAsEditBox = AutomationElement.FocusedElement; // ΠΏΠΎΠΌΠ΅Π½ΡΠ΅ΠΌ Π΅ΡΡ ΠΊΠΎΠ΄ΠΈΡΠΎΠ²ΠΊΡ ΡΠ΅ΡΠ΅Π· ΠΊΠΎΠΌΠ±ΠΎΠ±ΠΎΠΊΡ Encoding // Π½Π°ΡΠ»ΠΈ ΠΎΠΊΠ½ΠΎ: var saveAsDialog = AutomationHelpers.FindWindowFrom(saveAsEditBox); // ΠΈ ΠΊΠΎΠΌΠ±ΠΎΠ±ΠΎΠΊΡ var encodingCombobox = saveAsDialog.FirstDescendantByTypeAndName(ControlType.ComboBox, "Encoding:"); // ΡΠ°ΡΠΊΡΡΠ»ΠΈ Π΅Π³ΠΎ: encodingCombobox.GetPattern<ExpandCollapsePattern>().Expand(); // Π½Π°ΡΠ»ΠΈ ΠΏΡΠ½ΠΊΡ UTF-8 ΠΈ Π²ΡΠ±ΡΠ°Π»ΠΈ Π΅Π³ΠΎ: var utf8item = encodingCombobox.FirstDescendantByTypeAndName(ControlType.ListItem, "UTF-8"); utf8item.GetPattern<SelectionItemPattern>().Select(); // Π²Π΅ΡΠ½ΡΠ»ΠΈ ΡΠΎΠΊΡΡ Π² edit box saveAsEditBox.SetFocus(); Thread.Sleep(100); // ΠΏΠΎΡΠ»Π°Π»ΠΈ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ ΡΠ°ΠΉΠ»Π° ΠΈ Enter System.Windows.Forms.SendKeys.SendWait(@"{%}TEMP{%}\oster.txt{ENTER}");
The code uses the following simple helper:
static class AutomationHelpers { static public T GetPattern<T>(this AutomationElement element) where T : BasePattern { var pattern = (AutomationPattern)typeof(T).GetField("Pattern").GetValue(null); return (T)element.GetCurrentPattern(pattern); } static public AutomationElement FirstChildByType( this AutomationElement element, ControlType ct) { return element.FindFirst( TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ct)); } static public AutomationElement FirstDescendantByTypeAndName( this AutomationElement element, ControlType ct, string name) { return element.FindFirst( TreeScope.Descendants, new AndCondition( new PropertyCondition(AutomationElement.ControlTypeProperty, ct), new PropertyCondition(AutomationElement.NameProperty, name))); } static public AutomationElement FindWindowFrom(AutomationElement control) { var walker = TreeWalker.ControlViewWalker; while (control.Current.ControlType != ControlType.Window) control = walker.GetParent(control); return control; } }
VB.NET will do the same; UI Automation functionality is available in both languages.
Added pauses per second between actions and adapted to the Russian system (other menu item names), the result:
