- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我已经创建了自己的扩展方法,其中包含自动化元素实现以在运行时查找任何 Win32、WPF 控件。
我已将动态属性和父控件作为输入,并使用 UIA 概念找到控件,并再次将控件作为 CodedUI 控件 (WinControls/WpfControls) 返回。
我实现了这个概念,因为一些自定义控件没有使用 CodedUI 识别,在实现这个 UIA 概念之后,自动化代码的稳定性得到了提高。
当以 Smoke/Regression 的形式执行脚本时,没有遇到任何问题,但在使用 CycleTest 执行相同操作时(就像我们过去运行 Smoke 脚本 30 次重复一样)在 Target 应用程序进程中始终出现 GDI 内存泄漏,而我没有遇到此类 UIMap 问题。
我尝试了很多方法来释放 GDI 对象,但没有一种对我有帮助。已将我的包装器方法放在这里。
public static T DetectControl<T>(this Object parentControl, Object attributes,
[Optional]bool shouldUseAEToFind, [Optional] PropertyExpressionOperator propertyExpression,
bool isLogMandatory = true, bool shouldScrollIntoView = false) where T : UITestControl, new()
{
#region Local Variables
AE.AutomationElement outputAutomationElement = null;
AE.AutomationElement inputAutomationElement = null;
List<AE.Condition> list_conditions = new List<AE.Condition>();
string technologyName = string.Empty;
string controlType = string.Empty;
T returnControl = new T();
if (!returnControl.GetType().Name.ToLower().Equals("uitestcontrol"))
{
technologyName = returnControl.TechnologyName;
if (!returnControl.GetType().Name.ToString().EndsWith("Control"))
{
controlType = returnControl.ControlType.Name;
}
}
StringBuilder allAttributesValue = new StringBuilder();
string localizedControlType = string.Empty;
bool flag = false;
ICollection<KeyValuePair<string, object>> IColl_properties = null;
List<T> list_matchingControls = null;
IntPtr intPtr = IntPtr.Zero;
#endregion
try
{
LogWriter.WriteDayLog(messageType.information,
"DetectControl method successfully called to find control with the given properties",
logStatus.DONE);
if (!shouldUseAEToFind)
returnControl.Container = (UITestControl)parentControl;
if (attributes.GetType().Name.Contains("Expando"))
{
IColl_properties = (ICollection<KeyValuePair<string, object>>)attributes;
}
else
{
IColl_properties = attributes.GetType().GetProperties().ToDictionary(x => x.Name.ToString(), x => x.GetValue(attributes));
}
foreach (KeyValuePair<string, object> keyValyePair in IColl_properties)
{
if (shouldUseAEToFind == false)
{
if (propertyExpression == PropertyExpressionOperator.EqualTo)
{
returnControl.SearchProperties.Add(keyValyePair.Key, keyValyePair.Value.ToString());
}
else
{
returnControl.SearchProperties.Add(keyValyePair.Key, keyValyePair.Value.ToString(), PropertyExpressionOperator.Contains);
}
}
else
{
if (keyValyePair.Key == "LocalizedControlType")
{
localizedControlType = keyValyePair.Value.ToString();
}
if (propertyExpression == PropertyExpressionOperator.EqualTo)
{
list_conditions.Add(new AE.PropertyCondition(GetAutomationProperty(keyValyePair.Key), (object)keyValyePair.Value));
}
else
{
if (keyValyePair.Key == "LocalizedControlType")
{
list_conditions.Add(new AE.PropertyCondition(GetAutomationProperty(keyValyePair.Key), (object)keyValyePair.Value));
}
}
}
if (IColl_properties.Last().Key != keyValyePair.Key)
{
allAttributesValue.Append(keyValyePair.Key + " : " + keyValyePair.Value + " | ");
}
else
{
allAttributesValue.Append(keyValyePair.Key + " : " + keyValyePair.Value);
}
}
if (localizedControlType == string.Empty && shouldUseAEToFind && propertyExpression == PropertyExpressionOperator.Contains)
{
throw new InvalidDataException("Please provide a LocalizedControlType to proceed further.");
}
LogWriter.WriteDayLog(messageType.trace, "Started to find the control with the given properties --> "
+ allAttributesValue.ToString(), logStatus.DONE);
if (shouldUseAEToFind)
{
LogWriter.WriteDayLog(messageType.information, "Finding the control based on the Automation Element", logStatus.DONE);
inputAutomationElement = parentControl.GetInputAutomationElement(isLogMandatory);
if (propertyExpression == PropertyExpressionOperator.EqualTo)
{
try
{
outputAutomationElement = inputAutomationElement.FindFirst(AE.TreeScope.Children
| AE.TreeScope.Descendants | AE.TreeScope.Element,
new AE.AndCondition(list_conditions.ToArray()));
}
catch (Exception ex)
{
if (isLogMandatory)
{
LogWriter.WriteDayLog(messageType.exception, "Failed to do FindFirst, encountered exception", logStatus.FAIL);
}
else
{
LogWriter.WriteDayLog(messageType.warning, "Failed to do FindFirst, encountered exception", logStatus.WARNING);
}
throw ex;
}
if (outputAutomationElement != null)
{
LogWriter.WriteDayLog(messageType.information, "outputAutomationElement is found", logStatus.DONE);
}
else
throw new Exception("outputAutomationElement is null");
if (shouldScrollIntoView)
{
LogWriter.WriteDayLog(messageType.information, "shouldScrollIntoView is true",
logStatus.DONE);
outputAutomationElement.ScrollIntoView();
}
bool visibleFlag = outputAutomationElement.Current.BoundingRectangle.Location.X == 0 ? outputAutomationElement.Current.BoundingRectangle.Location.Y > 0 : true;
if (visibleFlag)
{
switch (technologyName)
{
case "UIA":
LogWriter.WriteDayLog(messageType.information, "Try to find the control using FromNativeElement, UIA",
logStatus.DONE);
returnControl = (T)UITestControlFactory.FromNativeElement(outputAutomationElement, "UIA");
break;
default:
LogWriter.WriteDayLog(messageType.information, "technologyName is " + technologyName,
logStatus.DONE);
if (string.IsNullOrWhiteSpace(technologyName) || technologyName.Equals("MSAA"))
{
try
{
LogWriter.WriteDayLog(messageType.information, "Try to find the control using FromPoint",
logStatus.DONE);
if (localizedControlType.ToLower() != "window")
{
returnControl = (T)UITestControlFactory.FromPoint(outputAutomationElement.GetClickablePoint());
}
else
{
intPtr = new IntPtr(outputAutomationElement.Current.NativeWindowHandle);
returnControl = (T)UITestControlFactory.FromWindowHandle(intPtr);
}
}
catch (AE.NoClickablePointException)
{
LogWriter.WriteDayLog(messageType.information, "Unable to find the control using GetClickablePoint, try FromWindowHandle", logStatus.DONE);
intPtr = new IntPtr(outputAutomationElement.Current.NativeWindowHandle);
returnControl = (T)UITestControlFactory.FromWindowHandle(intPtr);
}
catch (Exception ex)
{
if (!ex.Message.Contains("Access is denied"))
{
LogWriter.WriteDayLog(messageType.exception, "Failed to find the control, encountered exception",
logStatus.FAIL);
throw new Exception(ex.Message);
}
else
{
intPtr = new IntPtr(outputAutomationElement.Current.NativeWindowHandle);
returnControl = (T)UITestControlFactory.FromWindowHandle(intPtr);
}
}
}
else
{
throw new Exception("Different Technology has been captured : " + technologyName.ToUpper());
}
break;
}
}
else
{
returnControl = null;
}
}
else
{
list_matchingControls = inputAutomationElement.DetectIdenticalControls<T>(new { LocalizedControlType = localizedControlType }, true, isLogMandatory: isLogMandatory);
foreach (KeyValuePair<string, object> keyValyePair in IColl_properties)
{
switch (keyValyePair.Key.ToLower())
{
case "name":
returnControl = (T)list_matchingControls.First(x => x.GetInspectProperty(InspectProperty.NAME).ToLower().Contains(keyValyePair.Value.ToString().ToLower()));
break;
case "classname":
returnControl = (T)list_matchingControls.First(x => x.GetInspectProperty(InspectProperty.CLASSNAME).ToLower().Contains(keyValyePair.Value.ToString().ToLower()));
break;
case "automationid":
returnControl = (T)list_matchingControls.First(x => x.GetInspectProperty(InspectProperty.AUTOMATIONID).ToLower().Contains(keyValyePair.Value.ToString().ToLower()));
break;
}
}
}
}
else
{
LogWriter.WriteDayLog(messageType.information, "Finding the control based on default CodedUI Search properties", logStatus.DONE);
flag = returnControl.TryFind();
}
}
catch (InvalidCastException ex)
{
throw new Exception(ex.Message);
}
catch (InvalidDataException idex)
{
throw new Exception(idex.Message);
}
catch (Exception e)
{
if (isLogMandatory)
{
LogWriter.WriteDayLog(messageType.exception, "Failed to find the control with the given properties --> " + allAttributesValue.ToString() + ", it throws >> " + e.ToString(), logStatus.FAIL);
}
else
{
LogWriter.WriteDayLog(messageType.warning, "Failed to find the control with the given properties --> " + allAttributesValue.ToString() + ", it throws >> " + e.ToString(), logStatus.WARNING);
}
returnControl = null;
}
finally
{
if (flag || returnControl != null)
{
LogWriter.WriteDayLog(messageType.trace, "Successfully found the control with the given properties --> " + allAttributesValue.ToString(), logStatus.DONE);
}
else
{
if (isLogMandatory)
{
LogWriter.WriteDayLog(messageType.error, "Unable to find the control with the given properties --> " + allAttributesValue.ToString(), logStatus.FAIL);
}
else
{
LogWriter.WriteDayLog(messageType.warning, "Unable to find the control with the given properties --> " + allAttributesValue.ToString(), logStatus.WARNING);
}
returnControl = null;
}
#region Variable Cleanup
list_conditions = null;
technologyName = null;
controlType = null;
allAttributesValue = null;
localizedControlType = null;
IColl_properties = null;
list_matchingControls = null;
parentControl = null;
AEDispose(inputAutomationElement);
AEDispose(outputAutomationElement);
AEDispose(null, intPtr);
#endregion
}
return returnControl;
}
internal static void AEDispose(AE.AutomationElement automationElement, [Optional]IntPtr wHandle)
{
if (automationElement != null)
{
IntPtr windowHandle = IntPtr.Zero;
if (wHandle == IntPtr.Zero)
windowHandle = new IntPtr(automationElement.Current.NativeWindowHandle);
else
windowHandle = wHandle;
var deviceContext = GetWindowDC(windowHandle);
var compatibleDeviceContext = CreateCompatibleDC(deviceContext);
DeleteDC(compatibleDeviceContext);
ReleaseDC(windowHandle, deviceContext);
DeleteObject(windowHandle);
}
}
[DllImport("GDI32.dll")]
private static extern bool DeleteDC(IntPtr hDC);
[DllImport("GDI32.dll")]
private static extern bool DeleteObject(IntPtr hObject);
[DllImport("GDI32.dll")]
private static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);
[DllImport("User32.dll")]
private static extern IntPtr GetWindowDC(IntPtr hWnd);
[DllImport("User32.dll")]
private static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDC);
[DllImport("GDI32.dll")]
private static extern IntPtr CreateCompatibleDC(IntPtr hDC);
internal static AE.AutomationProperty GetAutomationProperty(string propertyName)
{
#region Local Variables
AE.AutomationProperty property = null;
#endregion
try
{
switch (propertyName.ToLower())
{
case "localizedcontroltype":
property = AE.AutomationElement.LocalizedControlTypeProperty;
break;
case "name":
property = AE.AutomationElement.NameProperty;
break;
case "automationid":
property = AE.AutomationElement.AutomationIdProperty;
break;
case "classname":
property = AE.AutomationElement.ClassNameProperty;
break;
}
}
catch (Exception e)
{
LogWriter.WriteDayLog(messageType.exception, "Unable to get the automation property, it throws exception >> " + e.Message, logStatus.FAIL);
}
return property;
}
internal static AE.AutomationElement GetInputAutomationElement(this Object parentControl, bool isLogMandatory = true)
{
#region Local Variables
UITestControl uiControl = null;
AE.AutomationElement inputAutomationElement = null;
#endregion
try
{
if (parentControl != null)
{
if (!parentControl.GetType().Name.ToLower().Contains("automation"))
{
uiControl = (UITestControl)parentControl;
try
{
inputAutomationElement = (AE.AutomationElement)(uiControl.ControlType.ToString() == "Window" ? AE.AutomationElement.FromHandle(uiControl.WindowHandle) : uiControl.NativeElement);
LogWriter.WriteDayLog(messageType.information, "inputAutomationElement is found, uiControl.ControlType is "
+ uiControl.ControlType.ToString(), logStatus.DONE);
}
catch (InvalidCastException ex)
{
if (ex.Message.Contains("Unable to cast object of type 'System.Object[]' to type 'System.Windows.Automation.AutomationElement"))
{
inputAutomationElement = AE.AutomationElement.FromHandle(uiControl.WindowHandle);
}
}
}
else
{
inputAutomationElement = (AE.AutomationElement)parentControl;
}
}
else
{
inputAutomationElement = AE.AutomationElement.RootElement;
}
LogWriter.WriteDayLog(messageType.information, "Successfully converted the given control into Automaiton Element", logStatus.PASS);
}
catch (Exception ex)
{
if (isLogMandatory)
{
LogWriter.WriteDayLog(messageType.exception, "Unable to convert given control to Automation Element, throws exception >> "
+ ex.Message, logStatus.FAIL);
}
else
{
LogWriter.WriteDayLog(messageType.trace, "Unable to convert given control to Automation Element, throws exception >> "
+ ex.Message + " So assigning Desktop as Root AutomationElement", logStatus.DONE);
inputAutomationElement = AE.AutomationElement.RootElement;
}
}
#region Variable Cleanup
uiControl = null;
#endregion
return inputAutomationElement;
}
最佳答案
我过去经历过这些的原因是因为我不断得到一个从未在我们的 VB6 应用程序中被垃圾回收的控件。我建议只获取将在整个应用程序生命周期中存在的任何控件的一个实例。对我们来说,这恰好是一个丝带酒吧。每次我获得一个新的自动化元素时,它都会强制 VB6 应用程序创建一个支持该控件的自动化对等体,并且会泄漏内存和 GDI 对象。
这blog很好地说明了 UIA 中客户端(您的 UIA 测试)和服务器(被测应用程序)之间的通信方式。
关于c# - UIA Automation 元素 GDI Target 应用程序过程中的泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47713698/
我是 C 语言新手,我编写了这个 C 程序,让用户输入一年中的某一天,作为返回,程序将输出月份以及该月的哪一天。该程序运行良好,但我现在想简化该程序。我知道我需要一个循环,但我不知道如何去做。这是程序
我一直在努力找出我的代码有什么问题。这个想法是创建一个小的画图程序,并有红色、绿色、蓝色和清除按钮。我有我能想到的一切让它工作,但无法弄清楚代码有什么问题。程序打开,然后立即关闭。 import ja
我想安装screen,但是接下来我应该做什么? $ brew search screen imgur-screenshot screen
我有一个在服务器端工作的 UDP 套接字应用程序。为了测试服务器端,我编写了一个简单的 python 客户端程序,它发送消息“hello world how are you”。服务器随后应接收消息,将
我有一个 shell 脚本,它运行一个 Python 程序来预处理一些数据,然后运行一个 R 程序来执行一些长时间运行的任务。我正在学习使用 Docker 并且我一直在运行 FROM r-base:l
在 Linux 中。我有一个 c 程序,它读取一个 2048 字节的文本文件作为输入。我想从 Python 脚本启动 c 程序。我希望 Python 脚本将文本字符串作为参数传递给 c 程序,而不是将
前言 最近开始整理笔记里的库存草稿,本文是 23 年 5 月创建的了(因为中途转移到 onedrive,可能还不止) 网页调起电脑程序是经常用到的场景,比如百度网盘下载,加入 QQ 群之类的 我
对于一个类,我被要求编写一个 VHDL 程序,该程序接受两个整数输入 A 和 B,并用 A+B 替换 A,用 A-B 替换 B。我编写了以下程序和测试平台。它完成了实现和行为语法检查,但它不会模拟。尽
module Algorithm where import System.Random import Data.Maybe import Data.List type Atom = String ty
我想找到两个以上数字的最小公倍数 求给定N个数的最小公倍数的C++程序 最佳答案 int lcm(int a, int b) { return (a/gcd(a,b))*b; } 对于gcd,请查看
这个程序有错误。谁能解决这个问题? Error is :TempRecord already defines a member called 'this' with the same paramete
当我运行下面的程序时,我在 str1 和 str2 中得到了垃圾值。所以 #include #include #include using namespace std; int main() {
这是我的作业: 一对刚出生的兔子(一公一母)被放在田里。兔子在一个月大时可以交配,因此在第二个月的月底,每对兔子都会生出两对新兔子,然后死去。 注:在第0个月,有0对兔子。第 1 个月,有 1 对兔子
我编写了一个程序,通过对字母使用 switch 命令将十进制字符串转换为十六进制,但是如果我使用 char,该程序无法正常工作!没有 switch 我无法处理 9 以上的数字。我希望你能理解我,因为我
我是 C++ 新手(虽然我有一些 C 语言经验)和 MySQL,我正在尝试制作一个从 MySQL 读取数据库的程序,我一直在关注这个 tutorial但当我尝试“构建”解决方案时出现错误。 (我正在使
仍然是一个初学者,只是尝试使用 swift 中的一些基本函数。 有人能告诉我这段代码有什么问题吗? import UIKit var guessInt: Int var randomNum = arc
我正在用 C++11 编写一个函数,它采用 constant1 + constant2 形式的表达式并将它们折叠起来。 constant1 和 constant2 存储在 std::string 中,
我用 C++ 编写了这段代码,使用运算符重载对 2 个矩阵进行加法和乘法运算。当我执行代码时,它会在第 57 行和第 59 行产生错误,非法结构操作(两行都出现相同的错误)。请解释我的错误。提前致谢:
我是 C++ 的初学者,我想编写一个简单的程序来交换字符串中的两个字符。 例如;我们输入这个字符串:“EXAMPLE”,我们给它交换这两个字符:“E”和“A”,输出应该类似于“AXEMPLA”。 我在
我需要以下代码的帮助: 声明 3 个 double 类型变量,每个代表三角形的三个边中的一个。 提示用户为第一面输入一个值,然后 将用户的输入设置为您创建的代表三角形第一条边的变量。 将最后 2 个步
我是一名优秀的程序员,十分优秀!