Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get active Tab URL in Chrome with C++

There are several answered questions about this on stackoverflow, but they seem to be outdated and don't work anymore. Chrome has changed its structure entirely. If I try the AccessibleObjectFromEvent technique, then I just get NULL values for the accName and accValue. It seems that there are solutions for python, however I could not find any solution for C++. How can I retrieve the active Tab URL in C++?

like image 412
Brotcrunsher Avatar asked Dec 03 '25 09:12

Brotcrunsher


1 Answers

We need UI Automation

Using the Inspect tool in Window SDK, we can get the property name for Chrome's address bar:

Name:           "Address and search bar"
ControlType:    UIA_EditControlTypeId

We will look for UIA_EditControlTypeId because it is language independent.

But there can be another edit box in the html document which may show up before the main toolbar. Therefore we need to skip the html document, and find the 'pane' which contains the address bar. This pane is called "Google Chrome" and there should be only one of them. The address bar is the child of this unique "Google Chrome pane".

There is no address bar if the browser is in full screen mode. We need a backup method to find the address. For example you can look it up in the document. But the document may not be available either, for example when Chrome has been minimized.

The following example uses ATL COM classes, it requires Visual Studio

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

//this method fails if browser is in full-screen mode
bool find_url(IUIAutomation* uia, IUIAutomationElement* root)
{
    // The root window has several childs, 
    // one of them is a "pane" named "Google Chrome"
    // This contains the toolbar. Find this "Google Chrome" pane:
    CComPtr<IUIAutomationElement> pane;
    CComPtr<IUIAutomationCondition> pane_cond;
    uia->CreatePropertyCondition(UIA_ControlTypePropertyId,
        CComVariant(UIA_PaneControlTypeId), &pane_cond);

    CComPtr<IUIAutomationElementArray> arr;
    if FAILED(root->FindAll(TreeScope_Children, pane_cond, &arr))
        return false;

    int count = 0;
    arr->get_Length(&count);
    for (int i = 0; i < count; i++)
    {
        CComBSTR name;
        if SUCCEEDED(arr->GetElement(i, &pane))
            if SUCCEEDED(pane->get_CurrentName(&name))
                if (wcscmp(name, L"Google Chrome") == 0)
                    break;
        pane.Release();
    }

    if (!pane)
        return false;

    //look for first UIA_EditControlTypeId under "Google Chrome" pane
    CComPtr<IUIAutomationElement> url;
    CComPtr<IUIAutomationCondition> url_cond;
    uia->CreatePropertyCondition(UIA_ControlTypePropertyId, 
        CComVariant(UIA_EditControlTypeId), &url_cond);
    if FAILED(pane->FindFirst(TreeScope_Descendants, url_cond, &url))
        return false;

    //get value of `url`
    CComVariant var;
    if FAILED(url->GetCurrentPropertyValue(UIA_ValueValuePropertyId, &var)) 
        return false;
    if (!var.bstrVal)
        return false;
    wprintf(L"find_url: %s\n", var.bstrVal);

    //set new address ...
    IValueProvider* pattern = nullptr;
    if (FAILED(url->GetCurrentPattern(UIA_ValuePatternId, (IUnknown**)&pattern)))
        return false;
    //pattern->SetValue(L"somewhere.com");
    pattern->Release();

    INPUT input[2] = { INPUT_KEYBOARD };
    input[0].ki.wVk = VK_RETURN;
    input[1] = input[0];
    input[1].ki.dwFlags |= KEYEVENTF_KEYUP;
    SendInput(2, input, sizeof(INPUT));

    return true;
}
    
int main()
{
    //find the first visible chrome window
    HWND hwnd = nullptr;
    while (true)
    {
        hwnd = FindWindowEx(nullptr, hwnd, L"Chrome_WidgetWin_1", nullptr);
        if (!hwnd)
            return 0;
        if (IsWindowVisible(hwnd) && GetWindowTextLength(hwnd) > 0)
            break;
    }

    //CoInitializeEx(nullptr, COINIT_MULTITHREADED);//<- pick the right one
    CoInitialize();
    CComPtr<IUIAutomation> uia;
    if SUCCEEDED(uia.CoCreateInstance(CLSID_CUIAutomation))
    {
        CComPtr<IUIAutomationElement> root;
        if SUCCEEDED(uia->ElementFromHandle(hwnd, &root))
            find_url(uia, root);
        uia.Release();
    }

    CoUninitialize();
    return 0;
}
like image 112
Barmak Shemirani Avatar answered Dec 05 '25 00:12

Barmak Shemirani