webbrowser1 webbrowser visual que net ejemplo crear windows com internet-explorer-9 webbrowser-control

windows - visual - Anulando la configuración de IE al incrustar un control WebBrowser usando IE9



webbrowser1 c# (1)

Tengo una aplicación (escrita en C ++ con MFC, pero no creo que eso sea particularmente relevante) que incorpora el control WebBrowser de Internet Explorer ActiveX con el propósito de mostrar algunas páginas HTML. Un requisito siempre ha sido utilizar los ajustes de nombre y tamaño de fuente de la aplicación como la configuración predeterminada para el HTML, en lugar de los valores predeterminados de Internet Exporer.

Para lograr esto, la aplicación implementa la interfaz COM IDocHostUIHandler2, que pasa al control WebBrowser. Esto hace que el control llame a la implementación de la aplicación de GetOptionKeyPath , que permite que la aplicación establezca la ubicación de registro desde la que obtiene control el control WebBrowser. Armado con las herramientas de Sysinternals para ver qué claves usa IE para encontrar el nombre y el tamaño de la fuente, esto ha sido suficiente para hacer lo que necesito.

Sin embargo, la apariencia de Internet Explorer 9 ha sido una sorpresa desagradable: en todas las máquinas con las que he probado y que tienen IE9 instalado, el control WebBrowser usa su propia configuración, ignorando la ubicación del registro desde la aplicación. La prueba con un depurador muestra que el control WebBrowser nunca llama al GetOptionKeyPath proporcionado.

Un poco más de experimentación muestra que el control WebBrowser IE9 está llamando al método GetOverrideKeyPath similar (pero no idéntico): supuestamente proporciona una forma de anular la configuración de IE, mientras que vuelve a la configuración real de IE si no se encuentra nada en la parte relevante del registro . Lamentablemente, esto tiene dos problemas: 1) No es exactamente lo que quiero, y 2) IE9 no siempre comprueba bajo la ubicación del registro GetOverrideKeyPath antes de ir a la configuración de registro predeterminada de IE.

En cuanto a la página GetOptionKeyPath MSDN, hay algunas quejas en líneas similares, pero no hay soluciones. ¿Alguien ha encontrado una manera limpia de persuadir al control WebBrowser para que vuelva al comportamiento previo a IE9 de realmente llamar a GetOptionKeyPath como está documentado?


He encontrado un truco para resolver este problema, pero debo advertirte: no es bonito. Deja de leer ahora si te has ofendido fácilmente ...

Dado que parece que no hay forma de hacer que IE9 use el método IDocHostUIHandler :: GetOptionKeyPath (), utilicé las herramientas de SysInternals para ver qué DLL de IE9 accedieron a las partes relevantes del registro para cargar las configuraciones de IE9. Esto reveló los únicos culpables como "mshtml.dll" y "iertutil.dll", que llaman RegOpenKeyExW ().

El plan era entonces cargar estos archivos DLL antes de inicializar el control WebBrowser y aplicarles un parche para que las llamadas se redireccionaran a mi código, donde puedo mentir sobre la clave de registro que abrí utilizando dbghelp.dll. Entonces, para comenzar, antes de inicializar el control 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); }

Y ahora, el código que hace el malvado trabajo de escanear las DLL importa tablas de direcciones y parchear la función solicitada (se omite el manejo de errores para mantener reducido el tamaño del código):

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

Finalmente, la función que he parcheado las DLL para llamar a mi código, en lugar de 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); }

Sorprendentemente, este horrible truco realmente funciona. Pero, por favor, Microsoft, si está escuchando, corrija esto correctamente en IE10.