重复下载不可靠吗?

发布于 2024-11-01 01:10:50 字数 988 浏览 8 评论 0原文

WatiN 似乎不能一致地处理重复的下载对话框:

        foreach (string file in lstFiles)
        {
            // continue if no download link
            if (!ie.Element([search criteria]).Exists) continue;

            var btnDownload = ie.Element([search criteria]);
            string fullFilename = workingDir + "\\" + file;
            FileDownloadHandler download = new FileDownloadHandler(fullFilename);
            using (new UseDialogOnce(ie.DialogWatcher, download))
            {
                btnDownload.ClickNoWait();

                download.WaitUntilFileDownloadDialogIsHandled(30);
                download.WaitUntilDownloadCompleted(150);
                ie.RemoveDialogHandler(download);
            }
        }

基本上,我循环浏览我期望可用的文件名列表,然后单击下载按钮。这通常有效,但是经过多次下载(情况各不相同,有时所有可用的下载,有时什么都没有),它会在等待处理对话框时挂起。该按钮被正确识别,下载对话框出现,只是没有被检测和处理。它不是特定于站点的,因为其他站点上的类似方法也取得了不同程度的成功。有人以前遇到过这个问题并知道解决方法吗?

编辑:重复下载在 Server 2008 中不起作用。在 Win7 中,这种情况在一次或多次成功重复下载后随机发生。

WatiN seems to not handle repeated download dialogs consistently:

        foreach (string file in lstFiles)
        {
            // continue if no download link
            if (!ie.Element([search criteria]).Exists) continue;

            var btnDownload = ie.Element([search criteria]);
            string fullFilename = workingDir + "\\" + file;
            FileDownloadHandler download = new FileDownloadHandler(fullFilename);
            using (new UseDialogOnce(ie.DialogWatcher, download))
            {
                btnDownload.ClickNoWait();

                download.WaitUntilFileDownloadDialogIsHandled(30);
                download.WaitUntilDownloadCompleted(150);
                ie.RemoveDialogHandler(download);
            }
        }

Basically, I loop through a list of filenames that I expect to be available and click the download button. This usually works, but after so many downloads (it varies, sometimes everything that's available downloads, sometimes nothing) it will hang while waiting to handle the dialog. The button's identified correctly, the download dialog appears, it just isn't detected and handled. It isn't site-specific as similar methods on other sites are also met with variable success. Anyone encounter this before and know of a resolution?

edit: Repeated downloads do not work whatsoever in Server 2008. In Win7, this happens randomly after one or more successful repeated downloads.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

冷默言语 2024-11-08 01:10:50

出现此问题的原因是 IE 文件下载对话框由 2 个窗口组成。 WatiN DialogWatcher 获取所有系统窗口并尝试在 foreach 循环中处理它们。处理第一个正确的对话框窗口后,DialogWatcher 获取下一个具有相同属性并且是有效下载对话框的窗口。 DialogWatcher 开始等待,直到该窗口可见,但在处理前一个窗口后立即关闭。
我的解决方案是在处理任何对话框后从 foreach 循环返回:

    #region WatiN Copyright (C) 2006-2011 Jeroen van Menen

//Copyright 2006-2011 Jeroen van Menen
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

#endregion Copyright

using System;
using System.Collections.Generic;
using System.Threading;
using WatiN.Core.Exceptions;
using WatiN.Core.Interfaces;
using WatiN.Core.Logging;
using WatiN.Core.Native.InternetExplorer;
using WatiN.Core.Native.Windows;
using WatiN.Core.UtilityClasses;

namespace WatiN.Core.DialogHandlers
{
    /// <summary>
    /// This class handles alert/popup dialogs. Every second it checks if a dialog
    /// is shown. If so, it stores it's message in the alertQueue and closses the dialog
    /// by clicking the close button in the title bar.  
    /// </summary>
    public class DialogWatcher : IDisposable
    {
        private static IList<DialogWatcher> dialogWatchers = new List<DialogWatcher>();

        private bool _keepRunning = true;
        private readonly IList<IDialogHandler> _handlers;
        private readonly Thread _watcherThread;
        private bool _closeUnhandledDialogs = Settings.AutoCloseDialogs;

        public Window MainWindow { get; private set; }


        /// <summary>
        /// Gets the dialog watcher for the specified (main) internet explorer window. 
        /// It creates new instance if no dialog watcher for the specified window exists.
        /// </summary>
        /// <param name="mainWindowHwnd">The (main) internet explorer window.</param>
        /// <returns></returns>
        public static DialogWatcher GetDialogWatcher(IntPtr mainWindowHwnd)
        {
            var window = new Window(mainWindowHwnd);
            Logger.LogDebug("GetDialogWatcher mainhwnd: " + window.Hwnd + ", " + window.Title);

            var toplevelWindow = window.ToplevelWindow;
            Logger.LogDebug("GetDialogWatcher mainhwnd: " + toplevelWindow.Hwnd + ", " + toplevelWindow.Title);

            CleanupDialogWatcherCache();

            var dialogWatcher = GetDialogWatcherFromCache(toplevelWindow);

            // If no dialogwatcher exists for the ieprocessid then 
            // create a new one, store it and return it.
            if (dialogWatcher == null)
            {
                dialogWatcher = new DialogWatcher(toplevelWindow);

                dialogWatchers.Add(dialogWatcher);
            }

            return dialogWatcher;
        }

        public static DialogWatcher GetDialogWatcherFromCache(Window mainWindow)
        {
            // Loop through already created dialogwatchers and
            // return a dialogWatcher if one exists for the given processid
            foreach (var dialogWatcher in dialogWatchers)
            {
                if (dialogWatcher.MainWindow.Equals(mainWindow))
                {
                    return dialogWatcher;
                }
            }

            return null;
        }

        public static void CleanupDialogWatcherCache()
        {
            var cleanedupDialogWatcherCache = new List<DialogWatcher>();

            foreach (var dialogWatcher in dialogWatchers)
            {
                if (!dialogWatcher.IsRunning)
                {
                    dialogWatcher.Dispose();
                }
                else
                {
                    cleanedupDialogWatcherCache.Add(dialogWatcher);
                }
            }

            dialogWatchers = cleanedupDialogWatcherCache;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="DialogWatcher"/> class.
        /// You are encouraged to use the Factory method <see cref="DialogWatcher.GetDialogWatcherFromCache"/>
        /// instead.
        /// </summary>
        /// <param name="mainWindow">The main window handle of internet explorer.</param>
        public DialogWatcher(Window mainWindow)
        {
            MainWindow = mainWindow;

            _handlers = new List<IDialogHandler>();

            // Create thread to watch windows
            _watcherThread = new Thread(Start);
            // Start the thread.
            _watcherThread.Start();
        }

        /// <summary>
        /// Increases the reference count of this DialogWatcher instance with 1.
        /// </summary>
        public void IncreaseReferenceCount()
        {
            ReferenceCount++;
        }

        /// <summary>
        /// Decreases the reference count of this DialogWatcher instance with 1.
        /// When reference count becomes zero, the Dispose method will be 
        /// automatically called. This method will throw an <see cref="ReferenceCountException"/>
        /// if the reference count is zero.
        /// </summary>
        public void DecreaseReferenceCount()
        {
            if (ReferenceCount > 0)
            {
                ReferenceCount--;
            }
            else
            {
                throw new ReferenceCountException();
            }

            if (ReferenceCount == 0)
            {
                Dispose();
            }
        }

        /// <summary>
        /// Adds the specified handler.
        /// </summary>
        /// <param name="handler">The handler.</param>
        public void Add(IDialogHandler handler)
        {
            lock (this)
            {
                _handlers.Add(handler);
            }
        }

        /// <summary>
        /// Removes the specified handler.
        /// </summary>
        /// <param name="handler">The handler.</param>
        public void Remove(IDialogHandler handler)
        {
            lock (this)
            {
                _handlers.Remove(handler);
            }
        }

        /// <summary>
        /// Removes all instances that match <paramref name="handler"/>.
        /// This method determines equality by calling Object.Equals.
        /// </summary>
        /// <param name="handler">The object implementing IDialogHandler.</param>
        /// <example>
        /// If you want to use RemoveAll with your custom dialog handler to
        /// remove all instances of your dialog handler from a DialogWatcher instance,
        /// you should override the Equals method in your custom dialog handler class 
        /// like this:
        /// <code>
        /// public override bool Equals(object obj)
        /// {
        ///   if (obj == null) return false;
        ///   
        ///   return (obj is YourDialogHandlerClassNameGoesHere);
        /// }                               
        /// </code>
        /// You could also inherit from <see cref="BaseDialogHandler"/> instead of implementing
        /// <see cref="IDialogHandler"/> in your custom dialog handler. <see cref="BaseDialogHandler"/> provides
        /// overrides for Equals and GetHashCode that work with RemoveAll.
        /// </example>
        public void RemoveAll(IDialogHandler handler)
        {
            while (Contains(handler))
            {
                Remove(handler);
            }
        }

        /// <summary>
        /// Removes all registered dialog handlers.
        /// </summary>
        public void Clear()
        {
            lock (this)
            {
                _handlers.Clear();
            }
        }

        /// <summary>
        /// Determines whether this <see cref="DialogWatcher"/> contains the specified dialog handler.
        /// </summary>
        /// <param name="handler">The dialog handler.</param>
        /// <returns>
        ///     <c>true</c> if [contains] [the specified handler]; otherwise, <c>false</c>.
        /// </returns>
        public bool Contains(IDialogHandler handler)
        {
            lock (this)
            {
                return _handlers.Contains(handler);
            }
        }

        /// <summary>
        /// Gets the count of registered dialog handlers.
        /// </summary>
        /// <value>The count.</value>
        public int Count
        {
            get
            {
                lock (this)
                {
                    return _handlers.Count;
                }
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether unhandled dialogs should be closed automaticaly.
        /// The initial value is set to the value of <cref name="Settings.AutoCloseDialogs" />.
        /// </summary>
        /// <value>
        ///     <c>true</c> if unhandled dialogs should be closed automaticaly; otherwise, <c>false</c>.
        /// </value>
        public bool CloseUnhandledDialogs
        {
            get
            {
                lock (this)
                {
                    return _closeUnhandledDialogs;
                }
            }
            set
            {
                lock (this)
                {
                    _closeUnhandledDialogs = value;
                }
            }
        }

        /// <summary>
        /// Gets the (main) internet explorer window handle this dialog watcher watches.
        /// </summary>
        /// <value>The process id.</value>
        public IntPtr MainWindowHwnd
        {
            get { return MainWindow.Hwnd; }
        }

        /// <summary>
        /// Called by the constructor to start watching popups
        /// on a separate thread.
        /// </summary>
        private void Start()
        {
            while (_keepRunning)
            {
                if (MainWindow.Exists())
                {
                    var winEnumerator = new WindowsEnumerator();
                    var windows = winEnumerator.GetWindows(win => true);

                    foreach (var window in windows)
                    {
                        if (!_keepRunning) return;
                        if(HandleWindow(window))
                            break;
                    }

                    // Keep DialogWatcher responsive during 1 second sleep period
                    var count = 0;
                    while (_keepRunning && count < 5)
                    {
                        Thread.Sleep(200);
                        count++;
                    }
                }
                else
                {
                    _keepRunning = false;
                }

            }
        }

        public bool IsRunning
        {
            get { return _watcherThread.IsAlive; }
        }

        public int ReferenceCount { get; private set; }

        /// <summary>
        /// Get the last stored exception thrown by a dialog handler while 
        /// calling the <see cref="IDialogHandler.HandleDialog"/> method of the
        /// dialog handler.
        /// </summary>
        /// <value>The last exception.</value>
        public Exception LastException { get; private set; }

        /// <summary>
        /// If the window is a dialog and visible, it will be passed to
        /// the registered dialog handlers. I none if these can handle
        /// it, it will be closed if <see cref="CloseUnhandledDialogs"/>
        /// is <c>true</c>.
        /// </summary>
        /// <param name="window">The window.</param>
        /// <returns>
        /// <c>true</c> if dialog is handled by one of handlers; otherwise, <c>false</c>.
        /// </returns>
        public bool HandleWindow(Window window)
        {
            if (!window.IsDialog()) return false;
            if (!HasDialogSameProcessNameAsBrowserWindow(window)) return false;

            // This is needed otherwise the window Style will return a "wrong" result.
            WaitUntilVisibleOrTimeOut(window);

            // Lock the thread and see if a handler will handle
            // this dialog window
            lock (this)
            {
                foreach (var dialogHandler in _handlers)
                {
                    try
                    {
                        if (dialogHandler.CanHandleDialog(window, MainWindow.Hwnd))
                        {
                            if (dialogHandler.HandleDialog(window)) return true;
                        }
                    }
                    catch (Exception e)
                    {
                        LastException = e;

                        Logger.LogAction((LogFunction log) => { log("Exception was thrown while DialogWatcher called HandleDialog: {0}",e.ToString()); });
                    }
                }

                // If no handler handled the dialog, see if the dialog
                // should be closed automatically.
                if (!CloseUnhandledDialogs || !MainWindow.Equals(window.ToplevelWindow)) return false;

                Logger.LogAction((LogFunction log) => { log("Auto closing dialog with title: '{0}', text: {1}, style: ", window.Title, window.Message, window.StyleInHex); });
                window.ForceClose();
            }
            return false;
        }

        private bool HasDialogSameProcessNameAsBrowserWindow(Window window)
        {
            var comparer = new Comparers.StringComparer(window.ProcessName, true);
            return comparer.Compare(MainWindow.ProcessName);
        }

        private static void WaitUntilVisibleOrTimeOut(Window window)
        {
            // Wait untill window is visible so all properties
            // of the window class (like Style and StyleInHex)
            // will return valid values.
            var tryActionUntilTimeOut = new TryFuncUntilTimeOut(TimeSpan.FromSeconds(Settings.WaitForCompleteTimeOut));
            var success = tryActionUntilTimeOut.Try(() => window.Visible);

            if (!success)
            {
                Logger.LogAction((LogFunction log) => { log("Dialog with title '{0}' not visible after {1} seconds.", window.Title, Settings.WaitForCompleteTimeOut); });
            }
        }

        #region IDisposable Members

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or
        /// resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            lock (this)
            {
                _keepRunning = false;
            }
            if (IsRunning)
            {
                _watcherThread.Join();
            }
            Clear();
        }

        #endregion
    }
}

The problem appears because IE File Download Dialog consist of 2 windows. WatiN DialogWatcher gets all the system windows and tries to handle them in foreach loop. After handling first correct dialog window DialogWatcher gets the next window wich has the same properties and is a valid Download Dialog. DialogWatcher starts waiting until this window is visible but it closes immediately after previos window is handled.
My solution is to return from foreach loop after any dialog is handled:

    #region WatiN Copyright (C) 2006-2011 Jeroen van Menen

//Copyright 2006-2011 Jeroen van Menen
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

#endregion Copyright

using System;
using System.Collections.Generic;
using System.Threading;
using WatiN.Core.Exceptions;
using WatiN.Core.Interfaces;
using WatiN.Core.Logging;
using WatiN.Core.Native.InternetExplorer;
using WatiN.Core.Native.Windows;
using WatiN.Core.UtilityClasses;

namespace WatiN.Core.DialogHandlers
{
    /// <summary>
    /// This class handles alert/popup dialogs. Every second it checks if a dialog
    /// is shown. If so, it stores it's message in the alertQueue and closses the dialog
    /// by clicking the close button in the title bar.  
    /// </summary>
    public class DialogWatcher : IDisposable
    {
        private static IList<DialogWatcher> dialogWatchers = new List<DialogWatcher>();

        private bool _keepRunning = true;
        private readonly IList<IDialogHandler> _handlers;
        private readonly Thread _watcherThread;
        private bool _closeUnhandledDialogs = Settings.AutoCloseDialogs;

        public Window MainWindow { get; private set; }


        /// <summary>
        /// Gets the dialog watcher for the specified (main) internet explorer window. 
        /// It creates new instance if no dialog watcher for the specified window exists.
        /// </summary>
        /// <param name="mainWindowHwnd">The (main) internet explorer window.</param>
        /// <returns></returns>
        public static DialogWatcher GetDialogWatcher(IntPtr mainWindowHwnd)
        {
            var window = new Window(mainWindowHwnd);
            Logger.LogDebug("GetDialogWatcher mainhwnd: " + window.Hwnd + ", " + window.Title);

            var toplevelWindow = window.ToplevelWindow;
            Logger.LogDebug("GetDialogWatcher mainhwnd: " + toplevelWindow.Hwnd + ", " + toplevelWindow.Title);

            CleanupDialogWatcherCache();

            var dialogWatcher = GetDialogWatcherFromCache(toplevelWindow);

            // If no dialogwatcher exists for the ieprocessid then 
            // create a new one, store it and return it.
            if (dialogWatcher == null)
            {
                dialogWatcher = new DialogWatcher(toplevelWindow);

                dialogWatchers.Add(dialogWatcher);
            }

            return dialogWatcher;
        }

        public static DialogWatcher GetDialogWatcherFromCache(Window mainWindow)
        {
            // Loop through already created dialogwatchers and
            // return a dialogWatcher if one exists for the given processid
            foreach (var dialogWatcher in dialogWatchers)
            {
                if (dialogWatcher.MainWindow.Equals(mainWindow))
                {
                    return dialogWatcher;
                }
            }

            return null;
        }

        public static void CleanupDialogWatcherCache()
        {
            var cleanedupDialogWatcherCache = new List<DialogWatcher>();

            foreach (var dialogWatcher in dialogWatchers)
            {
                if (!dialogWatcher.IsRunning)
                {
                    dialogWatcher.Dispose();
                }
                else
                {
                    cleanedupDialogWatcherCache.Add(dialogWatcher);
                }
            }

            dialogWatchers = cleanedupDialogWatcherCache;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="DialogWatcher"/> class.
        /// You are encouraged to use the Factory method <see cref="DialogWatcher.GetDialogWatcherFromCache"/>
        /// instead.
        /// </summary>
        /// <param name="mainWindow">The main window handle of internet explorer.</param>
        public DialogWatcher(Window mainWindow)
        {
            MainWindow = mainWindow;

            _handlers = new List<IDialogHandler>();

            // Create thread to watch windows
            _watcherThread = new Thread(Start);
            // Start the thread.
            _watcherThread.Start();
        }

        /// <summary>
        /// Increases the reference count of this DialogWatcher instance with 1.
        /// </summary>
        public void IncreaseReferenceCount()
        {
            ReferenceCount++;
        }

        /// <summary>
        /// Decreases the reference count of this DialogWatcher instance with 1.
        /// When reference count becomes zero, the Dispose method will be 
        /// automatically called. This method will throw an <see cref="ReferenceCountException"/>
        /// if the reference count is zero.
        /// </summary>
        public void DecreaseReferenceCount()
        {
            if (ReferenceCount > 0)
            {
                ReferenceCount--;
            }
            else
            {
                throw new ReferenceCountException();
            }

            if (ReferenceCount == 0)
            {
                Dispose();
            }
        }

        /// <summary>
        /// Adds the specified handler.
        /// </summary>
        /// <param name="handler">The handler.</param>
        public void Add(IDialogHandler handler)
        {
            lock (this)
            {
                _handlers.Add(handler);
            }
        }

        /// <summary>
        /// Removes the specified handler.
        /// </summary>
        /// <param name="handler">The handler.</param>
        public void Remove(IDialogHandler handler)
        {
            lock (this)
            {
                _handlers.Remove(handler);
            }
        }

        /// <summary>
        /// Removes all instances that match <paramref name="handler"/>.
        /// This method determines equality by calling Object.Equals.
        /// </summary>
        /// <param name="handler">The object implementing IDialogHandler.</param>
        /// <example>
        /// If you want to use RemoveAll with your custom dialog handler to
        /// remove all instances of your dialog handler from a DialogWatcher instance,
        /// you should override the Equals method in your custom dialog handler class 
        /// like this:
        /// <code>
        /// public override bool Equals(object obj)
        /// {
        ///   if (obj == null) return false;
        ///   
        ///   return (obj is YourDialogHandlerClassNameGoesHere);
        /// }                               
        /// </code>
        /// You could also inherit from <see cref="BaseDialogHandler"/> instead of implementing
        /// <see cref="IDialogHandler"/> in your custom dialog handler. <see cref="BaseDialogHandler"/> provides
        /// overrides for Equals and GetHashCode that work with RemoveAll.
        /// </example>
        public void RemoveAll(IDialogHandler handler)
        {
            while (Contains(handler))
            {
                Remove(handler);
            }
        }

        /// <summary>
        /// Removes all registered dialog handlers.
        /// </summary>
        public void Clear()
        {
            lock (this)
            {
                _handlers.Clear();
            }
        }

        /// <summary>
        /// Determines whether this <see cref="DialogWatcher"/> contains the specified dialog handler.
        /// </summary>
        /// <param name="handler">The dialog handler.</param>
        /// <returns>
        ///     <c>true</c> if [contains] [the specified handler]; otherwise, <c>false</c>.
        /// </returns>
        public bool Contains(IDialogHandler handler)
        {
            lock (this)
            {
                return _handlers.Contains(handler);
            }
        }

        /// <summary>
        /// Gets the count of registered dialog handlers.
        /// </summary>
        /// <value>The count.</value>
        public int Count
        {
            get
            {
                lock (this)
                {
                    return _handlers.Count;
                }
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether unhandled dialogs should be closed automaticaly.
        /// The initial value is set to the value of <cref name="Settings.AutoCloseDialogs" />.
        /// </summary>
        /// <value>
        ///     <c>true</c> if unhandled dialogs should be closed automaticaly; otherwise, <c>false</c>.
        /// </value>
        public bool CloseUnhandledDialogs
        {
            get
            {
                lock (this)
                {
                    return _closeUnhandledDialogs;
                }
            }
            set
            {
                lock (this)
                {
                    _closeUnhandledDialogs = value;
                }
            }
        }

        /// <summary>
        /// Gets the (main) internet explorer window handle this dialog watcher watches.
        /// </summary>
        /// <value>The process id.</value>
        public IntPtr MainWindowHwnd
        {
            get { return MainWindow.Hwnd; }
        }

        /// <summary>
        /// Called by the constructor to start watching popups
        /// on a separate thread.
        /// </summary>
        private void Start()
        {
            while (_keepRunning)
            {
                if (MainWindow.Exists())
                {
                    var winEnumerator = new WindowsEnumerator();
                    var windows = winEnumerator.GetWindows(win => true);

                    foreach (var window in windows)
                    {
                        if (!_keepRunning) return;
                        if(HandleWindow(window))
                            break;
                    }

                    // Keep DialogWatcher responsive during 1 second sleep period
                    var count = 0;
                    while (_keepRunning && count < 5)
                    {
                        Thread.Sleep(200);
                        count++;
                    }
                }
                else
                {
                    _keepRunning = false;
                }

            }
        }

        public bool IsRunning
        {
            get { return _watcherThread.IsAlive; }
        }

        public int ReferenceCount { get; private set; }

        /// <summary>
        /// Get the last stored exception thrown by a dialog handler while 
        /// calling the <see cref="IDialogHandler.HandleDialog"/> method of the
        /// dialog handler.
        /// </summary>
        /// <value>The last exception.</value>
        public Exception LastException { get; private set; }

        /// <summary>
        /// If the window is a dialog and visible, it will be passed to
        /// the registered dialog handlers. I none if these can handle
        /// it, it will be closed if <see cref="CloseUnhandledDialogs"/>
        /// is <c>true</c>.
        /// </summary>
        /// <param name="window">The window.</param>
        /// <returns>
        /// <c>true</c> if dialog is handled by one of handlers; otherwise, <c>false</c>.
        /// </returns>
        public bool HandleWindow(Window window)
        {
            if (!window.IsDialog()) return false;
            if (!HasDialogSameProcessNameAsBrowserWindow(window)) return false;

            // This is needed otherwise the window Style will return a "wrong" result.
            WaitUntilVisibleOrTimeOut(window);

            // Lock the thread and see if a handler will handle
            // this dialog window
            lock (this)
            {
                foreach (var dialogHandler in _handlers)
                {
                    try
                    {
                        if (dialogHandler.CanHandleDialog(window, MainWindow.Hwnd))
                        {
                            if (dialogHandler.HandleDialog(window)) return true;
                        }
                    }
                    catch (Exception e)
                    {
                        LastException = e;

                        Logger.LogAction((LogFunction log) => { log("Exception was thrown while DialogWatcher called HandleDialog: {0}",e.ToString()); });
                    }
                }

                // If no handler handled the dialog, see if the dialog
                // should be closed automatically.
                if (!CloseUnhandledDialogs || !MainWindow.Equals(window.ToplevelWindow)) return false;

                Logger.LogAction((LogFunction log) => { log("Auto closing dialog with title: '{0}', text: {1}, style: ", window.Title, window.Message, window.StyleInHex); });
                window.ForceClose();
            }
            return false;
        }

        private bool HasDialogSameProcessNameAsBrowserWindow(Window window)
        {
            var comparer = new Comparers.StringComparer(window.ProcessName, true);
            return comparer.Compare(MainWindow.ProcessName);
        }

        private static void WaitUntilVisibleOrTimeOut(Window window)
        {
            // Wait untill window is visible so all properties
            // of the window class (like Style and StyleInHex)
            // will return valid values.
            var tryActionUntilTimeOut = new TryFuncUntilTimeOut(TimeSpan.FromSeconds(Settings.WaitForCompleteTimeOut));
            var success = tryActionUntilTimeOut.Try(() => window.Visible);

            if (!success)
            {
                Logger.LogAction((LogFunction log) => { log("Dialog with title '{0}' not visible after {1} seconds.", window.Title, Settings.WaitForCompleteTimeOut); });
            }
        }

        #region IDisposable Members

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or
        /// resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            lock (this)
            {
                _keepRunning = false;
            }
            if (IsRunning)
            {
                _watcherThread.Join();
            }
            Clear();
        }

        #endregion
    }
}
能否归途做我良人 2024-11-08 01:10:50

我的团队在使用 WatiN 自动化 IE8 时也遇到了这个问题。问题似乎与 IE 相关,可能需要进行一些耗时的清理工作。我们最终使用的解决方法是在外部循环中调用 IE 的 new 实例,每次迭代都会处理它,然后等待 5 秒以解决后台发生的任何问题。这是一次黑客攻击,但完成了工作。

foreach (var file in lstFiles)
{
    string fullFilename = workingDir + "\\" + file;
    using (var browser = new IE(fullFilename))
    {
        //page manipulations...

        FileDownloadHandler download = new FileDownloadHandler(fullFilename);
        using (new UseDialogOnce(browser.DialogWatcher, download))
        { //lnkFile.ClickNoWait(); 
            download.WaitUntilFileDownloadDialogIsHandled(15);
            download.WaitUntilDownloadCompleted(150);
        }
    }
    Thread.Sleep(5000);
}

My team ran into this as well while automating IE8 with WatiN. The problem seems to be with IE, possibly doing some time consuming house-cleaning. The work-around we ultimately used was to invoke a new instance of IE within the outer loop, disposing of it each iteration and then waiting for 5 seconds for whatever was going on in the background to resolve. It was a hack but got the job done.

foreach (var file in lstFiles)
{
    string fullFilename = workingDir + "\\" + file;
    using (var browser = new IE(fullFilename))
    {
        //page manipulations...

        FileDownloadHandler download = new FileDownloadHandler(fullFilename);
        using (new UseDialogOnce(browser.DialogWatcher, download))
        { //lnkFile.ClickNoWait(); 
            download.WaitUntilFileDownloadDialogIsHandled(15);
            download.WaitUntilDownloadCompleted(150);
        }
    }
    Thread.Sleep(5000);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文