Page 1 of 1

wxInternetExplorerHelper

Posted: Thu Mar 22, 2018 7:58 am
by PB
When an application is using the Microsoft Internet Explorer backend for wxWebView, it is almost always necessary to set the appropriate emulation level. While this is generally a job for the installer, sometimes it may be needed to do it from the application’s code, e.g., in a portable installer-less application or just when playing with the code. wxWidgets has recently introduced wxWebView::MSWSetModernEmulationLevel() method but it unfortunately sets the emulation level only to IE8, which is often not high enough.

wxInternetExplorerHelper has two purposes:
1. To obtain the installed version of Internet Explorer.
2. To obtain and set the emulation level for the current application (for a currently logged user).

wxInternetExplorerHelper.h

Code: Select all

////////////////////////////////////////////////////////////////////////////////////
//
//  Name:        wxInternetExplorerHelper.h
//  Purpose:     Implements utility functions for detecting version of
//               Microsoft Internet Explorer and for detecting and setting
//               the emulation level for applications using wxWebViewIE
//  Author:      PB
//  Copyright:   (c) 2017 PB <[email protected]>
//  Licence:     wxWindows licence
//
////////////////////////////////////////////////////////////////////////////////////

#ifndef WX_INTERNET_EXPLORER_HELPER_H_DEFINED
#define WX_INTERNET_EXPLORER_HELPER_H_DEFINED

#include <stddef.h>

class wxInternetExplorerHelper
{
public:
    enum Version
    {
        Version_unknown = 0,
        Version_IE5 = 5,
        Version_IE6,
        Version_IE7,
        Version_IE8,
        Version_IE9,
        Version_IE10,
        Version_IE11
    };

    // Go here to learn more about individual values
    // https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/general-info/ee330730(v=vs.85)#browser_emulation
    enum Emulation
    {
        Emulation_none = 0,
        Emulation_unknown = 1,
        Emulation_IE7 = 7000, // default value for wxWebViewIE host
        Emulation_IE8_Default = 8000,
        Emulation_IE8_Standards = 8888,
        Emulation_IE9_Default = 9000,
        Emulation_IE9_Standards = 9999,
        Emulation_IE10_Default = 10000,
        Emulation_IE10_Standards = 10001,
        Emulation_IE11_Default = 11000,
        Emulation_IE11_Standards = 11001
    };

    // Uses the version of MSHTML.dll which may not
    // be exactly the same as the MSIE version but 
    // is exact enough for the purpose.
    static Version GetIEVersion(); 
    static bool IsIEVersionAtLeast(Version version);

    // Retrieves the emulation level for the calling executable
    // for the current user.
    static bool GetEmulation(Emulation& emulation);

    // Sets the emulation level for the calling executable
    // for the current user.
    // Calling with Emulation_none removes the emulation information 
    // for the calling executable for the current user from the registry.
    static bool SetEmulation(Emulation emulation);

private:
    static bool GetMSHTMLDllVersion(unsigned& major, 
                                    unsigned* minor = NULL, 
                                    unsigned* build = NULL, 
                                    unsigned* revision = NULL);
};


#endif // #ifdef WX_INTERNET_EXPLORER_HELPER_H_DEFINED
wxInternetExplorerHelper.cpp

Code: Select all

////////////////////////////////////////////////////////////////////////////////////
//
//  Name:        wxInternetExplorerHelper.cpp
//  Purpose:     Implements utility functions for detecting version of
//               Microsoft Internet Explorer and for detecting and setting
//               the emulation level for applications using wxWebViewIE
//  Author:      PB
//  Copyright:   (c) 2017 PB <[email protected]>
//  Licence:     wxWindows licence
//
////////////////////////////////////////////////////////////////////////////////////


#include "wxInternetExplorerHelper.h"

#ifdef __WXMSW__

#include <wx/buffer.h>
#include <wx/dynlib.h>

#include <wx/msw/registry.h>
#include <wx/msw/private.h>
#include <wx/msw/wrapwin.h>

wxInternetExplorerHelper::Version wxInternetExplorerHelper::GetIEVersion()
{
    unsigned major;

    if ( !GetMSHTMLDllVersion(major) )
        return Version_unknown;

    if ( major >= Version_IE5 && major <= Version_IE11 )
        return static_cast<Version>(major);
    else
        return Version_unknown;
}

bool wxInternetExplorerHelper::IsIEVersionAtLeast(Version version)
{
    wxCHECK(version != Version_unknown, "Invalid version value");
    
    const Version v = GetIEVersion();
    
    return v != Version_unknown && v >= version;        
}

// Code for getting/setting emulation is adapted from wxWebViewIE::MSWSetModernEmulationLevel()
// in WXWIN/src/msw/webview_ie.cpp

 // Registry key where emulation level for programs are set.
//  Used by wxInternetExplorerHelper::{Get|Set}Emulation()
static const wxChar* IE_EMULATION_KEY =
    wxS("SOFTWARE\\Microsoft\\Internet Explorer\\Main")
    wxS("\\FeatureControl\\FEATURE_BROWSER_EMULATION");

bool wxInternetExplorerHelper::GetEmulation(wxInternetExplorerHelper::Emulation& emulation)
{
    wxRegKey key(wxRegKey::HKCU, IE_EMULATION_KEY);
    
    if ( !key.Exists() )
    {        
        return false;
    }

    const wxString programName = wxGetFullModuleName().AfterLast('\\');
    
    if ( !key.HasValue(programName) )
    {
        emulation = Emulation_none;
        return true;
    }
    
    long keyValue;

    if ( !key.QueryValue(programName, &keyValue) )
    {
        return false;
    }

    switch ( keyValue )
    {
        case Emulation_IE7:
        case Emulation_IE8_Default: 
        case Emulation_IE8_Standards:
        case Emulation_IE9_Default:
        case Emulation_IE9_Standards:
        case Emulation_IE10_Default:
        case Emulation_IE10_Standards:
        case Emulation_IE11_Default:
        case Emulation_IE11_Standards:
            emulation = static_cast<Emulation>(keyValue);
            break;
        default:
            emulation = Emulation_unknown;
    };

    return true;
}

bool wxInternetExplorerHelper::SetEmulation(wxInternetExplorerHelper::Emulation emulation)
{
    wxCHECK(emulation != Emulation_unknown, wxS("Invalid emulation value"));
        
    wxRegKey key(wxRegKey::HKCU, IE_EMULATION_KEY);

    if ( !key.Exists() )
    {        
        return false;
    }
    
    const wxString programName = wxGetFullModuleName().AfterLast('\\');
    
    if ( emulation == Emulation_none )    
    {
        return key.DeleteValue(programName);
    }
    
    return key.SetValue(programName, static_cast<long>(emulation));
}

// code adapted from private function GetFileVersion(const wxString& filename) 
// in WXWIN/src/msw/dllmsw.cpp
bool wxInternetExplorerHelper::GetMSHTMLDllVersion(unsigned& major, 
                                                   unsigned* minor, 
                                                   unsigned* build, 
                                                   unsigned* revision)
{
    static const wxChar* dllName = wxS("mshtml.dll");	
    const DWORD sizeVerInfo = ::GetFileVersionInfoSize(dllName, NULL);

    if ( sizeVerInfo )
    {
        wxCharBuffer buf(sizeVerInfo);

        if ( ::GetFileVersionInfo(dllName, 0, sizeVerInfo, buf.data()) )
        {
            void *pVer = NULL;
            UINT sizeInfo = 0;
            
            if ( ::VerQueryValue(buf.data(), const_cast<wxChar*>(wxS("\\")),
                &pVer, &sizeInfo) )
            {
                const VS_FIXEDFILEINFO* info = (VS_FIXEDFILEINFO*)pVer;

                major = HIWORD(info->dwFileVersionMS);
                if ( minor )
                    *minor = LOWORD(info->dwFileVersionMS);
                if ( build )
                    *build = HIWORD(info->dwFileVersionLS);
                if ( revision )
                    *revision = LOWORD(info->dwFileVersionLS);

                return true;
            }
        }
    }

    return false;
}

#else // #ifdef __WXMSW__

wxInternetExplorerHelper::Version wxInternetExplorerHelper::GetIEVersion()
{ return Version_Unknown; }

bool wxInternetExplorerHelper::IsIEVersionAtLeast(wxInternetExplorerHelper::Version)
{ return false; }

bool wxInternetExplorerHelper::GetMSHTMLDllVersion(unsigned&, unsigned*, unsigned*, unsigned*)
{ return false; }

bool wxInternetExplorerHelper::GetEmulation(wxInternetExplorerHelper::Emulation&)
{ return false; }

bool wxInternetExplorerHelper::SetEmulation(wxInternetExplorerHelper::Emulation)
{ return false; }

#endif // #ifdef __WXMSW__