使用IE9embeddedWebBrowser控件时覆盖IE设置

我有一个应用程序(使用MFC编写的C ++,但我不认为这是特别相关的)embeddedInternet Explorer ActiveX WebBrowser控件的目的是显示一些HTML页面。 一个要求一直是使用应用程序的字体名称和大小设置作为HTML的默认设置,而不是Internet Exporer的默认设置。

为此,应用程序实现IDocHostUIHandler2 COM接口,将其传递给WebBrowser控件。 这会导致控件调用应用程序的GetOptionKeyPath实现,该应用程序允许应用程序设置WebBrowser控件从中获取其设置的registry位置。 用Sysinternals的工具武装,看看IE使用哪些键来查找字体名称和大小,这已经足以做我所需要的。

但是,Internet Explorer 9的出现却是一个令人不快的惊喜:在我testing过的所有机器上安装了IE9,WebBrowser控件使用自己的设置,忽略了应用程序的registry位置。 使用debugging器进行testing表明WebBrowser控件从不调用提供的GetOptionKeyPath。

多一点实验表明,IE9 WebBrowser控件正在调用类似(但不完全相同)的GetOverrideKeyPath方法:据称这提供了一种方法来覆盖IE设置,同时回落到IE的实际设置,如果没有在registry的相关部分find。 不幸的是,这有两个问题:1)它不是我想要的,2)在进入IE默认registry设置之前,IE9并不总是在GetOverrideKeyPathregistry位置下进行检查。

查看GetOptionKeyPath MSDN页面,有类似的一些抱怨,但没有解决scheme。 有没有人find一个干净的方式来说服WebBrowser控制恢复到实际调用GetOptionKeyPath的前IE9行为logging?

Solutions Collecting From Web of "使用IE9embeddedWebBrowser控件时覆盖IE设置"

我想出了一个办法来解决这个问题,但我应该警告你:这不是很好。 现在停止阅读,如果你轻易冒犯了…

由于似乎没有办法使IE9使用IDocHostUIHandler :: GetOptionKeyPath()方法,我使用SysInternals的工具来查看哪些IE9 DLL访问注册表的相关部分加载IE9设置。 这揭示了唯一的罪魁祸首作为“mshtml.dll”和“iertutil.dll”,这两者都调用RegOpenKeyExW()。

然后,计划在初始化WebBrowser控件之前加载这些DLL,并将其修补,以便将调用重定向到我的代码,在那里我可以使用dbghelp.dll来说明我打开的注册表项。 因此,在初始化WebBrowser控件之前,

if (theApp.GetIEVersion() >= 9.0) { HMODULE advadi = ::LoadLibrary("advapi32.dll"); HMODULE mshtml = ::LoadLibrary("mshtml.dll"); HookApiFunction(mshtml,advadi,"advapi32.dll","RegOpenKeyExW",(PROC)HookRegOpenKeyExW); HMODULE iertutil = ::LoadLibrary("iertutil.dll"); HookApiFunction(iertutil,advadi,"advapi32.dll","RegOpenKeyExW",(PROC)HookRegOpenKeyExW); } 

而现在,执行扫描DLL的邪恶工作的代码将导入地址表,并修补所请求的函数(省略错误处理以减小代码大小):

 void HookApiFunction(HMODULE callingDll, HMODULE calledDll, const char* calledDllName, const char* functionName, PROC newFunction) { // Get the pointer to the 'real' function PROC realFunction = ::GetProcAddress(calledDll,functionName); // Get the import section of the DLL, using dbghelp.dll's ImageDirectoryEntryToData() ULONG sz; PIMAGE_IMPORT_DESCRIPTOR import = (PIMAGE_IMPORT_DESCRIPTOR) ImageDirectoryEntryToData(callingDll,TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT,&sz); // Find the import section matching the named DLL while (import->Name) { PSTR dllName = (PSTR)((PBYTE)callingDll + import->Name); { if (stricmp(dllName,calledDllName) == 0) break; } import++; } if (import->Name == NULL) return; // Scan the IAT for this DLL PIMAGE_THUNK_DATA thunk = (PIMAGE_THUNK_DATA)((PBYTE)callingDll + import->FirstThunk); while (thunk->u1.Function) { PROC* function = (PROC*)&(thunk->u1.Function); if (*function == realFunction) { // Make the function pointer writable and hook the function MEMORY_BASIC_INFORMATION mbi; ::VirtualQuery(function,&mbi,sizeof mbi); if (::VirtualProtect(mbi.BaseAddress,mbi.RegionSize,PAGE_READWRITE,&mbi.Protect)) { *function = newFunction; DWORD protect; ::VirtualProtect(mbi.BaseAddress,mbi.RegionSize,mbi.Protect,&protect); return; } } thunk++; } 

最后,我已经修补DLL的函数来调用我的代码,而不是RegOpenKeyExW():

 LONG WINAPI HookRegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult) { static const wchar_t* ieKey = L"Software\\Microsoft\\Internet Explorer"; // Never redirect any of the FeatureControl settings if (wcsstr(lpSubKey,L"FeatureControl") != NULL) return ::RegOpenKeyExW(hKey,lpSubKey,ulOptions,samDesired,phkResult); if (wcsnicmp(lpSubKey,ieKey,wcslen(ieKey)) == 0) { // Redirect the IE settings to our registry key CStringW newSubKey(m_registryPath); newSubKey.Append(lpSubKey+wcslen(ieKey)); return ::RegOpenKeyExW(hKey,newSubKey,ulOptions,samDesired,phkResult); } else return ::RegOpenKeyExW(hKey,lpSubKey,ulOptions,samDesired,phkResult); } 

令人惊讶的是,这个可怕的黑客真的有用。 但是,请微软,如果你在听,请在IE10中正确解决这个问题。