4

I'm trying to get a URL from Firefox using UI Automation, but it keeps failing.

It worked fine in Chrome. but it doesn't work in Firefox. i think Search Or Enter Address is same 'Address and search bar' in Chrome

#include <Windows.h>
#include <AtlBase.h>
#include <AtlCom.h>
#include <UIAutomation.h>
#include <stdlib.h>
#define UNICODE

int main()
{
    CoInitialize(NULL);
    HWND hwnd = NULL;
    while (true)
    {
        hwnd = FindWindowEx(0, hwnd, L"MozillaWindowClass", NULL);
        if (!hwnd)
            break;
        if (!IsWindowVisible(hwnd))
            continue;

        CComQIPtr<IUIAutomation> uia;
        if (FAILED(uia.CoCreateInstance(CLSID_CUIAutomation)) || !uia)
            break;

        CComPtr<IUIAutomationElement> root;
        if (FAILED(uia->ElementFromHandle(hwnd, &root)) || !root)
            break;

        CComPtr<IUIAutomationCondition> condition;


        uia->CreatePropertyCondition(UIA_ControlTypePropertyId,
            CComVariant(0xC354), &condition);


        CComPtr<IUIAutomationElement> edit;
        if (FAILED(root->FindFirst(TreeScope_Descendants, condition, &edit))
            || !edit)
            continue; //maybe we don't have the right tab, continue...

        CComVariant url;
        edit->GetCurrentPropertyValue(UIA_ValueValuePropertyId, &url);
        MessageBox(0, url.bstrVal, 0, 0);
        break;
    }
    CoUninitialize();
    return 0;
}

A blank value is displayed in the message box I want to get Active tab URL

zett42
  • 25,437
  • 3
  • 35
  • 72
morte00
  • 43
  • 3

1 Answers1

3

The main section of above code is designed to work with Chrome, not Firefox.

Use the Inspect tool to examine arrangement of controls in Firefox. You will see something like the following structure:

Firefox window
    -> "" toobar
    -> "" toobar
    -> "Navigation Toolbar" toobar
        -> "" combobox
            -> "Search with Google" edit //<- url editbox
        -> "Search" combobox //<- we don't want this

We need the control with label "Search with Google". We can look for the elements by name, but this can be language dependent, also the order of the controls could be different, because the user can customized the browser and rearrange the controls.

Instead, we can look for AutomationId which in this case is available in Firefox (that's not always the case)

"Navigation" shows AutomationId = "nav-bar" property, and "editbox" shows AutomationId = "urlbar-input" property

We can use UIA_AutomationIdPropertyId to look for these names:

#include <Windows.h>
#include <AtlBase.h>
#include <AtlCom.h>
#include <UIAutomation.h>
#include <stdlib.h>
#define UNICODE

int main()
{
    if FAILED(CoInitialize(nullptr))
        return 0;
    struct coinit { ~coinit() { CoUninitialize(); } } cleanup;

    //find the first visible window in firefox
    HWND hwnd = NULL;
    while (true)
    {
        hwnd = FindWindowEx(0, hwnd, L"MozillaWindowClass", NULL);
        if (!hwnd)
        {
            printf("Firefox window not found.\n");
            return 0;
        }
        if (IsWindowVisible(hwnd))
            break;
    }

    //initialize UIAutomation
    CComPtr<IUIAutomation> uia;
    if FAILED(uia.CoCreateInstance(CLSID_CUIAutomation))
        return 0;

    CComPtr<IUIAutomationElement> root, navigation, editbox;
    CComPtr<IUIAutomationCondition> c1, c2;

    //find root from hwnd handle
    if FAILED(uia->ElementFromHandle(hwnd, &root))
        return 0;

    //find navigation bar as child of root
    uia->CreatePropertyCondition(UIA_AutomationIdPropertyId, 
        CComVariant(L"nav-bar"), &c1);
    if FAILED(root->FindFirst(TreeScope_Children, c1, &navigation))
        return 0;

    //find editbox under as descendant of navigation
    uia->CreatePropertyCondition(UIA_AutomationIdPropertyId, 
        CComVariant(L"urlbar-input"), &c2);
    if FAILED(navigation->FindFirst(TreeScope_Descendants, c2, &editbox))
        return 0;

    //get the string in editbox 
    CComVariant url;
    if FAILED(editbox->GetCurrentPropertyValue(UIA_ValueValuePropertyId, &url))
        return 0;
    if(url.bstrVal)
        wprintf(L"[%s]\n", url.bstrVal);

    return 0;
}
Barmak Shemirani
  • 30,904
  • 6
  • 40
  • 77