FIX: An update is available to enable customization of control identification for the Coded UI Test extension model in Visual Studio 2010 SP1

An update is available for Microsoft Visual Studio 2010 Service Pack 1 (SP1). This update adds a new extension model to enable customization of control identification when you record and play back Automation tests by using the Coded UI Test extension model in Visual Studio 2010 SP1. After you apply this update, the implementation of a new plug-in for custom controls is much simpler and more straightforward than before.

The new extension model adds the following classes:
  • UITechnologyElementProxy. As an example of how to use this new class, you can change the QueryID method. This method is listed as a set of conditions on the map of UI elements (UIMap). You can use this new class to add more conditions or to change existing conditions. These conditions could be additional Automation attributes. Or, these conditions could be used to add more available hierarchy information to the existing UIMap files.
  • UITechnologyManagerProxy. You can use this new class to register your technology manager with the proxy technology manager.

For more information about how to use these new classes after you apply this update, see the scenarios in the "More Information" section.


Scenario 1

You try to test a customized control by using the Coded UI Test. Everything looks good except for one or two minor glitches such as changes to the bounding rectangle of a customized control or the override of the GetHashCode method. With the previous extension model, you could write a plug-in to resolve this problem and to override the intended method. But at the same time, you would have to override several other methods to make the plug-in work, and it may take days to stabilize. By using the new extension model, you can do the same work by overriding only the intended methods.

Scenario 2

You develop a customized control and verify that the Coded UI Test does not automate the actions of the customized control. For example, the Coded UI Test only plays back coordinate clicks. By using these new classes, you can implement the extension model to customize a control’s search properties to automate its actions by using the Coded UI Test in the nine simple steps that follow.

Microsoft provides programming examples for illustration only, without warranty either expressed or implied. This includes, but is not limited to, the implied warranties of merchantability or fitness for a particular purpose. This article assumes that you are familiar with the programming language that is being demonstrated and with the tools that are used to create and to debug procedures. Microsoft support engineers can help explain the functionality of a particular procedure. However, they will not change these examples to provide extra functionality or to construct procedures to meet your specific requirements.
  1. Pass the control's identification property through a usable property of the AccessibleObject type such as the Description or Help property. Similarly, pass other property values as a delimiter-separated string in the AccessibleObject property, as in the following example:

    public override string Description{    get    {        return "<custom_property_value1>"+";"+"<custom_property_value2>";    }}

    Note This is just one method for passing additional parameters to the Coded UI Test. If you have several properties that must be exposed, you can also pass custom properties by using the code injection approach. One approach would be to use a WCF channel between the Coded UI Test and the actual application. The channel can be used to pass the properties that are required to identify controls or perform basic validation of controls by using custom properties. Another method for passing properties is by using Windows Messages. You can decide on the appropriate method, depending on your requirements.

  2. Specify the custom technology name in the UITechnologyManagerProxy class and corresponding core technology manager name so that the Coded UI Test extension framework can do the internal proxy registration accordingly.

    Note Currently, third-party plug-ins cannot use the same technology name as any of the Coded UI Test core technology names. Also, the multiple third-party plug-in names cannot conflict. Although the plug-in is loaded by the extension manager, the Coded UI Test plug-in manager cannot allow for registration of multiple plug-ins that have duplicate technology names. Therefore, customized controls have to be registered against a different technology name in the CustomTechnologyManager constructor, such as in the following example:
    public CustomTechnologyManager()            : base("MSAA", "<custom_technology_name>")        {        }
  3. Override the GetControlSupportLevel method of the UITechnologyManagerProxy class. You can obtain the AccessibleObject type from the windowHandle property, as in the following example. After you do this, it becomes fairly easy to extract the custom property. You can then return the appropriate support level from the custom plug-in after it is validated against the custom property value.
    internal enum OBJID : uint        {            WINDOW = 0x00000000,            SYSMENU = 0xFFFFFFFF,            TITLEBAR = 0xFFFFFFFE,            MENU = 0xFFFFFFFD,            CLIENT = 0xFFFFFFFC,            VSCROLL = 0xFFFFFFFB,            HSCROLL = 0xFFFFFFFA,            SIZEGRIP = 0xFFFFFFF9,            CARET = 0xFFFFFFF8,            CURSOR = 0xFFFFFFF7,            ALERT = 0xFFFFFFF6,            SOUND = 0xFFFFFFF5,        } internal static IAccessible AccessibleObjectFromWindow(IntPtr windowHandle)        {            Guid accessibleGuid = typeof(IAccessible).GUID;            IAccessible accessible = null;             if (AccessibleObjectFromWindow(windowHandle, (int)OBJID.WINDOW, ref accessibleGuid, ref accessible) != 0)            {                Trace.TraceError("AccessibleObjectFromWindow failed for window handle {0}", windowHandle);            }             return accessible;        }         [DllImport("oleacc.dll")]internal static extern int AccessibleObjectFromWindow(IntPtr hWnd, int dwObjectID, ref Guid riid, ref IAccessible pAcc); public override int GetControlSupportLevel(IntPtr windowHandle)        {            int supportLevel = base.GetControlSupportLevel(windowHandle);            if (supportLevel > 1)            {                IAccessible accessibleObject = this.AccessibleObjectFromWindow(windowHandle);                if (accessibleObject!=null && accessibleObject.accDescription.Contains("custom_property_value"))                {                    return (int)ControlSupport.ControlSpecificSupport;                }            }             return (int)ControlSupport.NoSupport;        }
  4. Add a custom property to the QueryID method in the UITechnologyElementProxy class. You can add an additional condition or remove a condition from the QueryID method. Be aware that as soon as a condition is removed, the property condition stops to appear in the UIMap. After an additional condition is added, it will be listed as an additional tag for the property conditions in the .uitest file of the generated code if any action is performed on the customized control, as in the following example:
    <PropertyCondition Name=" <Custom_property_name>">Custom_property_value</PropertyCondition>         public override IQueryElement QueryId        {            get             {                if (queryElement == null)                {                    queryElement = base.QueryId;                    if(string.Equals(this.ControlTypeName, ControlType.Button.ToString(), StringComparison.OrdinalIgnoreCase))                    {                        Utilities.UpdateQueryId(this, queryElement, new string[]                         {                            <Custom_property_name>                    });                    }                }                return queryElement;            }        }

    The following is an example of how to implement the Utilities.UpdateQueryId method. This method is used in the previous example.
    internal static void UpdateQueryId(UITechnologyElement element, IQueryElement queryElement, string[] inclusionProperties)        {            List<IQueryCondition> conditionList = new List<IQueryCondition>(queryElement.Condition.Conditions);            if (conditionList != null)            {                bool updated = false;                foreach (string propertyToInclude in inclusionProperties)                {                    bool exists = false;                    foreach (IQueryCondition qCond in conditionList)                    {                        PropertyCondition pCond = qCond as PropertyCondition;                        if (pCond != null &&                            string.Equals(pCond.PropertyName, propertyToInclude, StringComparison.OrdinalIgnoreCase))                        {                            exists = true;                            break;                        }                    }                     if (!exists)                    {                        string propVal = element.GetPropertyValue(propertyToInclude) as string;                        PropertyCondition newCondition = new PropertyCondition(propertyToInclude, propVal);                        conditionList.Add(newCondition);                        updated = true;                    }                }                 if (updated)                {                    queryElement.Condition.Conditions = conditionList.ToArray();                }            }        }
  5. Override the GetPropertyValue method of the UITechnologyElementProxy class, and then set the value as the first token in the Description string. This implementation will differ based on how you pass custom properties. If you use code injection to pass the properties, you should create a channel and then fetch the properties from the host, as in the following example:
    public override object GetPropertyValue(string propertyName){    if (string.Equals(propertyName, “<custom_property_name>”))    {        string accDesc = this.GetPropertyValue(<custom_property_name>) as string;        if (accDesc != null)        {            string[] descriptionTokens = accDesc.Split(new char[] { ';' });            return descriptionTokens[0];        }    }    return base.GetPropertyValue(propertyName);}
  6. Specify the custom Technology Manager in the UITechnologyElementProxy class, and then associate it with the core IUI Technology Element, as in the following example:
    public RadGridViewTechnologyElement(CustomTechnologyManager technologyManager, IUITechnologyElement coreElement)            : base(technologyManager, coreElement)        {        }
  7. If you have a specialized class for custom code generation, and if you have added additional property conditions in the QueryID method as described in step 4, you have to expose the custom property as a valid search property for this element, as in the following example:
    protected override Dictionary<string, bool> GetValidSearchProperties(){    Dictionary<string, bool> validSearchProperties = base.GetValidSearchProperties();    if (!validSearchProperties.ContainsKey(<custom_property_name>))    {        validSearchProperties.Add((<custom_property_name>, true);    }     return validSearchProperties;}
  8. In the PropertyProvider extension, add conditions to set the control support level, as in the following example.

    Note When the properties of the uiTestControl method are retrieved, we recommend that you use only those properties that are available in the SearchProperties property or in the FilterProperties property of a uiTestControl method. Do not try to fetch any additional properties, because the live control may not be available during code generation.
    public override int GetControlSupportLevel(UITestControl uiTestControl)        {            if (IsSupported(uiTestControl))            {                return (int)ControlSupport.ControlSpecificSupport;            }             return (int)ControlSupport.NoSupport;        } private static bool IsSupported(UITestControl uiTestControl)        {            string accDescriptionValue = string.Empty;            string objectType = string.Empty;             if (uiTestControl.SearchProperties != null && uiTestControl.SearchProperties.Count > 0)            {                PropertyExpression controlTypeExpression = uiTestControl.SearchProperties.Find(“<Custom_property_name>”);                if (controlTypeExpression != null)                {                    accDescriptionValue = controlTypeExpression.PropertyValue;                    string[] descriptionTokens = accDescriptionValue.Split(new char[] { ';' });                    objectType = descriptionTokens[0];                }            }             if (string.Equals(uiTestControl.TechnologyName, “<Custom_technology_name>”, StringComparison.OrdinalIgnoreCase)                 && (objectType.Contains(“<Custom_property_value>”)))                         {                 return true;            }            return false;        }
  9. Implement the UITestExtensionPackage method, and then attach the PropertyProvider and TechnologyManager services by overriding the GetService method, as in the following example:
    public override object GetService(Type serviceType){    Trace.WriteLine("RadGridViewExtensionPackage.GetService(" + serviceType.ToString() + ")");    if (serviceType == typeof(UITestPropertyProvider))        return this.PropertyProvider;    else if (serviceType == typeof(UITechnologyManager))        return this.TechnologyManager;    return null;}

Update information

A supported hotfix is available from Microsoft. However, this hotfix is intended to correct only the problem that described in this article. Apply this hotfix only to systems that are experiencing the problem described in this article. This hotfix might receive additional testing. Therefore, if you are not severely affected by this problem, we recommend that you wait for the next software update that contains this hotfix.

If the hotfix is available for download, there is a "Hotfix download available" section at the top of this Knowledge Base article. If this section does not appear, contact Microsoft Customer Service and Support to obtain the hotfix.

Note If additional issues occur or if any troubleshooting is required, you might have to create a separate service request. The usual support costs will apply to additional support questions and issues that do not qualify for this specific hotfix. For a complete list of Microsoft Customer Service and Support telephone numbers or to create a separate service request, go to the following Microsoft website: Note The "Hotfix download available" form displays the languages for which the hotfix is available. If you do not see your language, this is because a hotfix is not available for that language.


To apply this hotfix, you must have Service Pack 1 (SP1) applied to one of the following:
  • Microsoft Visual Studio 2010 Premium
  • Microsoft Visual Studio 2010 Ultimate
  • Microsoft Visual Studio 2010 Test Professional
  • Microsoft Visual Studio Team Foundation Server 2010
  • Microsoft Visual Studio Test Agent 2010

For more information about how to obtain Visual Studio 2010 SP1, click the following article number to view the article in the Microsoft Knowledge Base:
983509 Description of Visual Studio 2010 Service Pack 1

Restart information

You may have to restart the computer after you apply this hotfix. We recommend that you exit any instances of Visual Studio before you apply this hotfix.

Hotfix replacement information

This hotfix does not replace a previously released hotfix.

File information

This hotfix installs files that have the attributes that are listed in the following tables. The dates and the times for these files are listed in Coordinated Universal Time (UTC). The dates and the times for these files on your local computer are displayed in your local time together with your current daylight saving time (DST) bias. Additionally, the dates and the times may change when you perform certain operations on the files.
File nameFile versionFile sizeDateTimePlatform

For more information about software update terminology, click the following article number to view the article in the Microsoft Knowledge Base:
824684 Description of the standard terminology that is used to describe Microsoft software updates

Article ID: 2696646 - Last Review: 05/23/2012 16:21:00 - Revision: 1.0

Microsoft Visual Studio 2010 Service Pack 1

  • kbautohotfix kbqfe kbhotfixserver kbfix kbbug kbexpertiseinter kbsurveynew KB2696646