Microsoft UI 自动化库

上一篇 / 下一篇  2008-10-07 18:14:15 / 个人分类:自动测试Framework

以使用多种技术测试Windows®应用程序的用户界面。例如,可以使用System.Reflection类来测试Microsoft®.NET Framework应用程序,也可以使用非托管C++C#或者Visual Basic®通过P/Invoke机制调用Win32®API函数(例如FindWindow)来测试.NET和本机应用程序。

在 本月的专栏中,我将为您介绍如何使用新的Microsoft UI自动化库(包含在.NET Framework 3.0中,是Windows Presentation Foundation (WPF)的一部分)开始进行UI测试自动化。您可以将其看作是Microsoft Active Accessibility (MSAA)库的后继产品,后者最初设计用于可访问性功能,但同时发现它对UI自动化很有用也很适合。另一方面,UI自动化库从一开始就是为可访问性和UI测试自动化任务而专门设计的。您可以使用UI自动化库来测试运行支持.NET Framework 3.0操作系统(例如Windows XPWindows Vista®Windows Server®2003Windows Server 2008)的主机上的Win32应用程序、.NET Windows窗体应用程序和WPF应用程序。

言 归正传,我认为UI自动化库的开发是迄今为止测试自动化领域中最重大的一项进步,并将迅速成为Windows应用程序UI测试自动化方面最常用的技术。与其他用于UI自动化的可选方法相比,UI自动化库功能更强大、往往更易于使用并且更加一致。就像.NET Framework改变了软件应用程序开发一样,我认为UI自动化库极有可能会彻底改变UI测试自动化。

向您阐述我的观点的一个好方法是通过屏幕快照。 1显示的是我将要测试的一个简单的Windows应用程序。该应用程序被称为StatCalc,它可以计算一组整数的算术平均数、几何平均数或调和平均数。算术平均数只是简单的平均。例如,30英寸和60英寸的算术平均数是45英寸。几何平均数用于比例。例如,30:160:1的几何平均数是42.4264:1。调和平均数用于比率。例如,在超过某一固定距离时30英里/小时和60英里/小时的平均数为40英里/小时。

图 1 UI 测试自动化中的示例应用程序
1 UI测试自动化中的示例应用程序(单击该图像获得较小视图)

图 1 UI 测试自动化中的示例应用程序
1 UI测试自动化中的示例应用程序(单击该图像获得较大视图)

 1中所示的UI测试自动化是一个控制台应用程序,它可以启动所测试的应用程序,使用UI自动化库获取对应用程序中的应用程序控件和用户控件的引用,模拟用户输入3060,以及模拟单击“Calculate”(计算)按钮控件。然后测试自动化通过检查结果TextBox控件是否为预期值来查看应用程序的最终状态,并在随后输出通过失败结果。我在测试自动化关闭所测试的应用程序之前捕获屏幕快照。

在 本专栏的其余部分中,我将简要介绍所测试的StatCalc Windows应用程序,并将说明如何启动所测试的应用程序;如何使用UI自动化库获得对应用程序控件和用户控件的引用;以及如何模拟用户操作和查看应用程序状态。我还将为您介绍如何扩展和修改此处介绍的测试系统以满足您的自身需求。我相信您会发现能够使用此新的UI自动化库对您的测试工具集是一个很好的补充。


了解StatCalc

让我们简要了解一下所测试的应用程序,从而使您了解测试自动化的目标。您还将了解为什么说在编写UI测试自动化时能够访问应用程序源代码很有用,而又不是绝对必要的。

StatCalc应用程序是一个简单的基于Windows的窗体。我使用C#为应用程序编写代码,不过UI自动化库也可以与Win32应用程序和WPF应用程序配合工作。为了简单起见,我接受Visual Studio®的默认控件名称,包括Form1label1textBox1groupBox1radioButton1radioButton2radioButton3button1textBox2。我使用MenuStrip控件(在.NET Framework 2.0及更高版本中提供),而非早期的MainMenu控件,增加了顶层菜单项:“File”(文件)和“Help”(帮助)StatCalc应用程序的功能包含在button1_Click方法中,如图 2所示。

用 户单击“Calculate”(计算)按钮时,控制权转至button1_Click方法,该方法将textBox1中的值提取为单字符串。然后使用String.Split方法将每个值解析为字符串数组。接着,单击处理程序将字符串数组转换为整型数组。Button1_Click逻辑将根据选择的单选按钮控件构造分支,以double类型计算相应的平均数,然后将结果的格式设置为四个小数位的字符串形式,显示在textbox2控件中。

在计算几何平均数时,应用程序将调用名为NthRoot的本地helper方法,定义如下:

private static double NthRoot(double x, int n) {
  return Math.Exp( Math.Log(x) / (double)n );
}

在此未执行任何常规错误检查,以确保应用程序代码尽可能的小并且易于理解。

作 为经验之谈,在使用UI自动化库编写测试自动化时,不需要访问所测试系统的源代码。大多数情况下,可以通过控件的标题(例如Calculate)而不是通过控件的内部Name属性(例如button1)访问控件。但是,某些控件(例如,文本框控件)没有标题。

若要使用UI自动化访问没有标题的控件,必需知道它们隐含的索引顺序。这一顺序是初始化窗体时控件加载到主窗体控件(或父控件)中的顺序。隐含的索引顺序不一定要与设计时将控件添加到窗体对象中的顺序一样,而且它与选项卡索引顺序也不一样。

通过查看应用程序源代码可以很容易地确定没有标题的控件的隐含索引顺序。例如,如果我检查StatCalc应用程序的Form1.Designer.cs文件并展开Windows窗体设计器生成的代码区,可以看到以下代码:

this.Controls.Add(this.button1);
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.label1);
this.Controls.Add(this.textBox2);
this.Controls.Add(this.textBox1);
this.Controls.Add(this.menuStrip1);

这意味着button1具有隐含的索引0groupBox1具有索引1,等等。请注意,textBox2控件隐含的索引小于textBox1控件(即使在设计StatCalc应用程序时,将textBox1先于textBox2放到窗体对象上也是如此)。此外,控件radioButton1radioButton2radioButton3groupBox1控件的子控件,而不是Form1的子控件。稍后您将看到,在使用UI自动化库编写测试自动化时,控件树的深度级别是很重要的。

因此,如果可以访问所测试的应用程序的源代码, 就可以轻松地确定控件隐含的索引顺序。但不能访问源代码时的情况如何呢?确定控件隐含的索引顺序的一种方法是使用Visual Studio附带的Spy++工具。启动Spy++后,可按Ctrl+F5然后将GUI Finder工具拖动到任何控件/窗口上获取关于该控件/窗口的详细信息。 3显示了使用Spy++指向textBox1控件时的结果。在背景中,您可以看到textBox1句柄为00080820。在前景中,textBox1后面的下一个控件标题为menuStrip1,而textBox1前面的一个控件没有标题,这个控件是textBox2

图 3 使用 Spy++ 查找隐含的索引顺序
3 使用Spy++查找隐含的索引顺序(单击该图像获得较小视图)

图 3 使用 Spy++ 查找隐含的索引顺序
3 使用Spy++查找隐含的索引顺序(单击该图像获得较大视图)

这样一来,即使您不能访问所测试的应用程序的源代码,也能通过使用Spy++检查每个控件来最终推断所有应用程序控件的隐含的索引顺序。

现 在,即便是通过StatCalc用户界面手动测试像它这样微小的应用程序也会是令人乏味、容易出错、耗时且效率低下。您必须输入一些输入数据,单击“Calculate”(计算)按钮控 件,直观地验证结果值,并手动将“pass/fail”(通过/失败)结果记录到电子表格或数据库中。一个更好的方法是,使用UI自动化库模拟用户执行应用程序,然后确定应用程序是否正确响应。通过自动化枯燥的测试案例,您可以将更多时间用于更有趣且更有用的手动测试案例,在这些测试案例中您的经验和直觉将发挥很大作用。

Back to top


UI
测试自动化代码

图 4显示了我的测试工具的整体结构。启动Visual Studio后,我创建了一个新的Console Application程序。我决定使用C#,但是如果您需要,应能很容易地将我的测试自动化代码转换为Visual Basic或其他任何.NET兼容的语言。接下来,我将项目引用添加到UIAutomationClient.dllUIAutomationTypes.dll库中。这些库是.NET Framework 3.0的一部分,通常位于%PROGRAMFILES%\Reference Assemblies\Microsoft\Framework\v3.0目录中。

UI自动化库体系结构使用客户端-服务器视点和命名约定。从UI测试自动化的角度来看,这意味着所测试的应用程序被称为服务器,测试工具被视为客户端-测试工具客户端向所测试的应用程序(服务器)请求UI信息。UIAutomationClient.dll库实际上就是UI自动化客户端使用的测试自动化库。另外,UIAutomationTypes.dll库包含UIAutomationClient.dll和其他UI自动化服务器库使用的各种类型的定义。

UIAutomationClient.dllUIAutomationTypes.dll库外,您还将看到UIAutomationClientSideProvider.dllUIAutomationProvider.dll库。UIAutomationClientSideProvider.dll库包含一组与构建时不支持自动化的控件配合使用的代码,这些控件可能包括旧式控件和自定义的.NET控件。由于我的应用程序全部使用标准控件(均设计为支持UI自动化),因此我不需要此库。UIAutomationProvider.dll库是一组接口定义,可供创建自定义UI控件和希望控件能被UI自动化库访问的开发人员使用。

添加 我的项目引用后,System.Windows.Automation命名空间将对我的测试工具程序可见,并且我可以向该命名空间中添加using语句。为了方便起见,我添加了指向System.Diagnostics命名空间的using语句(以便能够方便地使用Process类),和指向System.Threading命名空间的using语句(以便能够方便地使用Thread.Sleep方法)。像往常使用任何测试自动化时一样,我将我的工具与顶层try/catch块封装在一起来处理任何致命错误。众所皆知,测试自动化软件机敏睿智,而异常是常事而非例外。

我的测试自动化代码首先启动所测试的应用程序:

Console.WriteLine("\nBegin WPF UIAutomation test run\n");
Console.WriteLine("Launching StatCalc application");
Process p =
    Process.Start("..\\..\\..\\StatCalc\\bin\\Debug\\StatCalc.exe");

请注意,我捕获了所测试的应用程序的进程信息。接下来,我获取对主机的桌面窗口的引用作为AutomationElement

AutomationElement aeDesktop = AutomationElement.RootElement;

大多数对使用UI自动化库进行测试自动化有用的对象都是AutomationElement类型。在此我能使用AutomationElement的静态RootElement属性获得对顶层可视元素(桌面)的引用。在执行UI测试自动化时,将主机上的每个可视实体(控件、窗口等)视为根元素作为桌面窗口的层次树结构的一部分是非常有用的。这是针对各种UI自动化的通用原则,包括使用UI自动化库的自动化。

接下来,我需要获得对主窗体对象的引用,该对象实际上就是StatCalc应用程序。以下说明了实现上述操作的一种简单方法:

// navie approach
Thread.Sleep(5000);
AutomationElement aeForm =
    AutomationElement.FromHandle(p.MainWindowHandle);
if (aeForm == null)
    Console.WriteLine(
        "Could not find the StatCalc Form");

暂停几秒钟以便给我的所测试的应用程序留出启动时间,然后使用FromHandle方法获得对该应用程序的引用。请记住,我在启动所测试的应用程序时保存了该应用程序的进程信息。

尽 管这一方法很奏效,但是它还存在两点小问题。首先,在尝试访问窗体对象之前没有好的方法可用于推测等待时间的长短。因此,必须进行保守估计,设置一个很长 的延迟时间,这将大大减慢测试自动化的速度,在运行数百或数千个测试案例时尤其如此。其次,此方法假定测试工具启动所测试的应用程序(允许您保存有关应用程序的进程信息)。但是,在某些测试情况下,您要测试的应用程序已在运行,因此您将不能立即访问所测试的应用程序的进程信息(虽然您能够以编程方式获得这 些信息)。

在大多数情况下,获得对所测试应用程序的窗体对象(作为AutomationElement)引用的更好方法是使用类似图 5中所示的代码。我就如何以很小的延迟(在本例中为100毫秒)在循环内部获得引用进行了尝试,在盲目请求对应用程序的引用之前无需任意时间的暂停。我跟踪我的工具进入等待循环的次数,在获得非空引用(意味着我找到了窗体对象)时,或在超过最大尝试次数(在本例中为50)时退出。

此外,我使用FindFirst方法,而不使用FromHandle,前者能够继续搜索对AutomationElement的第一个可用的引用,AutomationElement满足作为一对参数传入的特定条件。我的第一个参数TreeScope.Children指示FindFirst仅查看其上下文(在本例中为aeDesktop)的直接子控件,而不需查看其上下文的所有后代。

FindFirst的第二个参数是一个条件:

new PropertyCondition(AutomationElement.NameProperty, "StatCalc")

可以将此代码的含义解释如下:标题(Name属性)的自动化元素等于StatCalc不需要在条件中使用传统的字符串方法来确定控件(例如,Property == StatCalc),UI自动化库的设计人员决定创建PropertyCondition类。这一方法乍看可能有些难以理解且冗繁,但是您很快就能熟悉它。

基 本上,使用完全面向对象的PropertyCondition类(而不使用简单的字符串)来确定控件在编写测试自动化时需要更多代码,但是它也有多个优点。PropertyCondition往往使测试自动化代码的意图非常明确(至少在您熟悉此模式后是这样的)。因为PropertyCondition对象较之字符串是更强类型化的,所以使用PropertyCondition允许集成的开发环境(如Visual Studio)提供设计时IntelliSense®自动完成帮助。它还使编译器能够执行更完善的错误检查。

获得对所测试应用程序的主窗体对象的引用后,我获取了对所有用户控件的引用。例如,在需要获得对“Calculate”(计算)按钮控件的引用时,我可以编写如下代码:

Console.WriteLine("Finding all user controls");
AutomationElement aeButton = aeForm.FindFirst(TreeScope.Children,
  new PropertyCondition(AutomationElement.NameProperty, "Calculate"));

获得用户控件的模式与获得窗体控件的模式是完全相同的。这种一致性是UI自动化库较之许多其他自动化库的一个优点。对于本例中这样使用大量编码类型、使用UI自动化的情况,通常可以使用几种不同的方法来完成任务。例如,若不使用上述代码获得对“Calculate”(计算)按钮控件的引用,我还可以编写如下代码:

AutomationElement aeButton = aeForm.FindFirst(TreeScope.Children,
  new PropertyCondition(AutomationElement.ControlTypeProperty,
    ControlType.Button));

我可以不使用NameProperty,而使用ControlTypePropertyControlType.Button的值。可以将此代码的含义解释为:提取在窗体上找到的第一个按钮控件。此方法仅在此处适用,因为我的窗体对象上只有一个按钮控件。

ControlType类是一种重要的Microsoft UI自动化思路。此类非常简单,可用于确定任何控件的类型。获得对我的既没有标题也没有名称的文本框控件的引用,需要不同的技术:

AutomationElementCollection aeAllTextBoxes =
  aeForm.FindAll(TreeScope.Children,
    new PropertyCondition(AutomationElement.ControlTypeProperty,
      ControlType.Edit));
 
AutomationElement aeTextBox1 = aeAllTextBoxes[1];
AutomationElement aeTextBox2 = aeAllTextBoxes[0];

这里,我使用FindAll方法来检索所有作为我的窗体控件的直接子项的文本框控件。注意,您可能已经猜到,我使用ControlType.Edit来指定文本框控件,而不是类似于ControlType.TextBox的控件。我将我的所有文本框控件存储在AutomationElementCollection中,然后可以按索引访问这些控件。

请回忆一下 先前介绍的内容:textBox2控件具有低于textBox1控件的隐含的索引,因此textBox2位于集合中的位置[0],而textBox1位于集合中的位置[1]。还可以使用其他几种方法来获得对没有标题的控件的引用,但是FindAll方法往往是不错的选择。

以下是我获取对radioButton1控件的引用的方法:

AutomationElement aeRadioButton1 =
  aeForm.FindFirst(TreeScope.Descendants,
    new PropertyCondition(AutomationElement.NameProperty,
      "Arithmetic Mean"));

请注意,因为我当前的上下文是窗体对象,所以我使用TreeScope.Descendants,而不使用TreeScope.ChildrenradioButton控件是groupBox1控件的子项,后者又是Form1控件的子项,因此radioButton控件是Form1的后代,但不是它的子项。或者,我可以首先获得对groupBox1控件(为Form1的子项)的引用,然后再获得对radioButton1(为groupBox1控件的子项)的引用。

在采用上述获得对radioButton1的引用的方法获得对radioButton2(几何平均数)和radioButton3(调和平均数)的引用后,我可以开始执行所测试的应用程序。以下是我模拟用户向textBox1控件中键入一些输入数据的方法:

Console.WriteLine("\nSetting input to '30 60'");
ValuePattern vpTextBox1 =
  (ValuePattern)aeTextBox1.GetCurrentPattern(ValuePattern.Pattern);
vpTextBox1.SetValue("30 60");

SetValue方法可能不会让人感到吃惊,但是请注意我不能通过aeTextBox1对象直接访问SetVaue。因此,我改用中介ValuePattern对象。AutomationPattern对象(如ValuePattern)的概念对于刚接触UI自动化库的工程师来说可能是概念理解上最大的障碍。您可以将模式对象视为用于公开控件功能的一种抽象方法,此方法与控件的类型或外观无关。换句话说,可以使用特定的AutomationPattern实例(如ValuePattern)来启用特定的控件功能。

考 虑到控件的ControlType公开了控件的类型,控件的Pattern公开了控件的作用,我对控件做了进一步简化。此处需要特别注意的是控件可以支持多种模式。以下是我使用AutomationPattern选择radioButton2控件的方法:

Console.WriteLine("Selecting 'Geometric Mean' ");
SelectionItemPattern ipSelectRadioButton2 =
  (SelectionItemPattern)aeRadioButton2.GetCurrentPattern(
    SelectionItemPattern.Pattern );
ipSelectRadioButton2.Select();

这一次我使用SelectionItemPattern来启用选择。GetCurrentPattern方法的名称经常会令UI自动化库初学者困惑。从测试自动化角度来看,此方法将设置(而不是获取)指定的AutomationPattern。而从客户端-服务器的角度来看,自动化客户端代码将从所测试的应用程序的服务器代码中提取特定的属性。以下我用于模拟单击“Calculate”(计算)按钮控件的代 码应该能够有助于阐明上述内容:

  Console.WriteLine("Clicking on Calculate button");
  InvokePattern ipClickButton1 =
    (InvokePattern)aeButton.GetCurrentPattern(
    InvokePattern.Pattern);
  ipClickButton1.Invoke();
  Thread.Sleep(1500);

这里,我使用InvokePattern来启用按钮单击,然后使用Invoke方法执行单击。请注意,我暂停1.5秒以留出我的应用程序响应的时间。我还可以进入延迟循环,使用我将在稍后简要介绍的方法定期进行检查以查看结果textBox2字段是否为空。有18AutomationPattern类型,我已在图 6中列出了这些类型。了解AutomationPattern类是了解如何使用Microsoft UI自动化库执行所测试的应用程序的关键。

此 时,在我的测试自动化代码中,我启动了所测试的应用程序,在输入(textBox1)控件中输入了“30 60”,选择了“Geometric Mean”(几何平均数)(radioButton2)控件,并且单击“Calculate”(计算)(button1)控件。现在,我检查textBox2控件以查看是否得到了预期值:

Console.WriteLine("\nChecking textBox2 for '42.4264'");
TextPattern tpTextBox2 =
  (TextPattern)aeTextBox2.GetCurrentPattern(TextPattern.Pattern);
string result = tpTextBox2.DocumentRange.GetText(-1);

我再次使用AutomationPattern(这次选择TextPattern)以准备调用GetText方法。请注意,我通过DocumentRange属性间接调用GetText,这一调用将返回一个封装有主文本“document”的文本段-在本例中为一个文本框。GetText的参数旨在指明我未对返回字符串的长度设定最大限制。

读取textBox2控件的内容的另一种方法是使用GetCurrentPropertyValue方法,如下所示:

string result =
  (string)aeTextBox2.GetCurrentPropertyValue(
    ValuePattern.ValueProperty);

在设置了AutomationElement控件的某个属性时,GetCurrentPropertyValue方法将返回该控件的当前属性;而在未设置上下文控件的属性时,GetCurrentPropertyValue方法将返回该控件的默认属性的值。在本例中,我未设置textBox2控件的属性,因此带有参数ValuePropertyGetCurrentPropertyValue将返回tetxtBox2控件的默认属性(即Text属性)的值。使用GetCurrentProperty在编码时可节省时间,但是由于控件的当前属性在运行时可能会更改,因此具有风险。

得到计算结果之后,我对照预期值进行检查以确定我的测试方案的结果是通过还是失败:

if (result == "42.4264") {
  Console.WriteLine("Found it");
  Console.WriteLine("\nTest scenario: Pass");
}
else {
  Console.WriteLine("Did not find it");
  Console.WriteLine("\nTest scenario: *FAIL*");
}

现在,我能够关闭所测试的应用程序:

Console.WriteLine("\nClosing application in 5 seconds");
Thread.Sleep(5000);
WindowPattern wpCloseForm =
  (WindowPattern)aeForm.GetCurrentPattern(WindowPattern.Pattern);
wpCloseForm.Close();

我使用WindowPattern类的Close方法,这是针对UI自动化库的主题法。

通过另一种方法也可以关闭所测试应用程序,您可以操作以下代码开头的“File”(文件)|“Exit”(退出)菜单项:

AutomationElement aeMenu =
  aeForm.FindFirst(TreeScope.Children,
    new PropertyCondition(AutomationElement.ControlTypeProperty,
      ControlType.Menu));

但是,ControlType.Menu类型是.NET Framework 1.1 MainMenu控件,不能与较新的MenuStrip控件配合使用。因为我的所测试应用程序使用MenuStrip,所以我无法使用ControlType.Menu类型。这是一个罕见的异常;UI自动化库支持绝大多数用户控件,还通过UIAutomationProvider.dll库中包含的功能提供了对自定义控件的自动化支持。至此我的测试自动化即将完成,我可以记录我的测试案例结果并启动另一个测试方案。

Back to top


扩展测试工具

本 月的专栏中提供的代码将为您开始使用UI自动化库创建自己的测试自动化奠定坚实的基础。正如您已了解的,此库的涵盖面非常广泛,而且其纯面向对象的编程模型与您用过的其他库可能有些不同。但是,我相信您很快就能学会如何使用它编写功能强大的UI测试自动化。值得关注的三个关键概念是:使用ControlType类确定UI控件的类型,使用AutomationPattern类确定UI控件的功能,以及使用PropertyCondition类指定特定的UI控件。

可以使用多种方法来扩展我介绍的这一介绍性测试自动化工具中的观点。一种显而易见的扩展便是 对工具进行参数化。无需对输入和预期值进行硬编码,可以在命令行中将这些信息传递给测试工具。但更好的做法是,将测试案例数据存储创建为文本文件、数据库表或XML文件,在每个测试案例中重复使用,分析出测试案例数据并将这些数据传递到测试工具中。我在20058月的专栏中详细介绍了此类设计模式,请参阅msdn.microsoft.com/msdnmag/issues/05/08/TestRun

我在此专栏中介绍的代码不执行结果日志记录,但是在大多数情况下,您都会希望将测试案例结果记录到数据存储中,而不只是希望通过失败消息输出到命令外壳程序。

我坚信UI自动化库将迅速成为最广泛使用的UI测试自动化框架。除了可供软件工程师免费使用的单一、标准、全面、一致且经过严格测试的UI自动化库之外,不需要其他任何东西。这已经使拥有公共论坛、博客、示例代码等的社区更加完善。

这 并不是说我认定UI自动化库将完全取代其他可选方法(如,商业UI测试自动化框架和自定义的UI自动化框架)。但是,UI自动化库与这些可选方法相比有许多明显的优点。与商业UI测试自动化框架相比,UI自动化库附带了.NET Framework 3.0(它是事实上的标准),成本更低。

与由一位或两位软件工程师编写的自定义UI测试自动化库相比,UI自动化库包含更多功能,您只需了解API集合,而不用了解每个自定义自动化库的新API。但是,商业UI测试自动化框架的优势在于它们往往与多种工具(例如,测试案例管理器和错误报告软件工具)紧密集成。而轻型自定义UI测试自动化库的优势在于它们通常能够更轻松用作应急测试自动化,并且适用于特殊测试情形。然而,随着.NET Framework 3.0的出现并因被Windows Vista采用而更加普及,您有望看到UI自动化库的使用将快速增长。


TAG: 自动测试Framework

Testing Express 引用 删除 sdnusaber   /   2008-10-30 12:09:30
做了一段时间微软自动化测试,以前一直在分析基于maui的框架,其实差不多也就是直接基于winAPI的。看了本文章后感觉自动化库确实更安全、简洁,也简单一些,受益匪浅啊。
其中提到说2个问题:一是等待的问题,个人感觉其实不用等待最大时间,而是可以做一个循环来判断Process.MainWindowHandle是否为空,当不空时,进程的主界面应该就完全启动成功了(至于其子控件的话应该暂时不用管),这时候就退出循环。二是说如果进程不是自己启动的时候,应该可以用CreateToolHelp32Snapshot()函数以及ProcessFirst(),ProcessNext()函数来找到所需进程,并其相关信息。
感觉您对自动化框架颇有研究,希望以后还能看到作者文章,也好让我们这些后来的少走弯路。哈哈。
 

评分:0

我来说两句

日历

« 2024-04-26  
 123456
78910111213
14151617181920
21222324252627
282930    

我的存档

数据统计

  • 访问量: 2222
  • 日志数: 2
  • 建立时间: 2008-10-07
  • 更新时间: 2008-10-07

RSS订阅

Open Toolbar