2

我正在使用一套驱动 IE 的 WatiN 测试来进行一些定期的健全性检查,以监控站点。

当我以交互方式调用它和/或将任务计划程序中的任务配置为“仅在用户登录时运行”时,该套件工作正常。

但是,当我将其设置为“无论用户是否登录时运行”,并选中“以最高权限运行”选项(WatiN 无法在 Windows Server 2008 和许多其他操作系统下令人满意地与浏览器对话而无需管理员特权),WatiN 无法与它的 iexplore.exe 实例进行令人满意的通信(它们开始了,但我得到了一个超时异常,如本文所述)。我已将我正在访问的站点添加到 IE 的管理员和非管理员上下文的受信任站点中。我尝试过使用和不使用提升,使用和不禁用 ESC,以及使用和不关闭互联网区域的保护模式。由于我的非 GUI 测试很开心,我认为这是在非交互式计划任务的上下文中可能的交互类型的限制,即使“以最高权限运行”也是如此。

现在,我的临时解决方法是要求 [TS] 会话始终保持打开状态,准备好运行计划任务。

如果我要坚持这一点,我至少会添加一个心跳通知,以允许某些东西监视任务实际上正在运行[例如,如果有人注销会话或重新启动机器]。

但是,我正在寻找更永久的东西——能够在我的 Windows Server 2008 [x64] 机器上定期调用我的 WatiN 测试 [使用 xunit-console.x86.exe v 1.5 运行] 的东西,就像任务计划程序一样,但是具有适当的交互式会话。

如果可能的话,我宁愿不使用 psexec 或 remcom,而且除了添加另一个故障点之外,我看不到创建 Windows 服务会如何做任何事情,但我很想听听所有经过验证的解决方案。

4

2 回答 2

4

我能够在“无论用户是否登录时运行”模式下使用计划任务运行 Watin 测试。在我的情况下,我将问题跟踪到 m_Proc.MainWindowHandle 始终为 0,当 IE 是从没有登录用户的情况下运行的计划任务创建时。在 Watin 来源中,这是在 IE.cs:CreateIEPartiallyInitializedInNewProcess 函数中

我的解决方法是手动枚举顶级窗口并找到一个属于进程的带有 className == "IEFrame" 的窗口,而不是使用 Process.MainWindowHandle 属性。

这是代码片段。我直接从 Watin 源复制了所有 pinvoke。

   public static class IEBrowserHelper
    {
        private static Process CreateIExploreInNewProcess()
        {
            var arguments = "about:blank";

            arguments = "-noframemerging " + arguments;

            var m_Proc = Process.Start("IExplore.exe", arguments);
            if (m_Proc == null) throw new WatiN.Core.Exceptions.WatiNException("Could not start IExplore.exe process");

            return m_Proc;
        }
        class IeWindowFinder
        {
            #region Interop
            [DllImport("user32.dll", SetLastError = true)]
            static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
            public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
            [DllImport("user32.dll", SetLastError = true)]
            public static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
            [DllImport("user32", EntryPoint = "GetClassNameA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
            internal static extern int GetClassName(IntPtr handleToWindow, StringBuilder className, int maxClassNameLength);
            #endregion

            readonly Process IeProcess;
            IntPtr HWnd = IntPtr.Zero;

            public IeWindowFinder(Process ieProcess)
            {
                this.IeProcess = ieProcess;
            }
            public IntPtr Find()
            {
                EnumWindows(FindIeWindowCallback, IntPtr.Zero);
                return HWnd;
            }

            bool FindIeWindowCallback(IntPtr hWnd, IntPtr lParam)
            {
                uint processId;
                GetWindowThreadProcessId(hWnd, out processId);
                if (processId == IeProcess.Id)
                {
                    int maxCapacity = 255;
                    var sbClassName = new StringBuilder(maxCapacity);
                    var lRes = GetClassName(hWnd, sbClassName, maxCapacity);
                    string className = lRes == 0 ? String.Empty : sbClassName.ToString();
                    if (className == "IEFrame")
                    {
                        this.HWnd = hWnd;
                        return false;
                    }
                }
                return true;
            }
        }

        public static WatiN.Core.IE CreateIEBrowser()
        {
            Process ieProcess = CreateIExploreInNewProcess();

            IeWindowFinder findWindow = new IeWindowFinder(ieProcess);

            var action = new WatiN.Core.UtilityClasses.TryFuncUntilTimeOut(TimeSpan.FromSeconds(WatiN.Core.Settings.AttachToBrowserTimeOut))
            {
                SleepTime = TimeSpan.FromMilliseconds(500)
            };

            IntPtr hWnd = action.Try(() =>
            {
                return findWindow.Find();
            });
            ieProcess.Refresh();
            return  WatiN.Core.IE.AttachTo<WatiN.Core.IE>(
                new WatiN.Core.Constraints.AttributeConstraint("hwnd", hWnd.ToString()), 5);
        }
    }

然后代替 new IE() 使用 IEBrowserHelper.CreateIEBrowser()

于 2012-03-06T11:16:12.800 回答
0

从命令提示符中,您可以安排这样的交互式任务:

C:\Users\someUser>schtasks /create /sc once /st 16:28 /tn someTask /tr cmd.exe

... 其中 sc 是计划,st 是开始时间,tn 是您选择的任务名称(可以是任何名称),tr 是您要运行的命令。显然,对于重复任务,您可以将 sc 更改为每月、每周等。只需键入“schtasks /create /?” 了解更多信息。

于 2012-01-05T22:41:29.100 回答