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