You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用C++获取Chrome浏览器当前活动标签页URL

新版Chrome下用C++获取当前活动标签页URL的可行方案

我最近研究过这个问题——确实,之前依赖AccessibleObjectFromEvent的老方法完全失效了,Chrome的UI结构和 accessibility 接口都改了不少,accName和accValue返回NULL是常态。这里给你两个亲测有效的C++实现方案,覆盖不同场景:

方案一:用Chrome DevTools Protocol(CDP,推荐)

这是Chrome官方提供的远程调试接口,稳定性拉满,不会因为UI更新失效。核心思路是通过Chrome的调试端口获取标签页列表,再筛选出活动标签页的URL。

步骤说明:

  1. 确保Chrome开启调试端口:要么启动Chrome时加参数--remote-debugging-port=9222,要么找到已运行的Chrome进程,读取它的命令行参数拿到实际的调试端口(比如用Windows的CreateToolhelp32Snapshot遍历进程)。
  2. 发送HTTP请求获取标签页数据:向http://localhost:端口号/json发送GET请求,返回的JSON里包含所有标签页的信息。
  3. 解析JSON找到活动标签页:筛选type为page且active为true的条目,提取url字段。

示例代码(用WinHTTP+ nlohmann/json):

#include <winhttp.h>
#include <nlohmann/json.hpp>
#include <string>
#include <iostream>

#pragma comment(lib, "winhttp.lib")

using json = nlohmann::json;

std::string GetChromeActiveTabUrl() {
    // 初始化WinHTTP会话
    HINTERNET hSession = WinHttpOpen(L"ChromeTabURLGetter", 
                                     WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, 
                                     WINHTTP_NO_PROXY_NAME, 
                                     WINHTTP_NO_PROXY_BYPASS, 0);
    if (!hSession) return "";

    // 连接到调试端口
    HINTERNET hConnect = WinHttpConnect(hSession, L"localhost", 9222, 0);
    if (!hConnect) {
        WinHttpCloseHandle(hSession);
        return "";
    }

    // 创建GET请求
    HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"GET", L"/json", 
                                            nullptr, WINHTTP_NO_REFERER, 
                                            WINHTTP_DEFAULT_ACCEPT_TYPES, 0);
    if (!hRequest) {
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        return "";
    }

    // 发送请求
    if (!WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0,
                            WINHTTP_NO_REQUEST_DATA, 0, 0, 0)) {
        WinHttpCloseHandle(hRequest);
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        return "";
    }

    // 接收响应
    if (!WinHttpReceiveResponse(hRequest, nullptr)) {
        WinHttpCloseHandle(hRequest);
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        return "";
    }

    // 读取响应内容
    std::wstring response;
    DWORD bytesRead;
    wchar_t buffer[4096];
    while (WinHttpReadData(hRequest, buffer, sizeof(buffer)/sizeof(wchar_t)-1, &bytesRead) && bytesRead > 0) {
        buffer[bytesRead] = L'\0';
        response += buffer;
    }

    // 清理资源
    WinHttpCloseHandle(hRequest);
    WinHttpCloseHandle(hConnect);
    WinHttpCloseHandle(hSession);

    // 解析JSON找活动标签页
    try {
        json tabs = json::parse(response);
        for (const auto& tab : tabs) {
            if (tab["type"] == "page" && tab["active"] == true) {
                return tab["url"].get<std::string>();
            }
        }
    } catch (...) {
        return "";
    }

    return "";
}

int main() {
    std::string url = GetChromeActiveTabUrl();
    if (!url.empty()) {
        std::cout << "当前活动标签页URL:" << url << std::endl;
    } else {
        std::cout << "获取失败!请确认Chrome已开启远程调试端口,或检查端口号是否正确。" << std::endl;
    }
    return 0;
}

注:需要引入nlohmann/json库(或者替换成你常用的JSON解析库);如果Chrome用的不是9222端口,得先遍历进程拿到实际端口。

方案二:用Windows UI Automation(无需开启调试)

如果不想给Chrome加启动参数,可以用Windows的UI Automation接口,遍历Chrome的UI树找到地址栏,读取它的内容。不过这个方案依赖Chrome的UI元素命名,未来如果Chrome更新UI可能需要调整。

示例代码:

#include <windows.h>
#include <uiautomation.h>
#include <iostream>
#include <string>

#pragma comment(lib, "uiautomation.lib")

// 用于查找地址栏的回调类
class AddressBarHandler : public IUIAutomationConditionEventHandler {
private:
    LONG refCount;
    std::wstring targetUrl;
    IUIAutomationElement* foundElem;

public:
    AddressBarHandler() : refCount(1), foundElem(nullptr) {}

    ULONG STDMETHODCALLTYPE AddRef() override { return InterlockedIncrement(&refCount); }
    ULONG STDMETHODCALLTYPE Release() override {
        ULONG cnt = InterlockedDecrement(&refCount);
        if (cnt == 0) delete this;
        return cnt;
    }

    HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppv) override {
        if (riid == IID_IUnknown || riid == IID_IUIAutomationConditionEventHandler) {
            *ppv = static_cast<IUIAutomationConditionEventHandler*>(this);
            AddRef();
            return S_OK;
        }
        *ppv = nullptr;
        return E_NOINTERFACE;
    }

    HRESULT STDMETHODCALLTYPE HandleElement(IUIAutomationElement* pElement) override {
        // 读取地址栏的Value属性
        VARIANT varVal;
        HRESULT hr = pElement->GetCurrentPropertyValue(UIA_ValueValuePropertyId, &varVal);
        if (SUCCEEDED(hr) && varVal.vt == VT_BSTR) {
            targetUrl = varVal.bstrVal;
            foundElem = pElement;
            foundElem->AddRef();
        }
        return S_OK;
    }

    std::wstring GetUrl() const { return targetUrl; }
};

std::wstring GetChromeTabUrlViaUIA() {
    HRESULT hr;
    IUIAutomation* pUIA = nullptr;
    hr = CoCreateInstance(CLSID_CUIAutomation, nullptr, CLSCTX_INPROC_SERVER, 
                          IID_IUIAutomation, (void**)&pUIA);
    if (FAILED(hr)) return L"";

    // 获取当前活动窗口
    HWND activeWnd = GetForegroundWindow();
    if (!activeWnd) {
        pUIA->Release();
        return L"";
    }

    // 确认是Chrome窗口
    wchar_t windowTitle[256];
    GetWindowText(activeWnd, windowTitle, sizeof(windowTitle)/sizeof(wchar_t));
    if (wcsstr(windowTitle, L"Google Chrome") == nullptr) {
        pUIA->Release();
        return L"";
    }

    // 获取Chrome窗口的UI元素
    IUIAutomationElement* pChromeWnd = nullptr;
    hr = pUIA->ElementFromHandle(activeWnd, &pChromeWnd);
    if (FAILED(hr)) goto cleanup;

    // 创建条件:找"Edit"类型且名称为"Address and search bar"的元素(Chrome地址栏)
    IUIAutomationPropertyCondition* typeCond = nullptr;
    hr = pUIA->CreatePropertyCondition(UIA_ControlTypePropertyId, 
                                        VARIANTFromInt32(UIA_EditControlTypeId), &typeCond);
    if (FAILED(hr)) goto cleanup;

    IUIAutomationPropertyCondition* nameCond = nullptr;
    hr = pUIA->CreatePropertyCondition(UIA_NamePropertyId, 
                                        CComBSTR(L"Address and search bar"), &nameCond);
    if (FAILED(hr)) goto cleanup;

    IUIAutomationAndCondition* andCond = nullptr;
    hr = pUIA->CreateAndCondition(typeCond, nameCond, &andCond);
    if (FAILED(hr)) goto cleanup;

    // 查找元素并读取URL
    AddressBarHandler* handler = new AddressBarHandler();
    hr = pChromeWnd->FindAllBuildCache(TreeScope_Subtree, andCond, nullptr, handler);
    std::wstring result = handler->GetUrl();

    // 清理资源
    handler->Release();
cleanup:
    if (andCond) andCond->Release();
    if (nameCond) nameCond->Release();
    if (typeCond) typeCond->Release();
    if (pChromeWnd) pChromeWnd->Release();
    if (pUIA) pUIA->Release();
    return result;
}

int main() {
    CoInitialize(nullptr);
    std::wstring url = GetChromeTabUrlViaUIA();
    if (!url.empty()) {
        std::wcout << L"当前活动标签页URL:" << url << std::endl;
    } else {
        std::wcout << L"获取失败!请确认Chrome是当前活动窗口,或检查Chrome版本是否适配。" << std::endl;
    }
    CoUninitialize();
    return 0;
}

注:如果你的Chrome是中文版本,地址栏名称可能是"地址和搜索栏",需要修改代码里的名称字符串。


方案对比

  • CDP方案:官方接口,稳定可靠,不受UI变化影响,但需要Chrome开启调试端口。
  • UI Automation方案:无需额外配置,但依赖Chrome的UI元素命名,可能随版本更新失效。

内容的提问来源于stack exchange,提问作者Brotcrunsher

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:58:00