Search code examples
c#visual-c++ui-automationmicrosoft-ui-automation

C++ UIA TextPattern is not found on RichEdit control in Win 7, but C# UIA does find it


On Win 7 SP1 with Convenience Update (latest Win 7 that was shipped), my C++ code using CUIAutomation from Windows Automation 3.0 cannot get the TextPattern from the RichEdit control in the built-in WordPad application. However, the equivalent C# code using UIAutomationClient and UIAutomationTypes can.

Better success on Win 10: both the C++ code and the C# code successfully get the TextPattern.

My main project has compatibility issues with another C# UIA application, which went away when I use the C++ code on Win 10. So I really want to use the C++ code on Win 7 also. Does anyone know why the C++ code fails and how to fix it? I am quite surprised that getting a simple TextPattern out of the built-in RichEdit control does not work reliably!

Here is the C# code (much easier to read!), followed by the C++ code:

using System;
using System.Threading;
using System.Windows.Automation;

namespace UIAutomationNET
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Getting element at cursor in 3 seconds...");
            Thread.Sleep(3000);

            var element = AutomationElement.FocusedElement;

            if (element != null)
            {
                var textPatternElement = element.FindFirst(
                    TreeScope.Subtree,
                    new PropertyCondition(AutomationElement.IsTextPatternAvailableProperty, true));

                if (textPatternElement == null)
                    Console.WriteLine("No element supporting TextPattern found.");
                else
                    Console.WriteLine("TextPattern is supported!  :-)");
            }
        }
    }
}

The following C++ code is based on this MSDN Code Gallery sample:

#include <windows.h>
#include <ole2.h>
#include <uiautomation.h>
#include <strsafe.h>

IUIAutomation *_automation;


int _cdecl wmain(_In_ int argc, _In_reads_(argc) WCHAR* argv[])
{
    UNREFERENCED_PARAMETER(argc);
    UNREFERENCED_PARAMETER(argv);

    // Initialize COM before using UI Automation
    HRESULT hr = CoInitialize(NULL);
    if (FAILED(hr))
    {
        wprintf(L"CoInitialize failed, HR:0x%08x\n", hr);
    }
    else
    {
        // Use CUIAutomation instead of CUIAutomation8 on Win 7
        hr = CoCreateInstance(__uuidof(CUIAutomation), NULL,
            CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&_automation));
        if (FAILED(hr))
        {
            wprintf(L"Failed to create a CUIAutomation, HR: 0x%08x\n", hr);
        }
        else
        {
            IUIAutomationElement *element = NULL;
            wprintf( L"Getting element at cursor in 3 seconds...\n" );
            Sleep(3000);

            POINT pt;
            GetCursorPos(&pt);
            hr = _automation->ElementFromPoint(pt, &element);
            if (FAILED(hr))
            {
                wprintf( L"Failed to ElementFromPoint, HR: 0x%08x\n\n", hr );
            }

            if (SUCCEEDED(hr) && element != NULL)
            {
                IUIAutomationElement *textElement = NULL;

                // Create a condition that will be true for anything that supports Text Pattern
                // Use UIA_IsTextPatternAvailablePropertyId instead of UIA_IsTextPattern2AvailablePropertyId on Win 7
                IUIAutomationCondition* textPatternCondition;
                VARIANT trueVar;
                trueVar.vt = VT_BOOL;
                trueVar.boolVal = VARIANT_TRUE;
                hr = _automation->CreatePropertyCondition(UIA_IsTextPatternAvailablePropertyId, trueVar, &textPatternCondition);

                if (FAILED(hr))
                {
                    wprintf(L"Failed to CreatePropertyCondition, HR: 0x%08x\n", hr);
                }
                else
                {
                    // Actually do the search
                    hr = element->FindFirst(TreeScope_Subtree, textPatternCondition, &textElement);
                    if (FAILED(hr))
                    {
                        wprintf(L"FindFirst failed, HR: 0x%08x\n", hr);
                    }
                    else if (textElement == NULL)
                    {
                        wprintf(L"No element supporting TextPattern found.\n");
                        hr = E_FAIL;
                    }
                    else
                    {
                        wprintf(L"TextPattern is supported!  :-)\n");
                    }
                    textPatternCondition->Release();
                }
            }
            _automation->Release();
        }
        CoUninitialize();
    }

    return 0;
}


Solution

  • If I remember correctly, the Win7 native UI Automation provider did not support TextPattern, while the managed UI Automation provider did.

    The native UI Automation provider didn't add TextPattern support until Windows 8.