WatiN LogonDialogHandlers在Windows 7中无法正常工作

时间:2010-05-15 17:48:11

标签: windows-7 watin

我最近更新到Windows 7,VS2010和IE8。我们有一个自动化套件,使用WatiN针对IE运行测试。这些测试需要使用登录对话框处理程序,以便将不同的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 个答案:

答案 0 :(得分:7)

无论出于何种原因,Clint发布的代码都有注释而不是输入用户名,密码和提交,并引用了一个未定义的方法,但是否则可以。这是一些已完成(和正在运行)的代码:

    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);
    }

答案 1 :(得分:5)

这也可以像这样重构为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 :(得分:2)

我们最终通过使用Windows Automation 3.0 API来获取对话框并处理登录来解决此问题。具体操作如下:

  1. 启动IE进程并将其分配给AutomationElement
  2. 您现在可以遍历IEFrame的子元素,选择用户名和密码编辑字段。
  3. 然后发送用户名和密码
  4. 一旦浏览器经过身份验证,我们就会将其附加到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 UI。如果你针对XP和Win7运行它,你可以清楚地看到Windows安全性对话框的结构在两个操作系统之间是如何变化的。

答案 3 :(得分:2)

Nicholas Riley的帖子就像魅力一样,但包括使用System.Windows.Automation可能有点棘手。我认为微软会把它放在GAC中,但它们不会,至少对我来说运行Windows 7专业版。我甚至从here下载了自动化工具包。

原来,这里有一个关于堆栈溢出的主题,它显示了dll的位置,你可以浏览它作为项目中的引用。其链接为here

基本上,你只需要引用两个dll。 UIAutomationClient.dll和UIAutomationTypes.dll(都在同一目录中)。

答案 4 :(得分:0)

由于没有人回答你的问题,我会,但遗憾的是没有现成的解决方案。

此刻我没有尝试使用Windows 7,但似乎WatiN的LogonDialogHandler与Windows 7不兼容,因此您必须编写自己的DialogHandler。最简单的方法是继承BaseDialogHandler。您可以在WatiN中查看现有对话框处理程序的源代码。我使自己变得非常简单而不是普遍的处理certificate dialogWinSpy++在实施过程中非常有用。

答案 5 :(得分:0)

如果您将运行watin的任何进程设置为在Windows 7中以管理员身份运行,则DialogHandler可以正常工作。

答案 6 :(得分:0)

我尝试使用上面的两个自动化示例,发现当其他凭据被记住时,他们没有处理这种情况,在这种情况下,您只能在框中看到密码。在这种情况下,您需要以编程方式单击“使用其他帐户”部分。所以我修改了提供的代码,它现在正常工作。这是修改后的代码:

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);
    }

感谢那些让我大部分时间都在那里的人。