UIA 抛出COMException的解决方案

Introducation

在基于UI Automation平台的软件UI 自动化测试中,找控件的过程中有时候会出现如下异常:

System.Runtime.InteropServices.COMException (0x80042002): Exception from HRESULT: 0x80042002at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)

at MS.Internal.Automation.UiaCoreApi.CheckError(Int32 hr)

at MS.Internal.Automation.UiaCoreApi.UiaFind(SafeNodeHandle hnode, UiaFindParams findParams, Condition findCondition, UiaCacheRequest request)

at System.Windows.Automation.AutomationElement.Find(TreeScope scope, Condition condition, UiaCacheRequest request, Boolean findFirst, BackgroundWorker worker)

at System.Windows.Automation.AutomationElement.FindFirst(TreeScope scope, Condition condition)

— End of inner exception stack trace —

 

 

通过在网上查找相关的资料,得知抛出COMException的原因是使用了非托管资源,在程序运行中GC无法自动回收相应的垃圾,进而导致此异常出现。

Solution

 

注:测试如下方法需要引入如下命名空间using System.Windows.Automation;

using System.Runtime.InteropServices;

 

如下代码为通过window name来查找window窗体的AutomationElement对象:

/// <summary>/// Find target window by window name.

/// </summary>

/// <param name=”windowName”>Window name</param>

/// <returns>Return target window element</returns>

public static AutomationElement FindWindowByWindowName(string windowName)

{

AutomationElement targetWindow = null;

int count = 0;

try

{

targetWindow = AutomationElement.FromHandle(WindowPtr(windowName));

return targetWindow;

}

catch (Exception)

{

Console.WriteLine(“Try #” + count + 1 + ” to find the target element”);

count++;

if (count > 10)

{

throw new COMException (“Target window is not existing ,please run the program and  try it again”);

}

GC.Collect();

        Thread.Sleep(3000);

        return FindWindowByWindowName(windowName);

}

}

 

#region FindWindow Handing

/// <summary>

/// Find window with win32 API

/// </summary>

/// <param name=”lpClassName”>Class name</param>

/// <param name=”lpWindowName”>WindowName</param>

/// <returns></returns>

[DllImport(“USER32.DLL”)]

public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

/// <summary>

/// Find window IntPtr

/// </summary>

/// <param name=”windowName”>Application WindowName</param>

private static IntPtr WindowPtr(string windowName)

{

IntPtr intPtr = FindWindow(null, windowName);

return intPtr;

}

#endregion

 

在上面的方法中,我们通过USER32.DLL中的FindWindow函数还获取对应窗体的IntPtr类型的对象,在FindWindowByWindowName方法中通过捕获COMException来循环调用此方法,一旦捕获到此异常,使用GC.Collect();来强制进行垃圾回收,是非托管资源被释放,这样在循环执行此方法时将不会应为内存错误而导致无法继续执行。经过测试发现,此种解决方案虽然不是最好的方法,但确实可以解燃眉之急。

Reference

http://social.msdn.microsoft.com/forums/en-US/csharpgeneral/thread/13004a05-8fa8-4b9c-b1f5-eff469f32235

http://msdn.microsoft.com/zh-cn/library/s5zscb2d(VS.80).aspx

相关新闻

发表评论

电子邮件地址不会被公开。 必填项已用*标注

联系我们

400-800-8888

在线咨询:点击这里给我发消息

邮件:ijumper@163.com

工作时间:周一至周五,9:30-18:30,节假日休息