Maximizing Internet Explorer in Windows Embedded Compact 7

Posted By David Campbell
Program Manager

I’d like to welcome Doug Boling back as a guest blogger. Doug has another interesting topic this month, the customization of Windows Embedded Compact’s Internet Explorer for Embedded. As a quick introduction again, Doug has been working for many years with Windows Embedded Compact and Windows Embedded CE. He is an author, trainer and consultant specializing in Windows Embedded Compact and CE. Doug also does monthly webcasts on a variety of Windows Embedded Compact topics, like this one, that I would encourage you to check out. You can learn more about Doug by visiting his website at www.bolingconsulting.com.

Windows Embedded Compact has a customized version of Microsoft’s Internet Explorer named Internet Explorer (IE) for Embedded. This powerful browser can be used in a number of ways in an embedded system to enhance the functionality of the system. This post will discuss the various ways to tune, customize and even embed IE for Embedded inside embedded applications.

IE for Embedded is a customized version of Internet Explorer 7 for the desktop with performance enhancements from IE 8 added as well. Specifically, the JScript engine brought from IE 8 provides a 400% performance improvement over the original IE 7 scripting engine. In addition gesture support along with zoom and pan support is in this browser.

Internet Explorer for Embedded is fundamentally an HTML rendering engine. As such, the user input surrounding the engine, (the “chrome”) isn’t really part of IE for Embedded. Windows Embedded Compact comes with two examples of IE for Embedded; one with classic “Windows” controls and the other one with the chrome rendered with the XAML-driven, Silverlight for Embedded framework. Both of these examples come with the source code that demonstrates how to host the IE control. They also both illustrate that almost all the functionality of these Browsers is contained within the control itself. The chrome only provides input from the user and a platform for returning feedback.

The classic browser example, IESample, supports a favorites list, browser history and URL completion. It incorporates an internet control panel that can tune how the browser connects to the web as well as setting security settings. The XAML-based browser, IEExr, has a vastly different look and feel. However, it too handles a favorites list, history and control pane. IEExr even supports tabbed browsing using a thumbnail page to switch between pages. The reason the two examples have similar features is that most of the functionality, is incorporated in the IE ActiveX control itself.

Configuring the Browser

Since the control is the heart of IE for Embedded most of the configuration, whether registry based or through extension DLLs, are applied to the IE control not the individual example applications. The most important configuration setting is how the control identifies itself to the web servers. By default, the browser reports that it is a Windows Phone-based browser with the User Agent string:

"Windows Phone OS 7.0; Trident/3.1; IEMobile/7.0“

This ID results in many mobile-aware sites rendering a reduced detail website that is more suited to a small, portrait mode screen. Since most Windows Embedded Compact systems use a larger screen, this results in a non-optimal user experience. To have websites deliver web pages that are similar to the desktop browser, the User Agent string needs to identify the system as IE as it would be seen from a PC. The string necessary to do this is:

"Windows NT 6.1“

This string can be changed in the registry by modifying the “Platform” value under the key

[HKLM]\Software\Microsoft\Windows\CurrentVersion\Internet Settings\5.0\User Agent

Other configuration data can be set under the key

[HKCU\Software\Microsoft\Internet Explorer\Main

The values that can be changed are shown in the screen capture below showing this key in the Remote Registry Editor.

image

Under this key, the Home page URL as well as the default Search Engine can be modified among other items. Note the StackRes value. This value will be important when the IE control is embedded within other applications. I will discuss this later in the document.

Over the years, Microsoft has been vigilant in tightening the security of Internet Explorer. Sometimes this results in Microsoft limiting the functionality of the browser to prevent malicious web sites from spoofing the user. For example, popup windows are not allowed to cover the menu of the browser due to the worry that a malicious web site might spoof the user. For embedded systems that only browse secure, internal web pages, such security features may be too restrictive.

Fortunately, these restrictions are controlled in the registry and can be disabled on a case by case basis. The registry key [HKLM]\Software\Microsoft\Internet Explorer\Main\FeatureControl shown below lists a series of keys that control these restrictions.

image

Under each key, the restriction is enable or disabled by listing the name of the application that has embedded the IE control as shown below.

image

If an application is not listed under the key, then the restriction is controlled by the default security settings for the system.

Default pages, such as “Page not Found” can also be configured. The registry provides locations of the various pages to the browser under the key {HKLM]\Software\Microsoft\Internet Explorer\About URLs as shown below.

image

The locations of the pages are described as URLs. Most of the pages are defined in a resource DLL but the “Version” page is a local file. There are dozens of other configuration settings in the registry. To learn about these settings, use the Remote Registry Editor to look over these settings to see what settings are available.

Performance

Of course, performance of the browser is very important. The browser rendering engine is designed to use extension DLLs that can speed rendering web pages by accessing the hardware acceleration features of the graphics driver. Two rendering plugins, one for OpenGL enabled video drivers and one for DirectDraw drivers are packaged with Platform Builder. Conveniently, these two plugins are the same ones used by the Silverlight for Windows Embedded runtime.

The plugins are not enabled by default. To enable one of them, or to use a custom plugin, you need to modify the registry under [HKCU]\Software\Microsoft\InternetExplorer\Gesture. Set the ICSRenderMethod value to 1 indicating that IE should use a plugin. Then set the ICSRenderPlugin value to the name of the DLL that implements the plugin. The OpenGL plugin is IcsRendererOpenGL.DLL and the DirectDraw plugin is IcsRendererDDraw.DLL. Of course, the system will then need a corresponding video driver that supports the interface required by the plugin.

Internet Explorer for Embedded Applications

I mentioned earlier that there are two browser examples in Platform Builder 7. While that is true, there are actually three examples that use the Browser plug in. The third application is HTMLHelp, the help application for the operating system. The source code for that application, along with the two browser examples, IESample, and IEExr are all located in \wince700\public\ie7\oak directory. Another browser example, IESimple was in earlier versions of Platform Builder, including PB 6. That example is actually the simplest, with the application hosting the browser control and not much more. If you are interested, it is possible to port the CE 6 IESimple example project to Windows Embedded Compact 7 with only trivial source code changes. These examples provide the best documentation for how to host the browser control in your application.

Other Internet-related source code examples are also provided. Below is a list of the folders underneath the Wince700\public\IE7\oak directory.

Htmlhelp                             Fairly simple app that uses browser control

IEexr                                      XAML skinned browser

IESample                             Classic browser example

IETheme                              Skins renderer buttons, scroll bars and such

IEThmxp                              Resources to skin IE controls like XP

Inetcpl                                  IE Control panel code

Inetcpl_exr                         XAML skinned IE control panel

UrlmonUI                            Allows interception of URLMon dialog boxes

WinInetUI                           Allows interception of WinInet dialog boxes

The IETheme directory contains the code that will skin the internal controls used by the renderer such as buttons, scrollbars, and edit boxes. This code can control the look of those controls as they are rendered in the browser. Unfortunately, while the code implies that it’s possible, there is no way for the current IETheme code to skin the Combo and Listbox. This is important because when the user clicks on either in IE for Embedded, the list of the items appears in a full screen window. This is due to legacy code from the Windows Phone version of the browser.

The system does enable other ways to skin the user experience. The Internet related components WinINet and URLMon both can display dialog boxes and message boxes in response to errors, or to query the user for passwords. The URLMonUI and WinINetUI directories contain code to intercept these dialogs. This allows the system to either return a default answer and never show the dialog/message box or instead provide alternative dialog and message boxes for user feedback.

Both directories contain example code that implement two functions, IsDialogBoxHandled and IsMessageBoxHandled. For both cases, if the routine returns ERROR_CALL_NOT_IMPLEMENTED, the operating system will display the standard dialog box. However, if the routine returns any other value, the operating system interprets the return value as the value that would have been returned by the user had the dialog box been displayed. This allows customized versions of these DLLs either provide a default return value for a given query or to provide dialog boxes better suited to the customized interface of the device.

Embedding the IE Control in an Application

The ultimate customization is to embed the IE Control inside your own application. While fairly straightforward, since the interfaces for the control are similar to the desktop IE control, there are a series of requirements that must be met by the application.

First, the default stack size of 64 KB for a Windows Embedded Compact 7 application simply isn’t big enough for the IE Control. The best way to determine the appropriate stack size is to read the registry value StackRes under the key [HKCU\Software\Microsoft\Internet Explorer\Main. Looking at the figure earlier in the document we can see that the value for the IE for Embedded control is 256 KB.

This value could be set in the linker when the application was built, but the traditional method for supporting the larger stack size is to have the main thread of the application read the registry value and then create a secondary thread with the proper stack size. Interestingly, this is one of the few areas where it is appropriate for the secondary thread to be the primary user interface thread for the application. In fact, the example code shows that every new instance of the IE control needs its own thread as well. When implementing the application this way, the main thread creates the blocks and waits for all the secondary threads hosting the IE Control instances to terminate. Then the main thread terminates. Under Windows Embedded Compact, if the main thread terminates for any reason, the application is terminated as well even if secondary threads are still active.

In addition to the stack size requirement, an application hosting the IE control needs to declare a number of GUIDs for the IE Control interfaces. These GUIDs aren’t defined anywhere else in Platform Builder so in all the IE Control hosting examples, the GUIDs are simply declared in the .cpp file that contains the code hosting the control. The necessary GUIDs are shown below.

DEFINE_GUID(CLSID_WebBrowser, 0x8856F961L, 0x340A, 0x11D0, 0xA9, 0x6B,

                                    0x00, 0xC0, 0x4F, 0xD7, 0x05, 0xA2);

 

DEFINE_GUID(IID_IWebBrowser, 0xEAB22AC1L, 0x30C1, 0x11CF, 0xA7, 0xEB,

                                    0x00, 0x00, 0xC0, 0x5B, 0xAE, 0x0B);

 

DEFINE_GUID(IID_IWebBrowser2, 0xD30C1661L, 0xCDAF, 0x11D0, 0x8A, 0x3E,

                                    0x00, 0xC0, 0x4F, 0xC9, 0xE2, 0x6E);

 

DEFINE_GUID(DIID_DWebBrowserEvents, 0xEAB22AC2L, 0x30C1, 0x11CF, 0xA7, 0xEB,

                                    0x00, 0x00, 0xC0, 0x5B, 0xAE, 0x0B);

 

DEFINE_GUID(DIID_DWebBrowserEvents2, 0x34A715A0L, 0x6587, 0x11D0, 0x92, 0x4A,

                                     0x00, 0x20, 0xAF, 0xC7, 0xAC, 0x4D);

 

DEFINE_GUID(IID_IWebBrowserApp, 0x0002DF05L, 0x0000, 0x0000, 0xC0, 0x00,

                                    0x00, 0x00, 0x00, 0x00, 0x00, 0x46);

As your application must host the ActiveX control, it must implement a series of event handling interfaces that receive feedback from the IE control. All the examples provided in Platform Builder accomplish this by supporting a series of interfaces in the class that hosts the IE Control. Below is the class statement used in HTMLHelp for the class that hosts the browser showing the interfaces supported.

class CMainWnd :

    public IOleContainer,

    public IOleClientSite,

    public IOleInPlaceSite,

    public IServiceProvider,

    public DWebBrowserEvents2,

    public IDocHostUIHandler,

    public IDocHostShowUI, // msgbox, help window

    public IHTMLOMWindowServices // for window move, resize events

While some of the methods in the interfaces must be implemented, the vast majority of the methods are stubbed out, returning E_NOTIMPL. The best documentation for what is required is the source code for the browser and help examples in Platform Builder.

One last item that I want to cover is how to programmatically support zooming the web page in and out. There are actually two “Zooms” supported by Internet Explorer. The first zoom is used to adjust the font sizes for a given page. This zoom has been around for a number of years. The zoom that most developers and users are see today allowing the entire page to scale is called Optical Zoom.

The code below is a slightly edited routine from the XMAL-skinned browser example IEExr. The code zooms the window by the passed value. The code first performs a range check by calling OLECMDID_OPTICAL_GETZOOMRANGE. Then the code sets the zoom value by calling OLECMDID_OPTICAL_ZOOM.

HRESULT TabWindow::OnZoomTo(ULONG lFactor)

{

    HRESULT hr = S_OK;

    CComPtr<IOleCommandTarget> pCommandTarget;

    CComVariant varFactor;

    CComVariant varRange;

    CComVariant varCurrent;

 

    CPRAEx(m_pBrowser, E_UNEXPECTED);

 

    CHRA(m_pObject->QueryInterface (IID_IOleCommandTarget,

                                  (LPVOID*)&pCommandTarget));

 

    CHRA(pCommandTarget->Exec(NULL/*pguidCmdGroup*/,

                              OLECMDID_OPTICAL_GETZOOMRANGE,

                              MSOCMDEXECOPT_DONTPROMPTUSER,

                              NULL/*pvaIn*/,

                              &varRange));

    varCurrent.vt = VT_I4;

    varCurrent.lVal = 0;

 

    // Get the current optical zoom setting

    CHRA(pCommandTarget->Exec(NULL/*pguidCmdGroup*/,

                              OLECMDID_OPTICAL_ZOOM,

                              OLECMDEXECOPT_DONTPROMPTUSER,

                              NULL/*pvaIn*/,

                              &varCurrent));

    varFactor.vt = VT_I4;

    varFactor.lVal = lFactor;

 

    // Range check

    varFactor.lVal = varFactor.lVal < LOWORD(varRange.lVal) ?

                                LOWORD(varRange.lVal) : varFactor.lVal;

 

    varFactor.lVal = varFactor.lVal > HIWORD(varRange.lVal) ?

                                HIWORD(varRange.lVal) : varFactor.lVal;

 

    // The varFactor.lVal is 0 if the returned zoom range is invalid.

    // If the zoom range is correct, zoom to the appropriate factor;

    // else, cache the zoom command until the web page nav is completed.

    if (varFactor.lVal != 0 && varFactor.lVal != varCurrent.lVal)

    {

        hr = pCommandTarget->Exec(NULL/*pguidCmdGroup*/,

                                  OLECMDID_OPTICAL_ZOOM,

                                  OLECMDEXECOPT_DONTPROMPTUSER,

                                  &varFactor,

                                  NULL/*pvaOut*/);

        m_bIsZoomOperationCached = false;

        CHRA(hr);

    }

    else if (varFactor.lVal == 0)

    {

        m_ulZoomFactor = lFactor;

        m_bIsZoomOperationCached = true;

    }

 

Error:

    return hr;

}

Summary

Internet Explorer for Embedded is a powerful tool that can be used in a variety of ways in your embedded system. There are a few actions that you should do when using IE for Embedded. First, be sure to enable hardware acceleration if your video driver supports an OpenGL or DirectDraw interface. You will need to change the default User Agent string if you want web pages to be rendered as they are on the desktop. Finally, learn the control and its capabilities. The best way to learn the control is to learn the source code for the example browsers that come with Platform Builder. Remember, the source code is the documentation.

I’d like to thank Doug for his always insightful teachings and extend an ongoing invitation back. As mentioned, Doug hosts a monthly webcast, here are the details for the next one:

When: Tuesday June 19, 2012, 9:00 AM Pacific Time

Title: Image Tuning to balance Performance and Power in Windows Embedded Compact 7

Overview: The demands of the embedded world make creating the best image possible an absolute requirement. This difficult task is made easier by the vast array of profiling and tuning tools available in Windows Embedded Compact 7. Come learn about these tools and see how they are used in this informative, example filled webcast.

Registration link (includes link to previous recordings): https://www.microsoft.com/windowsembedded/en-us/develop/windows-embedded-compact-7-developer-classroom.aspx