Export (0) Print
Expand All
Expand Minimize

Using the Windows CE .NET Internet Explorer ActiveX Control

 

Mike Hall
Microsoft Corporation

Steve Maillet
Entelechy Consulting

January 7, 2003

Summary: Shows how to use eMbedded Visual C++ to create an MFC-based application that hosts the Windows CE .NET Internet Explorer ActiveX control. (9 printed pages)

Welcome to the first Microsoft® Windows® CE Get Embedded article of 2003. First, I should apologize for not wishing the readers of this article CEsons (seasons) greetings in December article. (It's amazing what you can do with CE, isn't it?)

Okay, this month we will take a look at a question that appears in the newsgroups every so often, and has popped up in the newsgroups during the last week or so. The question is, "How do I make use of the Windows CE Microsoft® Internet Explorer control within my Windows CE application?" And more importantly, "I've seen how this works on Pocket PC 2002, but can't get this working with Windows CE .NET." To answer this, I'm going to cheat by using some code and samples from last year's Windows Embedded Developers Conference, in particular, the eMbedded Microsoft® Visual C++® hands-on lab. The content for the lab was written by Doug Boling, speaker extraordinaire, and author of Programming Windows CE Second Edition. Doug can be found at http://www.bolingconsulting.com/.

In order to test out the code used in this article, we need to create a custom operating system image. So that you can all follow along, we will use the emulator to test the code. The emulator does ship with a pre-configured operating system image, STANDARDSDK_410 Emulator. Unfortunately, the standard SDK emulation image doesn't contain the Internet Explorer application, and by definition doesn't contain the Internet Explorer control. This is why we need to create a custom operating system image.

In case you haven't been through the steps of creating a Windows CE .NET platform before, here are the steps for creating our base image, which includes the Internet Explorer.

  1. Launch Platform Builder.
  2. From the File menu, click New Platform.
  3. On the New Platform Wizard, click Next.
  4. From the list of available BSPs, select EMULATOR: X86, and then click Next.
  5. From the list of available platform configurations, click Web Pad.
  6. In the Platform Name box, type IEViewer as the name for your platform, and then click Next.
  7. From the list of Web Pad Device variants, select Web Pad, and then click Next.
  8. On the Application & Media page, only select Internet Browser. Disable all other options. (Note that any of the features can be added by using the component catalog). Click Next.
  9. On the Networking & Communications page, disable Personal Area Network (PAN) | Bluetooth (note that this can be added at any time by using the component catalog); Wide Area Networking, and TCP/IPV6. click Next.
  10. On the Congratulations page, click Done to close the New Platform Wizard.
  11. From the Build menu, click Set Active Configuration.
  12. From the list of platform configurations, select EMULATOR: X86 Win32 (WCE emulator) Release, and then click OK.

Now we build the operating system image. On the Build menu, click Build Platform. The build process will take a few minutes; once complete, we will need to create a custom Software Development Kit (SDK) for our platform. This process is well documented in a Get Embedded article from last year, Creating a Software Development Kit for Windows CE .NET.

With the platform built, and the SDK created and installed, we're now ready to write our application. We will be using eMbedded Visual C++ 4.0 to write a Microsoft® Foundation Classes (MFC) application that hosts the Internet Explorer control.

First, it's probably a good idea to download our custom operating system image to the emulator, so we're ready to build, download, and test our MFC application. In Platform Builder, on the Target menu, click Download. You will be prompted to configure a connection to the target. Click OK, select Emulator for the download and kernel transport, and click OK. Click OK on the KITL Security Warning.

You're probably wondering why you get a security warning when you download an operating system image to the emulator or to any Windows CE .NET reference board. Let's take a quick detour to find out what's happening...

There's a hint in the wording of the security warning. Here's the text from the warning dialog: "Connecting to this device using KITL will allow the device to have remote access to the local file system." In the Emulator, open "My Computer." You will notice a number of folders, including one called "Release." If you open this folder, you will see hundreds of files, including the NK.BIN, which you've just downloaded to the emulator. The Release folder is a shared folder between the desktop development environment and the current reference platform. Anything we drop into our _FLATRELEASEDIR (on the desktop PC) from Platform Builder will be visible to the emulator. (We've seen this in use in the emulator WebCam article a few months ago.) The Emulator desktop has three icons, Recycle Bin, My Computer, and Internet Explorer. If you see these icons on the desktop, you're in good shape. Now, on with writing the code using eMbedded Visual C++ 4.0.

Start eMbedded Visual C++. The development environment is very similar to Visual C++ 6.0 for the desktop, though you will notice some differences when we run through the Application Wizard. Here are the steps needed to create the application's boilerplate code. We will customize the application once the wizard is complete.

  1. On the File menu, click New. This will display the Application Wizard. You will notice that you can only create WCE (Windows CE) -based applications using this tool.
  2. Enter an application name of IEViewer. Also, notice the list of supported processors at the bottom of the dialog. Since we're building for the emulator, we should make sure that Win32 Emulator is enabled. You can select more than one processor from the list.
  3. Select WCE MFC AppWizard (exe). We're going to build an MFC-based application. Click OK. This will launch the Application Wizard for MFC-based applications. There are four steps to the wizard:
  4. Application Wizard Step 1. Use the default options, Single Document with Document View Architecture. Here we can see one major difference between the desktop and Windows CE Application Wizard: Windows CE supports Single Document, and Dialog-based applications. The desktop also supports MDI (Multiple Document Interface) -based applications.
  5. Application Wizard Step 2. Add support for Windows Sockets and Microsoft® ActiveX® controls.
  6. Application Wizard Step 3. Use the default options, Comments and Shared MFC DLL.
  7. Application Wizard Step 4. Select the View (CIEViewerView) and change the view type from CView to CformView.
  8. Click Finish.

That creates the boilerplate code. You could build and test the application. Since we've created a new platform (IEViewer), and have created an SDK, we also need to make sure that the connection between eMbedded Visual C++ and the running target is okay. The default option for connecting to a platform is TCP/IP. Since we already have a connection to the target from Platform Builder, we can use the same transport from eMbedded Visual C++. If we were to build and download the application without configuring the connection, we would launch a second instance of the emulator, which is not ideal.

To configure the transport from eMbedded Visual C++, on the Tools menu, click Configure Platform Manager. Then locate and expand the IEVIEWER platform, and select the IEVIEWER Emulator. You can then click Properties to display the device properties dialog. Change the Transport to KITL Transport for Windows CE, and the Startup Server to CESH Server for Windows CE. Click OK twice to accept the changes.

eMbedded Visual C++ can work with a number of SDKs. In our case we want to use the IEVIEWER SDK. Use the build toolbar to set the platform to IEVIEWER, and the target to IEVIEWER Emulator.

Click here for larger image.

Figure 1. eMbedded Visual C++ build toolbar

Now build and test your application. On the Build menu, click Build IEViewer.exe. This will build and download the application, and also download the MFC debug runtime DLLs (mfcce400d.dll, and olece400d.dll). Note that the MFC runtime DLLs exist as a component in the Platform Builder catalog, so you can add MFC support to a platform at build time. This is, of course, the release version of the DLLs (mfcce400.dll, and olece400.dll). To close the application, on the File menu, click Exit. Now to add some code...

The MFC Doc/View boilerplate code has created a number of classes for us. These are: CAboutDlg, CIEViewerApp, CIEViewerDoc, CIEViewerView, and CMainFrame. For the purposes of this article, we will only modify the view. Expand the IEViewer classes in eMbedded Visual C++. We will want to add a couple of member variables to the View class. This is simple: Right-click on the CIEViewerView and select Add Member Variable . This will display a dialog that prompts you for a variable type and a variable name.

Figure 2. Adding the IWebBrowser2 member variable

We will use the pointer to the IWebBrowser2 interface to communicate with the Internet Explorer ActiveX control. We also need a second member variable to contain the controls window.

Again, right-click the CIEViewerView class and add the following member variable:

Variable Type: CWnd
Variable Name: m_wndBrowser

If we were to build the application at this point, we would get a number of errors. This is due to IWebBrowser2 not being defined in the application. We need to include some additional header files to fix these errors.

Open stdafx.h for your application by clicking on the file view tab of the workspace window, expanding the IEViewer and then the Header files node. Double-click StdAfx.h.

Below the line

#include <afxsock.h>      // MFC socket extensions

Add the following code:

#undef __urlmon_h__
#include "urlmon.h"

#undef _WINNETWK_
#include <winnetwk.h>

#undef _SHLOBJ_H_
#include <shlobj.h>

#undef __AFXHTML_H__
#include "afxhtml.h"

You can now build the application without any errors, though at this point, you've not added enough code to be able to create the Internet Explorer control. Since we're all good coding citizens, we should make sure we initialize variables, and clean up once we're done. Expand the CIEViewerView class (you may need to switch back to the Class view), and then double-click the class constructor and initialize the m_pBrowserApp variable by replacing the code

// TODO: add construction code here

With:

m_pBrowserApp = NULL;

Now double-click the destructor and add the following clean-up code:

if (m_pBrowserApp != NULL)
            m_pBrowserApp->Release();

We now need to create the window. For a Win32-based application, this would typically be handled by the WM_CREATE handler. This gives you the opportunity to create any child windows before the main application window becomes visible. Adding a handler for WM_CREATE in our MFC application would be straight forward enough; however, MFC provides a virtual function called Create, which is specifically set aside for creating any child windows. We can add the Create virtual function by right-clicking the CIEViewerView class, selecting Add Virtual Function, and selecting the Create function. Click Add and Edit to add the Create handler and edit the code.

Replace all the code in the function:

// TODO: Add your specialized code here and/or call the base class
      
return CFormView::Create(lpszClassName, lpszWindowName, dwStyle,
    rect, pParentWnd, nID, pContext);

With following code:

// create the view window itself
if (!CView::Create(lpszClassName, lpszWindowName,
                  dwStyle, rect, pParentWnd, nID, pContext))
      return FALSE;

// Setup window to contain ActiveX contorls
AfxEnableControlContainer();
      
RECT rectClient;
GetClientRect(&rectClient);

// create the control window
// AFX_IDW_PANE_FIRST is a safe but arbitrary ID
if (!m_wndBrowser.CreateControl(CLSID_WebBrowser, lpszWindowName,
                                WS_VISIBLE | WS_CHILD,
                                rectClient, this, 
                                AFX_IDW_PANE_FIRST))
{
      DestroyWindow();
      return FALSE;
}

// Get interface pointer
LPUNKNOWN lpUnk = m_wndBrowser.GetControlUnknown();
HRESULT hr = lpUnk->QueryInterface(IID_IWebBrowser2, 
                                   (void**) &m_pBrowserApp);
if (!SUCCEEDED(hr))
{
      m_pBrowserApp = NULL;
      m_wndBrowser.DestroyWindow();
      DestroyWindow();
      return FALSE;
}
return TRUE;

The code above creates a View class window that is used to host the ActiveX control. The function AfxEnableControlContainer is then called to enable the window to contain ActiveX controls. The control is created by calling the CreateControl method of m_wndBrowser. After the control is created, we get an IWebBrowser2 interface by calling m_wndBrowser.GetControlUnknown() and then querying for IID_IWebBrowser2. The application will use this interface to communicate with the Internet Explorer ActiveX control.

The final step is to point the control at some useful content, which you can do when the application gets started. Perhaps the OnInitialUpdate is a good place to do this. Let's add a function called Nav2Url, which we will call from OnInitialUpdate to navigate to a URL of our choosing.

Again, right-click the CIEViewerView class and add the following member function:

Function Type: void
Function Declaration: Nav2URL(LPCTSTR lpszURL)

Adding the member function will open the code editor at the appropriate place:

COleVariant empty;
CString strURL(lpszURL);
BSTR bstrURL = strURL.AllocSysString();

m_pBrowserApp->Navigate (bstrURL, COleVariant((long) 0, VT_I4),
                         empty, empty, empty);

The code above converts the C string lpszURL to a BSTR for use by the ActiveX control. The other parameters of the Navigate method aren't used, so they are filled in with zeros or empty strings.

So now you need to call the Nav2Url function from the Views OnInitialUpdate function. Right-click the CIEViewerView class and select add Virtual Function. Select OnInitialUpdate, and then click Add and Edit. Add the following line of code and you're done.

 Nav2URL (_T("\\Release\\test.htm"));

So, what's missing? Of course! We don't have a test.htm page to point the application at. We can create a test.htm file in eMbedded Visual C++. On the File menu, click New. On the Files tab select HTML page. Give the page a name of test.htm, and then click OK. This will generate a dummy html page that looks like this :

<HTML>
<HEAD>
<META NAME="GENERATOR" Content="Microsoft eMbedded Visual C++">
<META HTTP-EQUIV="Content-Type" content="text/html; charset=iso-8859-1">
<TITLE>Document Title</TITLE>
</HEAD>
<BODY>

<!-- Insert HTML here -->

</BODY>
</HTML>

Replace the <!-- Insert HTML here --> with Hello World or similar, and then save the file. Now comes the interesting bit: We can copy the file test.htm from our workspace folder to C:\wince410\public\IEViewer\RelDir\EMULATOR_X86Release, and the file is instantly available to our application running in the emulator.

The default maximum stack size for a Windows CE application is around 58K. Since the Internet Explorer ActiveX control can easily use more than this, the project settings must be modified so the application will have a larger maximum stack size.

  1. On the Project menu, click Settings.
  2. In the Settings For box, in the upper left corner, select All Configurations.
  3. Click the Link tab.
  4. In the Category box, select Output.
  5. In the Reserve field under Stack Allocations enter 0x40000.
  6. Click OK.

Now lets build and run the application.

And here's the end result: The Internet Explorer ActiveX control being hosted by an MFC eMbedded Visual C++ application. The control is displaying our custom HTML page.

Figure 3. The MFC application hosting the Internet Explorer control

Okay, so this wraps up how to use eMbedded Visual C++ to create an MFC-based application that hosts the Windows CE Internet Explorer control. There are a number of application development choices: native code using eMbedded Visual C++, C/C++ Win32, MFC, ATL, or making use of the .NET Compact Framework and managed code written in Microsoft® C# .NET and Microsoft® Visual Basic® .NET. Next month we will expand on the options available for creating Windows CE .NET applications.

 

Get Embedded

Mike Hall is a Product Manager in the Microsoft Embedded and Appliance Platform Group (EAPG). Mike has been working with Windows CE since 1996—in developer support, Embedded System Engineering, and the Embedded product group. When not at the office, Mike can be found with his family, working on Skunk projects, or riding a Honda ST1100.

Steve Maillet is the Founder and Senior Consultant for Entelechy Consulting. Steve has provided training and has developed Windows CE solutions for clients since 1997, when CE was first introduced. Steve is a frequent contributor to the Microsoft Windows CE development newsgroups. When he's not at his computer burning up the keys, Steve can be found jumping out of airplanes at the nearest drop zone.

Show:
© 2014 Microsoft