Справится ли C# с управлением другой программы

319
11 сентября 2017, 02:58
  • Справится ли C# с управлением другой программы?
  • Насколько он хуже или лучше чем C++ в этом плане?
  • Справится ли с этой задачей VB.NET?

Требуется.

  1. Изменить размеры окна стороннего приложения.
  2. Отправить приложение на самый нижний Z уровень, чтобы оно не
    появлялось поверх других открытых окон, в то время когда на нем будут происходить какие то действия, например нажатия кнопок.
  3. Требуется выбирать в выпадающем списке нужный пункт и далее нажимать кнопку для применения настроек.

Понимаю что это все можно сделать через WinApi но не понимаю где взять описания функций (желательно на русском) и как их встраивать в код C#.
Например, как это делалось в VB 6.0 помню.

Answer 1
  • c# справится. Справится любой язык умеющий вызывать winapi
  • Хуже только тем, что нужно объявить функции winapi и возможно структуры
  • у vb те же возможности, что и у c#

Вам сюда http://www.pinvoke.net/ за тем как объявлять функции winapi в c# и vb.net

Возможно подойдет что-то более высокоуровневое вроде Cruciatus от 2GIS

Answer 2

Для вашей задачи вполне подойдёт стандартный майкрософтовский UI Automation. Вот пример без 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);

(изменяет размер окна notepad.exe на 300х300).

Не забудьте подключить сборки UIAutomationClient и UIAutomationTypes и добавить контроль ошибок.

В MSDN есть документация об остальной функциональности UI Automation. Например, как активировать контрол (нажать на кнопку, выбрать пункт меню и т. п.).

Список всех подокон и их доступных свойств легко подсмотреть при помощи утилиты Inspect.exe из Windows SDK.

После небольшого упражнения в гуглопоиске на стэковерфлоу, вот более серьёзный пример:

// находим бегущий 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}");

В коде используется следующий простой хелпер:

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 справится точно так же, функциональность UI Automation доступна в обоих языках.

Добавил паузы в секунду между действиями и адаптировал к русской системе (другие названия пунктов меню), результат:

READ ALSO
Не получается разобраться с Ajax и getJSON

Не получается разобраться с Ajax и getJSON

Привет, есть сервер http://codeitpro/frontTestTask/user/registration

353
счётчик при вводе символов в Input

счётчик при вводе символов в Input

при старте в features-elem__symbols-number показываеться максимальное количество введеных символов(например 30), при вводе начинает считать сколько можно...

285
Как в autocomplete сделать несколько столбцов?

Как в autocomplete сделать несколько столбцов?

А хочется чтобы выглядело так:

322
Select2 выбирается предыдущее поле для поиска

Select2 выбирается предыдущее поле для поиска

На странице имеется три поля select с подключенным к ним Select2При активации одного из полей и открытия выпадающего списка поиск по нему не происходит,...

375