Using POOM with .Net Compact Framework Whidbey Beta1

Note: Be sure to also read the update to this post. Working with POOM in the Compact Framework is even easier now that version 2 has shipped.

-----

One of the areas that I work on in the .Net Compact Framework group is native code interoperability. Now that Whidbey Beta1 has shipped, I’m anxious to start writing about all the great work we’re doing to make it much easier to integrate native code into your managed application in Whidbey.

One of the big new interoperability features in Whidbey is the ability to call Com components directly from managed code. This support makes it much easier to use the Pocket Outlook Object Model (POOM) in your managed application than it was with version 1.0 of the Compact Framework. Instead of having to write numerous PInvoke wrappers and having to define your own managed object model, you can generate an assembly using the Type Library Importer (tlbimp.exe) SDK tool that allows you to call POOM directly.

In this entry, I’ll describe the steps you’ll need to take to use POOM through the .Net Compact Framework’s COM Interoperability feature in Whidbey Beta1. Because Beta1 is a test release, and not a final product, you’ll need to take a few extra steps to use POOM in your managed application than you will by the time the product ships. Specifically, you must:

1. Create a POOM Type Library

2. Create an “Interop Assembly” using the Type Library Importer

3. Reference the Interop Assembly from your Visual Studio Project

4. Write your POOM application

5. Register the POOM Type Library on your Device if you’re calling POOM through IDispatch

Step 1: Build the POOM Type Library

The easiest way to call a COM component from managed code is to start with a type library that defines the component’s interfaces, coclasses and so on. Unfortunately, the type library for POOM is not included in either the PocketPC or Smartphone SDKs so you’ll have to build your own. Fortunately, building the type library is easy. You’ll need to install the PocketPC (or Smartphone) SDK to get the midl.exe tool that you’ll use to build the type library.

After you’ve installed the SDK, download the POOM idl file (pimstore.idl) from the Windows Mobile blog, copy it to the Include directory in the SDK and use midl.exe to create the type library:

C:\Program Files\Windows CE Tools\wce420\POCKET PC 2003\Include\Armv4>midl pimstore.idl

Running midl.exe on pimstore.idl will produce a type library named pimstore.tlb.

Step 2: Create an Interop Assembly from the Type Library

By the time the final version of Visual Studio is released, it’s likely you’ll be able to skip this step and reference pimstore.tlb directly from Visual Studio. In Beta1, however, you’ll need to create an interop assembly yourself using the Type Library Importer (tlbimp.exe) from the .Net Framework SDK.

Running tlbimp.exe on pimstore.tlb will produce an assembly called PocketOutlook which contains a managed code object model you can use to access POOM directly from your .Net Compact Framework application:

C:\Program Files\Windows CE Tools\wce420\POCKET PC 2003\Include\Armv4>tlbimp pimstore.tlb

Step 3: Reference the Interop Assembly from your Visual Studio Project

Now that you’ve created an interop assembly, you can reference it from your Visual Studio project and use it just as any other .Net assembly. To reference the interop assembly, right click on the “References” node for your project in the Solution Explorer and select “Add Reference…”. Choose the “Browse tab” in the “Add Reference” dialog and select the PocketOutlook.dll file you created in Step 2.

Step 4: Write your POOM application

Referencing the PocketOutlook interop assembly gives you a namespace of types you can use to access POOM. For example, the following code snippet initializes Pocket Outlook and retrieves the list of contacts:

using PocketOutlook;

   // ....

   // Create an instance of the application object and log on

   ApplicationClass outlookApp =

         new PocketOutlook.ApplicationClass();

   outlookApp.Logon(0);

   // Get the “Contacts” folder

   Folder contactsFolder =

      outlookApp.GetDefaultFolder(OlDefaultFolders.olFolderContacts);

           

   // Loop through the contacts

   PocketOutlook.Items contacts = contactsFolder.Items;

   for (int i = 0; i < contacts.Count; i++)

   {

  // Get an item representing a contact.

      ContactItem contact = (ContactItem) contacts.Item(i + 1);

      // The ContactItem object has properties for accessing the

      // contact’s name, phone number and so on…..

   }

   // Logoff

   outlookApp.Logoff();

Step 5: Register the POOM Type Library on your Device

The interfaces in the POOM type library are marked as dual meaning they can be called either late-bound through IDispatch or early-bound through the interface derived directly from IUnknown. In Beta1 of the .Net Compact Framework, dual interfaces are called through IDispatch by default. The primary reason for this default is that the support for calling through IDispatch is more fully functional in the Beta than the support for calling through interfaces derived directly from IUnknown. Specifically, calling through IDispatch supports the marshaling of more types, including the ability to pass floating point numbers which is needed in several places in POOM to marshal the OLE DATE type.

There are various ways to register the POOM type library on your device – you can manually enter the required keys using a .reg file, you can embed the type library in a .dll that can be registered using regsvrce.exe , or you can build a small executable using C++ that calls the COM APIs required to registry the type library. A colleague of mine (https://blogs.msdn.com/jehance) wrote an executable that does just that. I’ve taken his code and removed some specifics about our internal build environment to make it more generally usable. Here it is:

#include "stdafx.h"

#include <windows.h>

#include <commctrl.h>

int wmain(int argc, wchar_t* argv[])

{

    GUID LIBID_PIMSTORE;

    LIBID_PIMSTORE.Data1 = 0x4E130E40L;

    LIBID_PIMSTORE.Data2 = 0x7DBE;

    LIBID_PIMSTORE.Data3 = 0x11D2;

    LIBID_PIMSTORE.Data4[0] = 0x8F;

    LIBID_PIMSTORE.Data4[1] = 0x23;

    LIBID_PIMSTORE.Data4[2] = 0x00;

    LIBID_PIMSTORE.Data4[3] = 0x00;

    LIBID_PIMSTORE.Data4[4] = 0xF8;

    LIBID_PIMSTORE.Data4[5] = 0x7A;

    LIBID_PIMSTORE.Data4[6] = 0x43;

    LIBID_PIMSTORE.Data4[7] = 0x35;

    ITypeLib *pTypelib = NULL;

    HRESULT hr = LoadRegTypeLib(LIBID_PIMSTORE, 1, 0, 0x00, &pTypelib);

    if (SUCCEEDED(hr))

    {

        // The POOM type library is already installed. Exit..

        MessageBox(NULL,

                   L"The POOM type library is already installed",

                   L"POOMTypeLib",

                   MB_OK);

    }

    else

    {

        wchar_t filename[MAX_PATH + 1];

        if(GetModuleFileName(NULL, filename, MAX_PATH) > 0)

        {

            hr = LoadTypeLib(filename, &pTypelib);

            if(SUCCEEDED(hr))

            {

                hr = RegisterTypeLib(pTypelib, filename, NULL);

   

                if(SUCCEEDED(hr))

                {

                    MessageBox(NULL,

                               L"POOM Type Library Successfully Registered",

                               L"POOMTypeLib",

                               MB_OK);

                }

                else

                {

                    MessageBox(NULL,

                               L"Failed to Register POOM Type Library",

                               L"POOMTypeLib",

                               MB_OK);

                }

            }

            else

            {

                MessageBox(NULL,

                           L"Unable to Load POOM Type Library from Resource",

                           L"POOMTypeLib",

                           MB_OK);

            }

        }

        else

        {

            MessageBox(NULL,

                       L"Unable to Load POOM Type Library from Resource",

                       L"POOMTypeLib",

                       MB_OK);

        }

    }

   return 0;

}

This sample code assumes that the POOM type library is embedded as a resource within the executable. If you find this approach useful, I’d be happy to send you a full Visual Studio project you can use to registry the POOM type library on your device. Post a comment to this blog if you’d like a copy of the full project.

 

Note: If you’d like to call POOM (or any other dual interface) directly through the IUnknown-derived interface, you can do so by setting a registry value on your device that overrides the Compact Framework’s default behavior of calling through IDispatch. The value to set is a DWORD value called UseVTable under

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETCompactFramework.

Setting UseVTable to 1 will cause the dual interface to be called directly rather than through IDispatch. Note that calling through IUnknown is actually more straightforward because you don’t have to register the POOM type library on your device.

 

Thanks,

Steven

Disclaimers:
This posting is provided "AS IS" with no warranties, and confers no rights.
Some of the information contained within this post may be in relation to beta software. Any and all details are subject to change.