我能够在“无论用户是否登录时运行”模式下使用计划任务运行 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()