gpt4 book ai didi

c# - UIA Automation 元素 GDI Target 应用程序过程中的泄漏

转载 作者:太空宇宙 更新时间:2023-11-03 14:58:18 30 4
gpt4 key购买 nike

我已经创建了自己的扩展方法,其中包含自动化元素实现以在运行时查找任何 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/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com