I organize my work (and a fair bit of my life) with the Outlook task list. In Outlook I have a customized view that shows all tasks due today, grouped by priority. This feature does not exist on the Pocket PC so I implemented a simple task manager with embedded VB which I used a lot on my old iPAQ. I didn't want to install the VB runtime on my new iPAQ 4150 so I decided to rewrite it in .NET CF.
I didn't get far before I hit the first hurdle though: accessing Pocket Outlook with .NET CF.
The problem is that Pocket Outlook is only available via the IPOutlookApp COM interface and .NET CF does not support calling COM components. The latest news I have from Microsoft is that this will be fixed in the next version. I quickly found the commercial PocketOutlook In The Hand component from InTheHand for accessing POOM. Both The Windows Mobile Team Blog and Omar Shahine refer to the InTheHand component as the way to go. But, in the end, I decided to continue on my DIY quest for several reasons;
- I wanted to learn how to access COM components from .NET CF
- I didn't feel like paying $40 for a component I will only use on a personal project
The only way to call a COM component with .NET CF is to write a standard DLL that wraps the COM methods. A lot of work, as POOM has a lot of objects, methods and properties. The great news is that you can find all the free tools and source code you need on the Microsoft web site(s):
The POOM C++ wrapper support all the objects (at least the ones I have checked). It also comes with a .NET CF client that shows how to access the Pocket Outlook contacts. The .NET CF client is fairly limited as it only imports some of the C++ managed DLL methods. It is very simple to extend as you only have to add new DllImport's. I added the methods (get and set) for accessing the DueDate and it compiled like a charm but bombed on the Pocket PC when I tried to set the DueDate. I found the problem after having a closer look at the C++ code. The (put) DueDate method signature was:
HRESULT ITask_put_DueDate(ITask* thisPtr,
DATE st)
{
return thisPtr->put_DueDate(st);
}
The problem is the st argument. It passes an OLE Automation DATE which is 8 bytes. .NET CF doesn't support arguments larger than 4 bytes (32 bit) so the source code has to be changed to pass a pointer (4 bytes) to a date:
HRESULT ITask_put_DueDate(ITask* thisPtr,
DATE* st)
{
return thisPtr->put_DueDate(*st);
}
The C# code has to be fixed as well. The correct DllImports are:
[ DllImport("PocketOutlook.dll", EntryPoint="ITask_get_DueDate") ]
private static extern int do_get_DueDate(IntPtr self,
ref double dueDate);
[ DllImport("PocketOutlook.dll", EntryPoint="ITask_put_DueDate") ]
private static extern int do_put_DueDate(IntPtr self,
ref double dueDate);
Almost there, one more thing do do: add a C# property wrapper for the DllImports
public System.DateTime DueDate
{
get
{
double doubleDate = 0.0;
PocketOutlook.CheckHRESULT(do_get_DueDate(this.RawItemPtr, ref doubleDate));
return PocketOutlook.OleDateToDateTime(doubleDate);
}
set
{
double doubleDate = PocketOutlook.DateTimeToOleDate(value);
PocketOutlook.CheckHRESULT(do_put_DueDate(this.RawItemPtr, ref doubleDate));
}
}
The code uses the .NET 1.0 CF Date conversion source code I posted earlier to convert the DATE arguments to System.DateTime
Fix the bugs in the Microsoft code you have a free .NET CF POOM client. Cool Or What?
Feel free to drop a few cents in the
tip jar if this post saved you time and money