使用IE9嵌入WebBrowser控件时覆盖IE设置 [英] Overriding IE settings when embedding a WebBrowser control using IE9

查看:152
本文介绍了使用IE9嵌入WebBrowser控件时覆盖IE设置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have an application (written in C++ with MFC, but I don't think that that's particularly relevant) that embeds the Internet Explorer ActiveX WebBrowser control for the purpose of showing some HTML pages. One requirement has always been to use the application's font name and size settings as the default settings for the HTML, rather than Internet Exporer's defaults.

为了实现这一点,应用程序实现IDocHostUIHandler2 COM接口,它传递给WebBrowser控件。这将导致控件调用应用程序的 GetOptionKeyPath ,它允许应用程序设置WebBrowser控件获取其设置的注册表位置。使用Sysinternals的工具来查看IE使用哪些键找到字体名称和大小,这已经足以做我需要的。

To achieve this, the application implements the IDocHostUIHandler2 COM interface, which it passes to the WebBrowser control. This causes the control to call the application's implementation of GetOptionKeyPath, which lets the application set the registry location that the WebBrowser control gets its settings from. Armed with Sysinternals' tools to see which keys IE uses to find the font name and size, this has been sufficient to do what I need.

但是,互联网的应用Explorer 9是一个令人讨厌的惊喜:在我测试过的所有机器,安装了IE9,WebBrowser控件使用自己的设置,忽略从应用程序的注册表位置。使用调试器进行测试显示,WebBrowser控件从不调用提供的GetOptionKeyPath。

However, the appeareance of Internet Explorer 9 has come as a nasty surprise: on all machines that I've tested with that have IE9 installed, the WebBrowser control uses its own settings, ignoring the registry location from the application. Testing with a debugger shows that the WebBrowser control never calls the provided GetOptionKeyPath.

更多的实验表明,IE9 WebBrowser控件正在调用类似的a href =http://msdn.microsoft.com/en-us/library/aa753274%28v=vs.85%29.aspx =nofollow> GetOverrideKeyPath 方法:据称提供了一种方法覆盖IE设置,而如果在注册表的相关部分找不到任何内容,则会回退到IE的实际设置。不幸的是,这有两个问题:1)这不是我想要的,和2)IE9并不总是检查下GetOverrideKeyPath注册表位置,然后去IE默认注册表设置。

A bit more experimentation shows that the IE9 WebBrowser control is calling the similar (but not identical) GetOverrideKeyPath method: this allegedly provides a way to override IE settings, while falling back to IE's actual settings if nothing is found in the relevant part of the registry. Unfortunately this has two problems: 1) It's not quite what I want, and 2) IE9 doesn't always check under the GetOverrideKeyPath registry location before going to the IE default registry settings.

查看 GetOptionKeyPath MSDN页面 a>有几个投诉沿着类似的线,但没有解决方案。有没有人发现一个干净的方式说服WebBrowser控制恢复到实际调用GetOptionKeyPath的前IE9行为记录?

Looking at the GetOptionKeyPath MSDN page there are a few complaints along similar lines, but no solutions. Has anyone found a clean way to persuade the WebBrowser control to revert to the pre-IE9 behaviour of actually calling GetOptionKeyPath as documented?

推荐答案

我想出了一个黑客来解决这个问题,但我应该警告你:这不漂亮。现在停止阅读,如果你很容易冒犯...

I've come up with a hack to solve this problem, but I should warn you: it's not pretty. Stop reading now if you've easily offended ...

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

Since there seems to be no way of making IE9 use the IDocHostUIHandler::GetOptionKeyPath() method, I used SysInternals' tools to see which IE9 DLLs accessed the relevant parts of the registry to load the IE9 settings. This revealed the only culprits as "mshtml.dll" and "iertutil.dll", both of which call RegOpenKeyExW().

计划然后加载这些DLL之前初始化WebBrowser控件,并修补它们,以便调用重定向到我的代码,在那里我可以说谎我打开了什么注册表项,使用dbghelp.dll。所以,开始,在初始化WebBrowser控件之前:

The plan was then to load these DLLs before initializing the WebBrowser control, and patch them so that calls are redirected to my code, where I can lie about what registry key I've opened, using dbghelp.dll. So, to start, before initializing the WebBrowser control:

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);
}

现在,执行邪恶的工作的代码扫描DLLs导入地址表和修补所请求的函数(错误处理被省略以保持代码大小降低):

And now, the code that does the evil work of scanning the DLLs import address tables, and patching the requested function (error handling omitted to keep the code size down):

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的函数调用我的代码, (HKEY hKey,LPCWSTR lpSubKey,DWORD ulOptions,REGSAM samDesired,PHKEY phkResult)替换RegOpenKeyExW():

Finally, the function that I have patched the DLLs to call in my code, in place of 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中正确地解决这个问题。

Amazingly enough, this horrible hack actually works. But please, Microsoft, if you're listening, please fix this properly in IE10.

这篇关于使用IE9嵌入WebBrowser控件时覆盖IE设置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆