VirtualBox Win7虚拟机调用InternetOpenUrl报错12157原因及解决方法
运行环境
- 虚拟化平台:Oracle Virtual Box 6.1
- 虚拟机系统:Windows 7 Home Premium x86、x64
问题现象
在上述Win7虚拟机环境中运行基于WinInet实现的URL重定向检测代码时,访问微软官方下载链接触发错误码12157,程序运行失败。相同代码在物理机上可正常运行;将目标URL替换为https://www.google.com时,虚拟机内程序也可正常执行,初步判定故障与目标URL、虚拟机环境配置相关。
测试代码如下:
#include <iostream> #include <Windows.h> #include <WinInet.h> #include <thread> #pragma comment(lib, "wininet.lib") using namespace std; bool isURL_Redirected(wstring url) { HINTERNET hInternet = InternetOpen(NULL, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); if (hInternet) { hInternet = InternetOpenUrl(hInternet, url.c_str(), 0, 0, INTERNET_FLAG_NO_AUTO_REDIRECT, 0); WCHAR lpvData[1000]; DWORD size = sizeof(lpvData); if (hInternet) { if (HttpQueryInfo(hInternet, HTTP_QUERY_LOCATION, lpvData, &size, NULL)) { InternetCloseHandle(hInternet); return true; } } else { cout << "line 30: " << GetLastError() << endl; } } else { cout << "line 35: " << GetLastError() << endl; } InternetCloseHandle(hInternet); return false; } int main() { if (isURL_Redirected(L"https://download.visualstudio.microsoft.com/download/pr/8e396c75-4d0d-41d3-aea8-848babc2736a/80b431456d8866ebe053eb8b81a168b3/ndp462-kb3151800-x86-x64-allos-enu.exe")) cout << "It does redirect." << endl; else cout << "It does not redirect." << endl; system("pause"); // Win only. }
程序错误输出:
line 30: 12157
补充说明
错误码12157为WinInet内部错误,通常在SSL/TLS库加载失败、HTTPS握手协议不匹配时触发,与HTTPS密钥发送流程无关。
故障原因
- 原生Windows 7系统的WinInet组件默认仅启用SSL 3.0、TLS 1.0协议支持,未开启TLS 1.1/1.2协议。而微软
download.visualstudio.microsoft.com服务器当前已完全禁用TLS 1.0/1.1,仅接受TLS 1.2及以上版本的HTTPS连接请求,握手阶段协议版本不匹配直接触发12157错误。 - 物理机系统通常已通过更新安装了TLS 1.2支持补丁并默认开启该协议,因此可正常访问;测试访问Google域名时可正常运行,是因为该域名服务端仍保留低版本TLS协议兼容,未触发协议不匹配问题。
- 测试代码本身存在句柄复用导致的资源泄漏问题:
InternetOpen返回的会话根句柄被InternetOpenUrl的返回值覆盖,InternetOpenUrl调用成功时根句柄未被关闭,会造成资源泄漏。
可行解决方案
系统层面配置
- 为虚拟机内的Windows 7安装KB3140245系统更新,该更新为微软官方推送的Win7 TLS 1.1/1.2协议支持补丁,安装完成后重启系统。
- 修改注册表开启WinInet组件默认TLS 1.2支持:
- 定位到注册表路径
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\WinHttp - 新建DWORD类型值,名称为
DefaultSecureProtocols,数值数据设置为0x00000A00(十进制2560),即默认启用TLS 1.1、TLS 1.2 - 64位系统需额外在
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Internet Settings\WinHttp路径下新建同名同值的DWORD项 - 修改完成后重启系统生效
- 定位到注册表路径
代码层面优化
- 手动指定WinInet会话支持的安全协议,不依赖系统默认配置,在
InternetOpen调用前加入以下代码:// 强制启用TLS 1.2协议 DWORD dwSecureProtocols = 0x00000800; // 对应WinInet TLS 1.2协议标识 InternetSetOption(NULL, INTERNET_OPTION_SECURE_PROTOCOLS, &dwSecureProtocols, sizeof(dwSecureProtocols)); - 分离会话句柄与请求句柄,修复句柄泄漏问题,不要复用同一个变量存储
InternetOpen和InternetOpenUrl的返回值,两个句柄需分别调用InternetCloseHandle关闭。
内容的提问来源于stack exchange,提问作者Simple
相关产品推荐
相关产品推荐

