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

如何在MFC中获取Firefox的URL?原DDE方案在50+版本失效

在MFC中获取Firefox浏览器URL的解决方案(DDE在Firefox 50+版本失效)

我之前使用DDE(Dynamic Data Exchange,动态数据交换)方案获取Firefox的URL,该方案在Firefox 49版本中运行正常,但在50及以上版本中失效。现在希望针对以下问题获取解决方案:

  1. Firefox 49版本与50版本之间是否存在重大变更?
  2. 为何DDE方案在Firefox 50及以上版本中失效?
  3. 在MFC中获取Firefox URL的最优方案是什么?(注:无法使用C#等其他编程语言)

以下是我近期使用的DDE相关代码:

wchar_t szApp[] = L"Firefox"; 
wchar_t szTopic[] = L"WWW_GetWindowInfo"; 

//DDE Initialization 
DWORD idInst=0; 
UINT iReturn; 
iReturn = DdeInitialize(&idInst, (PFNCALLBACK)DdeCallback, APPCLASS_STANDARD | APPCMD_CLIENTONLY, 0 ); 
if (iReturn!=DMLERR_NO_ERROR) { 
    _TM(L"DDE Initialization Failed: 0x%04x\n", iReturn); 
    Sleep(1500); 
    break; 
} 

//DDE Connect to Server using given AppName and topic. 
HSZ hszApp, hszTopic; 
HCONV hConv; 
hszApp = DdeCreateStringHandle(idInst, szApp, 0); 
hszTopic = DdeCreateStringHandle(idInst, szTopic, 0); 
hConv = DdeConnect(idInst, hszApp, hszTopic, NULL); 
DdeFreeStringHandle(idInst, hszApp); 
DdeFreeStringHandle(idInst, hszTopic); 

if (hConv == NULL) { 
    _TM(L"DDE Connection Failed.\n"); 
    Sleep(1500); 
    DdeUninitialize(idInst); 
    break; 
} 

wchar_t szItem1[100]; 
wchar_t szDesc1[DDEREQUEST_ITEM_LENGTH]; 
memset(szItem1,0,sizeof(szItem1)); 
memset(szDesc1,0,sizeof(szDesc1)); 
wsprintf(szItem1,L"URL"); 

//Execute commands/requests specific to the DDE Server. 
DDERequest(idInst, hConv, szItem1, szDesc1); 

//DDE Disconnect and Uninitialize. 
DdeDisconnect(hConv); 
DdeUninitialize(idInst); 

CString strData; 
strData.Format(L"%s",szDesc1); 
strData.MakeLower(); 
_TM(L"firefox Start : %s\n",strData); 

int nStartPos = strData.Find(L"http"); 
if (nStartPos!=-1) { 
    int nEndPos = strData.Find(L"\"",nStartPos+1); 
    if (nEndPos!=-1) { 
        strReturnUrl = strData.Mid(nStartPos,nEndPos-1); 
    } else { 
        nEndPos = strData.Find(L"/",nStartPos+9); 
        strReturnUrl = strData.Mid(nStartPos,nEndPos-1); 
    } 
} 
_TM(L"firefox End : %s\n",strReturnUrl); 

if (strReturnUrl.IsEmpty()) { 
    _TM(L"firefox chrome Start\n"); 
    strReturnUrl = GetChromeWndAddress(hWnd); 
    _TM(L"firefox chrome End : %s\n",strReturnUrl); 
} 

针对问题的解答

1. Firefox 49与50之间的重大变更

Firefox 50确实带来了不少关键变更,其中和你的问题直接相关的是DDE服务的彻底移除。此外,这个版本还全面启用了多进程架构(Electrolysis,e10s),默认让每个标签页运行在独立的内容进程中,同时重构了内部的进程间通信(IPC)机制,这些都彻底改变了传统进程间数据交互的基础。

2. DDE方案在Firefox 50+失效的原因

Mozilla官方在Firefox 50版本中完全废弃了对DDE协议的支持。此前Firefox提供的WWW_GetWindowInfo这类DDE主题是单进程时代的遗留特性,随着多进程架构的普及,DDE这种老旧、安全性不足且维护成本高的通信方式,已经无法适配新的进程隔离模型,因此被官方彻底移除。这直接导致你的DDE连接请求会失败,自然无法获取到URL。

3. MFC中获取Firefox URL的最优方案

由于不能使用C#,这里推荐两种可靠的替代方案:

方案一:Firefox远程调试API(推荐)

Firefox提供了官方支持的Remote Debugging Protocol,可以通过本地TCP连接与Firefox通信,获取标签页的URL信息。步骤如下:

  1. 让用户在Firefox中开启远程调试:打开about:config,设置devtools.debugger.remote-enabled=true,可选设置devtools.debugger.prompt-connection=false避免连接弹窗;
  2. 在MFC程序中用WinSock建立TCP连接到localhost:6000(默认端口,可在Firefox设置中修改);
  3. 发送符合协议规范的JSON请求,获取标签页列表并提取URL。

这种方案兼容性好、官方维护,只要调试协议不发生突破性变更就能稳定工作。以下是简化的MFC代码片段:

// 初始化WinSock
WSADATA wsaData;
WSAStartup(MAKEWORD(2,2), &wsaData);

// 创建socket
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(6000);
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

// 连接到Firefox调试服务
connect(sock, (sockaddr*)&serverAddr, sizeof(serverAddr));

// 发送获取标签列表的请求
const char* request = "{\"id\":1,\"method\":\"Target.getTargets\"}";
send(sock, request, strlen(request), 0);

// 接收响应
char buffer[4096];
int bytesRead = recv(sock, buffer, sizeof(buffer)-1, 0);
buffer[bytesRead] = '\0';

// 解析JSON响应提取URL(可使用cppjson等轻量JSON库,或手动解析)
// ...

// 清理资源
closesocket(sock);
WSACleanup();
方案二:Windows UI自动化(Accessibility API)

使用Windows的IUIAutomation接口遍历Firefox的UI元素,找到地址栏控件并读取其文本内容。这种方案不需要用户修改Firefox设置,但需要适配不同版本的Firefox UI结构:

// 初始化UI自动化
CoInitialize(NULL);
IUIAutomation* pUIAutomation = NULL;
CoCreateInstance(CLSID_CUIAutomation, NULL, CLSCTX_INPROC_SERVER, IID_IUIAutomation, (void**)&pUIAutomation);

// 查找Firefox主窗口
IUIAutomationElement* pFirefoxWindow = NULL;
VARIANT varProp;
varProp.vt = VT_BSTR;
varProp.bstrVal = SysAllocString(L"Mozilla Firefox");
pUIAutomation->FindFirst(TreeScope_Children, pUIAutomation->CreatePropertyCondition(UIA_NamePropertyId, varProp), &pFirefoxWindow);
SysFreeString(varProp.bstrVal);

// 查找地址栏元素(需根据Firefox版本调整名称属性)
IUIAutomationElement* pAddressBar = NULL;
varProp.bstrVal = SysAllocString(L"Address and search bar");
pUIAutomation->FindFirst(TreeScope_Subtree, pUIAutomation->CreatePropertyCondition(UIA_NamePropertyId, varProp), &pAddressBar);
SysFreeString(varProp.bstrVal);

// 读取地址栏文本
if (pAddressBar) {
    VARIANT varValue;
    pAddressBar->GetCurrentPropertyValue(UIA_ValueValuePropertyId, &varValue);
    if (varValue.vt == VT_BSTR) {
        CString url(varValue.bstrVal);
        // 使用获取到的URL
        SysFreeString(varValue.bstrVal);
    }
    pAddressBar->Release();
}

// 清理资源
pFirefoxWindow->Release();
pUIAutomation->Release();
CoUninitialize();

综合来看,远程调试API是最稳定、长期可维护的方案;UI自动化则更适合对用户体验要求高、不希望用户修改浏览器设置的场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:14:46