WatiN LogonDialogHandlers не работает правильно в Windows 7 - PullRequest
8 голосов
/ 15 мая 2010

Я недавно обновился до Windows 7, VS2010 и IE8.У нас есть пакет автоматизации, который выполняет тесты для IE с использованием WatiN.Эти тесты требуют использования обработчика диалогового окна входа для регистрации различных пользователей AD в браузере IE.

Это прекрасно работает при использовании Windows XP и IE8, но теперь использование Windows 7 привело к тому, что диалоговое окно безопасности Windows больше не распознается, диалоговое окно просто игнорируется.Этот метод используется для запуска браузера:

        public static Browser StartBrowser(string url, string username, string password)
        {
            Browser browser = new IE();
            WatiN.Core.DialogHandlers.LogonDialogHandler ldh = new WatiN.Core.DialogHandlers.LogonDialogHandler(username, password);
            browser.DialogWatcher.Add(ldh);
            browser.GoTo(url);
            return browser;
        }

любые предложения или помощь будут с благодарностью ...

Ответы [ 7 ]

7 голосов
/ 14 июля 2010

По какой-либо причине в опубликованном Клинтом коде содержались комментарии вместо ввода имени пользователя, пароля и отправки, а также ссылка на неопределенный метод, но в остальном все в порядке. Вот несколько завершенных (и работающих) кодов:

    public static Browser Win7Login(string username, string password, string URL) {
        Process ieProcess = Process.Start("iexplore.exe", URL);
        ieProcess.WaitForInputIdle();

        Thread.Sleep(2000);

        AutomationElement ieWindow = AutomationElement.FromHandle(ieProcess.MainWindowHandle);
        string t = ieWindow.Current.ClassName.ToString();

        Condition conditions = new AndCondition(new PropertyCondition(AutomationElement.IsEnabledProperty, true),
                                   new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window));
        Condition List_condition = new AndCondition(new PropertyCondition(AutomationElement.IsEnabledProperty, true),
                                        new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ListItem));
        Condition Edit_condition = new AndCondition(new PropertyCondition(AutomationElement.IsEnabledProperty, true),
                                    new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit));
        Condition button_conditions = new AndCondition(new PropertyCondition(AutomationElement.IsEnabledProperty, true),
                                     new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button));

        AutomationElementCollection c = ieWindow.FindAll(TreeScope.Children, conditions);
        foreach (AutomationElement child in c) {
            if (child.Current.ClassName.ToString() == "#32770") {
                // find the list
                AutomationElementCollection lists = child.FindAll(TreeScope.Children, List_condition);
                // find the buttons
                AutomationElementCollection buttons = child.FindAll(TreeScope.Children, button_conditions);

                foreach (AutomationElement list in lists) {
                    if (list.Current.ClassName.ToString() == "UserTile") {
                        AutomationElementCollection edits = list.FindAll(TreeScope.Children, Edit_condition);
                        foreach (AutomationElement edit in edits) {
                            if (edit.Current.Name.Contains("User name")) {
                                edit.SetFocus();
                                ValuePattern usernamePattern = edit.GetCurrentPattern(ValuePattern.Pattern) as ValuePattern;
                                usernamePattern.SetValue(username);
                            }
                            if (edit.Current.Name.Contains("Password")) {
                                edit.SetFocus();
                                ValuePattern passwordPattern = edit.GetCurrentPattern(ValuePattern.Pattern) as ValuePattern;
                                passwordPattern.SetValue(password);
                            }
                        }
                    }
                }
                foreach (AutomationElement button in buttons) {
                    if (button.Current.AutomationId == "SubmitButton") {
                        InvokePattern submitPattern = button.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;
                        submitPattern.Invoke();
                        break;
                    }
                }
            }
        }
        return IE.AttachTo<IE>(Find.By("hwnd", ieWindow.Current.NativeWindowHandle.ToString()), 30);
    }
5 голосов
/ 06 апреля 2011

Это также можно изменить как DialogHandler, например:

public class Windows7LogonDialogHandler : BaseDialogHandler
{
    private readonly string _username;
    private readonly string _password;
    AndCondition _conditions = new AndCondition(new PropertyCondition(AutomationElement.IsEnabledProperty, true),
                                   new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window));

    readonly AndCondition _listCondition = new AndCondition(new PropertyCondition(AutomationElement.IsEnabledProperty, true),
                                    new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ListItem));

    readonly AndCondition _editCondition = new AndCondition(new PropertyCondition(AutomationElement.IsEnabledProperty, true),
                                new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit));

    readonly AndCondition _buttonConditions = new AndCondition(new PropertyCondition(AutomationElement.IsEnabledProperty, true),
                                 new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button));

    public Windows7LogonDialogHandler(string username, string password)
    {
        _username = username;
        _password = password;
    }

    public override bool HandleDialog(Window window)
    {
        if(CanHandleDialog(window))
        {
            var win = AutomationElement.FromHandle(window.Hwnd);
            var lists = win.FindAll(TreeScope.Children, _listCondition);
            var buttons = win.FindAll(TreeScope.Children, _buttonConditions);
            var another = (from AutomationElement list in lists
                           where list.Current.ClassName == "UserTile"
                           where list.Current.Name == "Use another account"
                           select list).First();
            another.SetFocus();

            foreach (var edit in from AutomationElement list in lists
                                 where list.Current.ClassName == "UserTile"
                                 select list.FindAll(TreeScope.Children, _editCondition)
                                     into edits
                                     from AutomationElement edit in edits
                                     select edit)
            {
                if (edit.Current.Name.Contains("User name"))
                {
                    edit.SetFocus();
                    var usernamePattern = edit.GetCurrentPattern(ValuePattern.Pattern) as ValuePattern;
                    if (usernamePattern != null) usernamePattern.SetValue(_username);
                }
                if (edit.Current.Name.Contains("Password"))
                {
                    edit.SetFocus();
                    var passwordPattern = edit.GetCurrentPattern(ValuePattern.Pattern) as ValuePattern;
                    if (passwordPattern != null) passwordPattern.SetValue(_password);
                }
            }
            foreach (var submitPattern in from AutomationElement button in buttons
                                          where button.Current.AutomationId == "SubmitButton"
                                          select button.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern)
            {
                submitPattern.Invoke();
                break;
            }
            return true;
        }
        return false;
    }

    public override bool CanHandleDialog(Window window)
    {
        return window.ClassName == "#32770";
    }
}

Что немного приятнее. Затем вы можете использовать его так:

using(var ie = new IE())
        {
            ie.DialogWatcher.Add(new Windows7LogonDialogHandler(@"domain\user", "password"));
            ie.GoTo("http://mysecuredwebsite");
        }
2 голосов
/ 18 января 2011

Пост Николаса Райли работает как шарм, однако использование System.Windows.Automation может быть немного сложнее. Я думал, что Microsoft поместит это в GAC, но это не так, по крайней мере, для меня работает Windows 7 Professional. Я даже скачал Automation Toolkit с здесь .

Оказывается, здесь есть тема переполнения стека, которая показывает, где находятся библиотеки DLL, которые вы можете просмотреть, чтобы включить в качестве ссылок в ваш проект. Ссылка для этого здесь .

По сути, вам просто нужно сослаться на две DLL. UIAutomationClient.dll и UIAutomationTypes.dll (оба находятся в одном каталоге).

2 голосов
/ 21 мая 2010

Мы в конечном итоге решили эту проблему, используя Windows Automation 3.0 API, чтобы выбрать диалоговое окно и обработать вход в систему. Это было сделано следующим образом:

  1. Запустите процесс IE и назначьте его элементу AutomationElement
  2. Теперь у вас есть возможность просматривать дочерние элементы IEFrame, выбирая поля ввода имени пользователя и пароля.
  3. Затем отправьте имя пользователя и пароль

После проверки подлинности браузера мы присоединяем его к объекту браузера WatiN IE. Код следует ниже:

        public static Browser LoginToBrowser(string UserName, string Password, string URL)
    {

        AutomationElement element = StartApplication("IEXPLORE.EXE", URL);
        Thread.Sleep(2000);
        string t = element.Current.ClassName.ToString();

             Condition conditions = new AndCondition(new PropertyCondition(AutomationElement.IsEnabledProperty, true),
                                        new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window));
            Condition List_condition = new AndCondition(new PropertyCondition(AutomationElement.IsEnabledProperty, true),
                                            new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ListItem));
            Condition Edit_condition = new AndCondition(new PropertyCondition(AutomationElement.IsEnabledProperty, true),
                                        new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit));
            Condition button_conditions = new AndCondition(new PropertyCondition(AutomationElement.IsEnabledProperty, true),
                                         new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button));

        AutomationElementCollection c = element.FindAll(TreeScope.Children, conditions);
        foreach (AutomationElement child in c)
        {
            if (child.Current.ClassName.ToString() == "#32770")
            {
                //find the list
                AutomationElementCollection lists = child.FindAll(TreeScope.Children, List_condition);
                // find the buttons
                AutomationElementCollection buttons = child.FindAll(TreeScope.Children, button_conditions);

                foreach (AutomationElement list in lists)
                {
                    if (list.Current.ClassName.ToString() == "UserTile")
                    {
                        AutomationElementCollection edits = list.FindAll(TreeScope.Children, Edit_condition);
                        foreach (AutomationElement edit in edits)
                        {
                            if (edit.Current.Name.Contains("User name"))
                            {
                                edit.SetFocus();
                                //send the user name
                            }
                            if (edit.Current.Name.Contains("Password"))
                            {
                                edit.SetFocus();
                                //send the password
                            }
                        }
                    }
                }
                foreach (AutomationElement button in buttons)
                {
                    if (button.Current.AutomationId == "SubmitButton")
                    {
                        //click the button 
                        break;
                    }
                }
            }            
        }
        return IE.AttachToIE(Find.By("hwnd", element.Current.NativeWindowHandle.ToString()), 30) ;
    }

Мы использовали инструмент под названием UI Spy для проверки интерфейса Windows. Если вы запустите его на XP и Win7, вы сможете ясно увидеть, как изменилась структура диалогового окна безопасности Windows между двумя ОС.

0 голосов
/ 06 апреля 2011

Я попытался использовать два приведенных выше примера автоматизации и обнаружил, что они не обрабатывают сценарий, когда запоминаются другие учетные данные, и в этом случае вы видите только пароль в поле. В этом случае вам необходимо программно щелкнуть раздел «Использовать другую учетную запись». Поэтому я изменил предоставленный код, чтобы сделать это, и теперь он работает нормально. Вот модифицированный код:

public static Browser Win7Login(string username, string password, string url)
    {
        var ieProcess = Process.Start("iexplore.exe", url);
        ieProcess.WaitForInputIdle();

        Thread.Sleep(2000);

        var ieWindow = AutomationElement.FromHandle(ieProcess.MainWindowHandle);

        var conditions = new AndCondition(new PropertyCondition(AutomationElement.IsEnabledProperty, true),
                                   new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window));
        var listCondition = new AndCondition(new PropertyCondition(AutomationElement.IsEnabledProperty, true),
                                        new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ListItem));
        var editCondition = new AndCondition(new PropertyCondition(AutomationElement.IsEnabledProperty, true),
                                    new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit));
        var buttonConditions = new AndCondition(new PropertyCondition(AutomationElement.IsEnabledProperty, true),
                                     new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button));

        var c = ieWindow.FindAll(TreeScope.Children, conditions);

        foreach (AutomationElement child in c)
        {
            if (child.Current.ClassName == "#32770")
            {
                // find the list
                var lists = child.FindAll(TreeScope.Children, listCondition);
                // find the buttons
                var buttons = child.FindAll(TreeScope.Children, buttonConditions);

                var another = (from AutomationElement list in lists
                              where list.Current.ClassName == "UserTile"
                              where list.Current.Name == "Use another account"
                              select list).First();

                another.SetFocus();

                foreach (var edit in from AutomationElement list in lists
                                                   where list.Current.ClassName == "UserTile"
                                                   select list.FindAll(TreeScope.Children, editCondition)
                                                   into edits from AutomationElement edit in edits select edit)
                {
                    if (edit.Current.Name.Contains("User name"))
                    {
                        edit.SetFocus();
                        var usernamePattern = edit.GetCurrentPattern(ValuePattern.Pattern) as ValuePattern;
                        if (usernamePattern != null) usernamePattern.SetValue(username);
                    }
                    if (edit.Current.Name.Contains("Password"))
                    {
                        edit.SetFocus();
                        var passwordPattern = edit.GetCurrentPattern(ValuePattern.Pattern) as ValuePattern;
                        if (passwordPattern != null) passwordPattern.SetValue(password);
                    }
                }
                foreach (var submitPattern in from AutomationElement button in buttons
                                                        where button.Current.AutomationId == "SubmitButton"
                                                        select button.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern)
                {
                    submitPattern.Invoke();
                    break;
                }
            }
        }
        return IE.AttachTo<IE>(Find.By("hwnd", ieWindow.Current.NativeWindowHandle.ToString()), 30);
    }

Спасибо всем, кто проделал мне большую часть пути туда.

0 голосов
/ 27 мая 2010

Если вы зададите какой-либо процесс, выполняющий ваш watin, для запуска в качестве администратора в Windows 7, DialogHandlers будут работать нормально.

0 голосов
/ 20 мая 2010

Поскольку никто не ответил на ваш вопрос, я отвечу, но, к сожалению, без готового решения.

У меня нет Windows 7, чтобы попробовать в данный момент, но кажется, что LogonDialogHandler WatiN не совместим с Windows 7, поэтому вы должны написать свой DialogHandler. Самый простой способ - наследовать от BaseDialogHandler. Вы можете посмотреть исходный код существующих обработчиков диалогов в WatiN. Я сделал себя очень простым и не универсальным для обработки диалога сертификатов . WinSpy ++ может быть очень полезен при реализации.

...