You have mail - OEAPI and COM
Written by Mike James   
Monday, 14 September 2009
Article Index
You have mail - OEAPI and COM
Wrapping the Interface
YHM application

 

Wrapping the Interface

You could use the Interface as defined above as it stands but it is usual to use the facilities of C# to make it easier to use by “wrapping” it in a new class – OEFolder. The complication is the our original OE class, which was created to wrap the IStoreNamespace interface, contains a method OpenSpecialFolder which creates an OEFolder object. This makes it impossible to create an OEFolder constructor which creates the IStoreFolder interface that the class wraps.

The solution is to use a two-stage process.

First create an instance of the IStoreFolder interface and then use this in the OEFolder constructor to create an OEFolder object which “wraps” the interface:

public OEFolder OpenSpecialFolder(  
SPECIALFOLDER FolderID)
{
IStoreFolder ppFolder;
OEFolders.OpenSpecialFolder(
(int)FolderID, 0, out ppFolder);
OEFolder fold = new OEFolder(ppFolder);
return fold;
}

Notice that you do need to add error handling code to this because sometimes Outlook Express will be temporarily unable to open a folder with the result that it generates an exception.

The constructor is simply:

public class OEFolder
{
private IStoreFolder m_IFolder;

public OEFolder(IStoreFolder folder)
{
m_IFolder = folder;
}

The member variable m_IFolder is used by the rest of the class to access the IStoreFolder interface. Now we have a method of creating an OEFolder object representing any of the special Outlook Express folders.

The next task is to create methods that wrap the IStoreFolder Interface. The first is easy as it is more or less a repeat of the corresponding method in IStoreNamespace:

public FOLDERPROPS GetFolderProps()
{
_FOLDERPROPS FP = new _FOLDERPROPS();
FP.cbSize = Marshal.SizeOf(FP);
m_IFolder.GetFolderProps(0, out FP);
FOLDERPROPS fp = OE.transfer(FP);
return fp;
}

The FOLDERPROPS structure is a more “civilised” managed version of the structure returned by the Interface.

The next method that we need reads the properties of each message in the folder in turn. The raw Interface does this using two functions. The first, GetFirstMessage, returns the details of the first message and a “handle” to an enumerator. Subsequent messages are returned by GetNextMessage as long you pass it the handle to the enumerator.

There is no need to separate getting the first and subsequent message properties as we can construct a method that automatically knows if it is to get the first or next according to the value of the enumerator.

That is:

public MESSAGEPROPS GetNextMessage(
ref UInt32 ehandle)
{
_MESSAGEPROPS MP = new _MESSAGEPROPS();
Int32 result=0;

If the enumerator is zero then get the first message:

 if (ehandle == 0)
{
result = m_IFolder.GetFirstMessage(
0, 0, MESSAGEID_FIRST,
ref MP, out ehandle);
}

If the enumerator has a non-zero value then it’s the next message we require:

 else
{
result = m_IFolder.GetNextMessage(
ehandle, 0, ref MP);
}

We also need the constant:

private const UInt32
MESSAGEID_FIRST = 0xffffffff;

At this point we have the message properties stored in MP but it’s not in a very C# programmer friendly form. The solution is to transfer it to a managed struct MESSAGEPROPS complete with an enumeration for the message state:

public struct MESSAGEPROPS
{
public Int32 MessageId;
public Int32 Language;
public MsgState State;
public Int32 MessageSize;
public Int32 priority;
public DateTime Received;
public DateTime Sent;
public string Subject;
public string DisplayTo;
public string DisplayFrom;
public string NormalSubject;
public Int32 Flags;
};
public enum MsgState
{
MSG_DELETED = 0x0001,
MSG_UNREAD = 0x0002,
MSG_SUBMITTED = 0x0004,
MSG_UNSENT = 0x0008,
MSG_RECEIVED = 0x0010,
MSG_NEWSMSG = 0x0020,
MSG_NOSECUI = 0x0040,
MSG_VOICEMAIL = 0x0080,
MSG_REPLIED = 0x0100,
MSG_FORWARDED = 0x0200,
MSG_RCPTSENT = 0x0400,
MSG_FLAGGED = 0x0800
}

Some of the fields need no processing or are converted using a simple cast:

MESSAGEPROPS mp = new MESSAGEPROPS();
if (result == 0)
{
mp.MessageId = MP.dwMessageId;
mp.Language = MP.dwLanguage;
mp.State = (MsgState)MP.dwState;
mp.MessageSize = MP.cbMessage;
mp.priority = MP.priority;

The first fields that need some processing are the date and times which are represented as Filetime structures. These are best converted to DateTime objects:

 mp.Received = System.DateTime.
FromFileTime(
FileTimeToLong(MP.ftReceived));
mp.Sent = System.DateTime.FromFileTime(
FileTimeToLong(MP.ftSent));
mp.Subject = MP.pszSubject;
mp.DisplayTo = MP.pszDisplayTo;
mp.DisplayFrom = MP.pszDisplayFrom;
mp.NormalSubject = MP.pszNormalSubject;
mp.Flags = MP.dwFlags;
}

if the result was non-zero there are no more messages and so we can close the ennumeration:

else
{
m_IFolder.GetMessageClose(ehandle);
}

Finally we free the MessageProps structure:

 m_IFolder.FreeMessageProps(ref MP);
return mp;
}

All that remains is the utility to convert Filetime structures to 64-bit integers:

private long FileTimeToLong(
System.Runtime.InteropServices.
ComTypes.FILETIME ftime)
{
long h =
((long)ftime.dwHighDateTime) << 32;
long l = 0xFFFFFFFFL &
ftime.dwLowDateTime;
long t = l | h;
return t;
}

This is just an exercise in bit manipulation but it proved to be very tricky to get it right.

<ASIN:1590598849>

<ASIN:1932394818>

<ASIN:0735621632>



Last Updated ( Monday, 14 September 2009 )