How to Add Pocket Outlook Features to Your Mobile Application

Architectural Overview

The Pocket Outlook Object Model (POOM) contains a few interfaces that allow you to perform sophisticated management of contacts, tasks, and a calendar. For developers who need to implement such customized and collaborative solutions, POOM can make it quick and easy. Because POOM is supported over a wide range of mobile devices, your applications will be able to work correctly on these PDAs without too many problems. Besides, Pocket Outlook provides a capability to add new menu commands for third-party add-ins. This article will focus mainly on POOM possibilities rather than external application commands. Add-ins will be discussed in the next article. C# developers can also use POOM, but recently it is harder than in C++. If you need POOM in managed code, you can either create and call an unmanaged DLL with all the stuff inside or wrap all required APIs by using the DllImport attribute. Another suitable way is to create an interop assembly from the POOM type library and then reference it from you C# application. Unfortunately, I’ve failed to find any TLB for POOM on the Web… So, I’ll leave it for better times.

I will start by overviewing the available POOM objects and their hierarchy. Actually, the hierarchy tree is pretty simple:

  • Application
    • Tasks Folder
      • Task 1
      • Task 2
      • Task 3
      • Task 4
    • Contacts Folder
      • Contact 1
      • Contact 2
      • Contact 3
      • Contact 4
    • Calendar Folder
      • Appointment 1
      • Appointment 2
      • Appointment 3
      • Appointment 4
    • Infrared Folder
      • Item 1
      • Item 2
      • Item 3
      • Item 4

As you can see, an Application object is located on the top of hierarchy. This is literally the only object that should be created via a CoCreateInstancecall. All others are returned through this object.

An Application provides a set of Folder objects. Each Folder contains an Item collection of appropriate individual items; for example, Tasks, Contacts, or Appointments. Individual items have their own set of properties, which you can manage as needed. Except for this, there is a possibility to send and receive POOM items via IR programmatically. A special Infrared Folder keeps items marked for beaming.

Note: All things related to City List and Time Zone has beenremoved from POOM since Pocket PC 2002. All calls to such methods or properties will return an E_NOTIMPL error.

Before you turn to code samples, here’s a typical POOM session scenario:

  • Create an instance of a PocketOutlook.Application object
  • Call the Application.Logon method
  • Manipulate Folders and Items to perform all required operations
  • Call the Application.Logoff method
  • Release the Application object

Getting Started with POOM Objects

Now, you can begin your tour through POOM objects. As I said before, the very first task is to create an Application object and call its Logon method:

typedef CComQIPtr<IPOutlookApp,&__uuidof(IPOutlookApp)>
        IPOutlookAppPtr;
...
// define class member
IPOutlookAppPtr m_pPOOMApp;
...
// initialize it somewhere
HRESULT hr = 0;
CLSID clsid;
LPOLESTR pProgID = L"PocketOutlook.Application";
hr = CLSIDFromProgID(pProgID,&clsid);
hr = m_pPOOMApp.CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER);
if ( SUCCEEDED(hr) )
{
   // perform login
   if(SUCCEEDED(m_pPOOMApp->Logon(NULL)))
   {
      m_bLoggedIn = TRUE;
   }
}

The code snippet above shows how to create a POOM Application object. I prefer to deal with smart pointers here to get rid of referencing issues, but the same code can be easily rewritten in pure API. At this point, you are ready to get specific folders containing Tasks, Contacts, and Appointments:

typedef CComQIPtr<IFolder,&__uuidof(IFolder)> IFolderPtr;
typedef CComQIPtr<IPOutlookItemCollection,
                     &__uuidof(IPOutlookItemCollection)>
                     IPOutlookItemCollectionPtr;
typedef CComQIPtr<ITask,&__uuidof(ITask)> ITaskPtr;

BOOL CPOOMDlg::GetPOOMFolder(int nFolder, IFolderPtr& pFolder)
{
   if ( !m_bLoggedIn )
      return FALSE;

   if (SUCCEEDED(m_pPOOMApp->GetDefaultFolder(nFolder, &pFolder)))
   {
      return TRUE;
   }
   else
   {
      return FALSE;
   }
}
...
void CPOOMDlg::OnButtonEnumAll()
{
   IFolderPtr pFolder;
   if (GetPOOMFolder(olFolderTasks, pFolder))
   {
      IPOutlookItemCollectionPtr pItemCol;
      CComBSTR bstrText;

      if (SUCCEEDED(pFolder->get_Items(&pItemCol)))
      {
         int cItems = 0;
         hr = pItemCol->get_Count(&cItems);

         for (int i = 1; i <= cItems; i++)
         {
            ITaskPtr pTask;
            if ( SUCCEEDED(pItemCol->Item(i,(IDispatch**)&pTask)) )
            {
               hr = pTask->get_Subject(&bstrText);
               // process this task as required
               ...
            }
         }
      }
   }
   ...
}

So, all you should do is to obtain the required folder and then get the corresponding items collection. Regardless of the folder type (olFolderTasks, olFolderContacts, or olFolderCalendar), item enumeration is always started from index 1. To simplify further explanation, let me put in an excerpt from the pimstore.h header file declaring IFolder and IPOutlookItemCollection interfaces (detailed declarations of available interfaces and all other stuff you will find in the pimstore.h header):

IFolder : public IDispatch
{
public:
   HRESULT get_Items(IPOutlookItemCollection **ppolItems);
   HRESULT get_DefaultItemType(int *polItem);
   HRESULT get_Application(IPOutlookApp **polApp);
   HRESULT AddItemToInfraredFolder(int olItem, IDispatch *polItem);
   HRESULT SendToInfrared(void);
   HRESULT ReceiveFromInfrared(IPOutlookItemCollection **ppItems);
};

IPOutlookItemCollection : public IDispatch
{
public:
   HRESULT Add(IDispatch **ppolItem);
   HRESULT get_Count(int *pnCount);
   HRESULT Find(BSTR pwszRestriction, IDispatch **ppItem);
   HRESULT FindNext(IDispatch **ppItem);
   HRESULT Item(int iIndex, IDispatch **ppolItem);
   HRESULT Remove(int iIndex);
   HRESULT Restrict(BSTR pwszRestriction,
                    IPOutlookItemCollection **ppolItems);
   HRESULT Sort(BSTR pwszProperty, VARIANT_BOOL fDescending);
   HRESULT get_IncludeRecurrences(VARIANT_BOOL *pfIncludeRecurrences);
   HRESULT put_IncludeRecurrences(VARIANT_BOOL fIncludeRecurrences);
   HRESULT get__NewEnum(IUnknown **ppEnumerator);
   HRESULT get_Application(IPOutlookApp **polApp);
};

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read