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 (http://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.


 

Comments (12)

  1. John Cody says:

    Hi,

    I know this is a little off-topic, but I have been beating my head against the wall, and would really appreciate any help anyone can offer 🙂

    I designed a mod to eVB that allows it to create apps for both Smartphone 2002 and 2003 devices. Everything works great, eVB apps can use ActiveX components and even call API’s of either OS.

    The only remaing problem I have is trying to use the POOM functions (pimstore.dll) on the Smartphone. I can create the "Pocketoutlook.application" object, but when I try to invoke any method, even "pol.logon", I get a "Object doesn’t support this action ‘pol.logon’".

    I am not a COM expert, but from my limited understanding of COM, it seems that the pimstore.dll file in Smartphones doesn’t support the "IDispatch" interface, which I believe is what eVB needs in order to call the routines in POOM (something to do with late binding?).

    Again, not being a COM expert, my understanding is that a TypeLib for POOM might just be what eVB needs to properly use the pimstore.dll file. Thats why my hope [to fix this issue] was raised when I saw this article. However, not being much of an eVC developer, I did not know how to fully use the info in this post to fix my issue.

    I placed a copy of the pimtlb.dll file (typelib for POOM) that is included in the "eVB Runtimes for Pocket PC 2003" CAB file in the windows directory of my Smartphone, and I have added the typelib’s GUID "{4E130E40-7DBE-11D2-8F23-0000F87A4335}…" to the registry of the device, but all POOM calls still fail.

    The one thing that I am confused about is this…how is eVB suppose to know that there is a typelib on the device when the typelib GUID regkey values doesn’t reference the POOM GUID (0505…), and visa-versa? My last guess is that maybe there is some way to add the POOM typelib’s GUID to my eVB project file so that my eVB app then becomes aware of the typelib and uses it to make all the POOM calls…but this may just be my mis-understanding of COM interfaces.

    So, I was hoping that someone could shed some light on my issue and maybe confirm my assumtions, or even offer a solution that will allow eVB to call the functions in the pimstore.dll file in smartphone 2002 and 2003 devices.

    REWARD: Anyone who provides a solution to this problem will receive a FREE copy of ALL of my apps (http://www.omnisoft.com/products.asp), expecially my most popular one: John Cody’s SATALERT

    Thanks for any help!

    -John Cody

  2. stevenpr says:

    Hi John – I’ve never used eVB so I’m not sure how great my help will be, but I’m happy to try. It was my understanding that installing the eVB runtime on a device should take care of registering the POOM type lib for you. If that’s not the case, the C code in my post can help. Send me an email at stevenpr@microsoft.com and I’d be happy to build and send you an exe you can use to make sure the POOM type lib is registered properly on your Smartphone. In terms of your question about how eVB knows there’s a typelib – basically the discovery of the type lib happens down in COM, so eVB doesn’t need explicit knowledge. When you call a method through IDispatch, the component’s IDispatch implementation typically delegates to the typelib so all this should be "hidden" from eVB. By the way, have you tried using eVB on a PocketPC to call POOM? That might shed some light on the problem as well. Anyway, contact me and I’ll send you my registration program. In the meantime I’ll try to find someone around here that knows more about eVB.

    Thanks,

    Steven

  3. Hi Steven,

    your example provides high value for my work. Thanks! I have sucessfully created pimstore.tlb and pocketoutlook.dll. Afterwards, I created a UseVTable = 1 DWORD value in HKEY_LOCAL_MACHINESOFTWARE.NETCompactFramework. Also successful was the creation of a Appointment item and of some properties in my app:

    outlookApp.Logon(0);

    PocketOutlook.AppointmentItem appointment = (PocketOutlook.AppointmentItem)outlookApp.CreateItem((int) PocketOutlook.OlItemType.olAppointmentItem);

    //appointment.AllDayEvent = true; ->NotSupported

    //appointment.Start = new DateTime(2004, 9, 15, 15, 0, 0); ->NotSupported

    //appointment.End = new DateTime(2004, 9, 15, 16, 0, 0); ->NotSupported

    appointment.Subject = "Paul’s Birthsday";

    appointment.ReminderOptions = PocketOutlook.OlReminderOptions.olVibrate;

    appointment.ReminderMinutesBeforeStart = 60;

    appointment.ReminderSet = true;

    appointment.Location = "Room 53 542";

    appointment.Save();

    outlookApp.Logoff();

    But, on stetting the properties AllDayEvent, Start, and End, I got a NotSupported exception! What can be the reasion for that?

    Best Regards,

    Paul

  4. stevenpr says:

    Hi Paul – The reason you are getting the NotSupportedExceptions is that the AllDayEvent, Start and End properties require marshaling types that we haven’t implemented support for in Beta1. Specifically, we don’t support Date by value (which is an 8 byte float) or VARIANT_BOOL by value. We will support these in the next community drop or in the next Beta. If you need to work around this now, you’ll have to use IDispatch which involves registering the type library. If you decide to go that route feel free to send me an email (stevenpr@microsoft.com) and I’ll send you a program to run on your device which will register the POOM type lib.

    Thanks,

    Steven

  5. Jose says:

    Thanks for this useful post, can you please send me the project? The email address is jose_simon at hotmail dot com .

    regards,

    Jose

  6. Last summer I wrote a post about how to access the PocketOutlook Object Model (POOM) using the Beta1…