微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

windows – 使用IE9嵌入WebBrowser控件时覆盖IE设置

我有一个应用程序(用C语言编写MFC,但我不认为那是特别相关的)嵌入Internet Explorer ActiveX Webbrowser控件以显示一些HTML页面.一个要求始终是使用应用程序的字体名称和大小设置作为HTML的认设置,而不是Internet Exporer的认设置.

为此,应用程序实现了IDocHostUIHandler2 COM接口,并将其传递给Webbrowser控件.这会导致控件调用应用程序的GetOptionKeyPath实现,该实现允许应用程序设置Webbrowser控件从中获取其设置的注册表位置.使用Sysinternals的工具来查看IE使用哪些键来查找字体名称和大小,这足以满足我的需要.

但是,Internet Explorer 9的出现令人惊讶:在我测试过的所有安装了IE9的机器上,Webbrowser控件使用自己的设置,忽略了应用程序的注册表位置.使用调试器进行测试表明Webbrowser控件从不调用提供的GetoptionKeyPath.

更多实验表明,IE9 Webbrowser控件正在调用类似(但不完全相同)的GetOverrideKeyPath方法:据称这提供了一种覆盖IE设置的方法,如果在注册表的相关部分中找不到任何内容,则会回退到IE的实际设置.不幸的是,这有两个问题:1)它不是我想要的,2)IE9在进入IE注册表设置之前并不总是在GetoverrideKeyPath注册表位置检查.

看看GetOptionKeyPath MSDN page,有类似线路的一些投诉,但没有解决方案.有没有人找到一种干净的方法来说服Webbrowser控件恢复到实际调用GetoptionKeyPath的IE9之前的行为?

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

由于似乎无法使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,(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.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,phkResult);
 }
 else
   return ::RegOpenKeyExW(hKey,phkResult);
}

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

原文地址:https://www.jb51.cc/windows/372085.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐