c++winapigeturl

Get active Tab URL in FireFox with C++


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


Solution

  • 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;
    }