SHDocVw::ShellWindows无法识别Edge IE模式标签窗口的解决方案咨询
我们有一款基于Microsoft Active Document/ActiveX技术的Windows客户端应用,原本依赖IE浏览器运行——它在IE标签页中显示,但以独立进程运行,需要向服务器发起HTTP请求获取资源。对于使用SiteMinder等单点登录(SSO)产品的客户,应用必须回传服务器初始发送的SMSESSION等Cookie。
在IE环境中,客户端应用可以通过Microsoft的SHDocVw::ShellWindows集合找到对应的IE标签页并获取Cookie。但IE已于2022年6月退役,客户尝试在Edge的IE模式下运行该应用时,SHDocVw::ShellWindows集合无法识别这些Edge IE模式的标签窗口。虽然可以通过EnumWindows定位客户端窗口,但仅靠HWND无法获取Cookie,导致应用向服务器的HTTP请求未携带Cookie,服务器端SSO软件返回登录页面而非请求的文档资源。
演示问题的示例程序
使用Visual Studio构建步骤:创建C++ Win32控制台项目,勾选“添加MFC通用头文件”,完成后将以下代码粘贴到启动源文件中:
#include "stdafx.h" #include "afxctl.h" #import <mshtml.tlb> #import <shdocvw.dll> #include "mshtml.h" int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) { SHDocVw::IShellWindowsPtr m_spSHWinds; IDispatchPtr spDisp; IWebBrowser2Ptr m_webBrowser; char *pszLocName; char *pszTitle; char *pszCookie; HWND iehwnd; DWORD iepid; DWORD ietid; _bstr_t bStrLocname; _bstr_t bStrTitle; _bstr_t bStrCookie; DWORD rc; IHTMLDocument2 *pdoc2 = NULL; BSTR bptr; BSTR ck; char info[4096]; int cntIEtabs = 0; CoInitialize(NULL); HRESULT hr = m_spSHWinds.CreateInstance(__uuidof(SHDocVw::ShellWindows)); long nCount = m_spSHWinds->GetCount(); for (long i = 0; i < nCount; i++) { _variant_t va(i, VT_I4); spDisp = m_spSHWinds->Item(va); SHDocVw::IWebBrowser2Ptr spBrowser(spDisp); if (spBrowser != NULL) { bStrLocname = spBrowser->GetLocationName(); pszLocName = bStrLocname; spBrowser->get_Name(&bptr); bStrTitle = bptr; pszTitle = bStrTitle; try { iehwnd = (HWND)spBrowser->GetHWND(); } catch (const _com_error &e) { // if GetHWND() fails continue; } ietid = GetWindowThreadProcessId(iehwnd, &iepid); // cookie stuff m_webBrowser = (IWebBrowser2Ptr)spBrowser; rc = m_webBrowser->get_Document(&spDisp); if (spDisp->QueryInterface(IID_IHTMLDocument2, (void**)&pdoc2) == S_OK) { pdoc2->get_cookie(&ck); bStrCookie = ck; pszCookie = bStrCookie; sprintf_s(info, "LocationName: %s\n\n" "PID: %d\n\n" "Title: %s\n\n" "Cookie string: %s", pszLocName, iepid, pszTitle, pszCookie); MessageBox(NULL, CA2T(info), _T("Browser tab info:"), MB_OK); cntIEtabs++; } } } if (cntIEtabs == 0) { MessageBox(NULL, _T("No IE browser tabs found."), _T("Browser tab info:"), MB_OK); } return 0; }
测试现象:打开IE访问http://microsoft.com并运行程序,可找到IE窗口并显示标题、PID、Cookie等信息;但关闭IE后,在Edge的IE模式下访问该网址,程序无法找到对应标签页。
咨询问题
- 是否需要额外配置让
SHDocVw::ShellWindows识别Edge IE模式标签窗口? - 有无其他方式定位这些标签页并获取关联Cookie,以在后续HTTP请求中回传给服务器?
关于SHDocVw::ShellWindows识别Edge IE模式的配置
SHDocVw::ShellWindows集合无法直接识别Edge IE模式的标签窗口,这是因为Edge IE模式的标签进程是作为Edge的子进程运行,而非传统IE的独立进程,微软并未提供让SHDocVw兼容识别这些窗口的配置选项,因此这条路走不通。
替代方案获取Edge IE模式的Cookie
方案1:直接读取IE共享Cookie存储
Edge IE模式会复用传统IE的Cookie存储,你可以通过WinINet API直接读取目标域名的Cookie:
- 使用
InternetGetCookieExW函数,传入目标URL,需启用INTERNET_COOKIE_HTTPONLY标志以读取HTTPOnly类型的Cookie(SiteMinder的SMSESSION通常属于此类)。 - 此方法无需定位标签页,直接获取系统中存储的对应域名Cookie,适合大多数场景。
示例代码片段:
#include <wininet.h> #pragma comment(lib, "wininet.lib") // 获取目标URL的Cookie wchar_t cookieBuffer[4096] = {0}; DWORD bufferSize = sizeof(cookieBuffer) / sizeof(wchar_t); BOOL result = InternetGetCookieExW( L"http://your-server-domain.com", NULL, cookieBuffer, &bufferSize, INTERNET_COOKIE_HTTPONLY, NULL ); if (result && bufferSize > 0) { // cookieBuffer中存储了目标域名的完整Cookie字符串 }
方案2:利用Edge WebDriver自动化获取
如果需要精准定位特定Edge IE模式标签页的Cookie,可以使用Edge WebDriver:
- 下载与Edge版本匹配的Edge WebDriver。
- 配置WebDriver以IE模式启动Edge,设置DesiredCapabilities参数:
ie.edgechromium=true、ie.edgepath指定Edge安装路径。 - 通过WebDriver API获取当前标签页的Cookie集合,提取所需的SMSESSION等字段后传递给应用。
方案3:进程注入获取Trident引擎COM对象
Edge IE模式标签进程本质运行Trident引擎,可通过以下步骤获取Cookie:
- 通过
EnumWindows找到Edge IE模式窗口,获取其进程ID(PID)。 - 使用进程注入技术(如
CreateRemoteThread)将代码注入到目标进程。 - 在注入代码中,通过
CoCreateInstance获取IHTMLDocument2对象,调用get_cookie方法读取Cookie。
- 注意:此方法需处理进程权限、COM线程模型问题,实现复杂度高,且可能受Windows安全机制限制。
方案4:修改HTTP请求逻辑自动携带Cookie
如果应用使用WinINet/WinHTTP发起请求,可直接配置API使用系统默认浏览器会话:
- 调用
InternetOpen时指定INTERNET_OPEN_TYPE_PRECONFIG参数,让API自动复用Edge IE模式的Cookie会话。 - 此方式发起的请求会自动携带对应域名的Cookie,无需手动获取和拼接,是最简便的适配方案。
内容的提问来源于stack exchange,提问作者John Carter

