Search code examples
c++google-chromewinapi

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++?


Solution

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