首页 文章

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

提问于
浏览
3

我有一个应用程序(用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 's actual settings if nothing is found in the relevant part of the registry. Unfortunately this has two problems: 1) It'不是我想要的,2)IE9没有在进入IE默认注册表设置之前,请始终在GetOverrideKeyPath注册表位置进行检查 .

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

1 回答

  • 3

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

    由于似乎没有办法让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中正确解决这个问题 .

相关问题