Not only does this powerful class allow you to retrieve any of the standard MAPI properties, it also gives you access to any custom Named Properties using a convenient string notation.
This class does have one minor problem though: it doesn't offer any way to explicitly check for the existence of a property. So when one half of your applications marks certain emails with a certain named property, and the other half needs to read out that marker, you end up with code like this:
var mailItem: OleVariant; propertyName: String; marker: String; begin ... propertyName := 'http://schemas.microsoft.com/mapi/string/someGuid/my.secret.marker'; try marker := mailItem.propertyAccessor.getProperty( propertyName ); except // Apparently, the marker isn't set. marker := ''; end; end;
Ouch. Not so much fun when doing this in a loop over a few thousand email. And turning off Break on OleException in the IDE is not the best of ideas when you are doing office automation, either.
Moving from late to early binding (and you should, anyway) makes this problem blatantly apparent; here is the interface definition of PropertyAccessor (renamed IPropertyAccessor for compliance with Delphi naming standards):
IPropertyAccessor = interface(IDispatch) ['{0006302D-0000-0000-C000-000000000046}'] ... snip ... function GetProperty(const SchemaName: WideString): OleVariant; safecall; procedure SetProperty(const SchemaName: WideString; Value: OleVariant); safecall; ... snip ... end;
See those safecall markers? Those means that Delphi has wrapped the calls in a little check, raising an exception whenver the result is not ok. Which is nice and error proof, but brushes over the fact that there are several different results possible from the underlying call, and not all of them are crucial errors. In our case the returned result is MAPI_E_NOT_FOUND, which just tells us the mailItem at hand wasn't marked... not exactly an "exceptional" situation in this particular application.
The trick is that we can simply redefine this interface, using HResult stdcalls directly, as opposed to the magically wrapped safecalls. This conversion is easy enough to do by hand (everything needs to return a HResult, move all function results to out parameters). However, for even more convenience, we can use use tlibimp to do this. From a command line, execute:
(make sure to correct that path if office is installed elsewhere). This will output a nice Outlook_TLB where we can copy the property from. I aptly (although perhaps slightly confusing) named my copy ISafePropertyAccessor.
The trick is that we can simply redefine this interface, using HResult stdcalls directly, as opposed to the magically wrapped safecalls. This conversion is easy enough to do by hand (everything needs to return a HResult, move all function results to out parameters). However, for even more convenience, we can use use tlibimp to do this. From a command line, execute:
tlibimp -P -Ps- "C:\Program Files\Microsoft Office\Office14\MSOUTL.OLB"
(make sure to correct that path if office is installed elsewhere). This will output a nice Outlook_TLB where we can copy the property from. I aptly (although perhaps slightly confusing) named my copy ISafePropertyAccessor.
ISafePropertyAccessor = interface(IDispatch) ['{0006302D-0000-0000-C000-000000000046}'] ... snip ... function GetProperty(const SchemaName: WideString; out Value: OleVariant): HResult; stdcall; function SetProperty(const SchemaName: WideString; Value: OleVariant): HResult; stdcall; ... snip ... end;
Here is how we'd use it in the example above:
var mailItem: OleVariant; propertyName: String; propertyAccessor: ISafePropertyAccessor; value: OleVariant; marker: String; begin ... propertyName := 'http://schemas.microsoft.com/mapi/string/someGuid/my.secret.marker'; propertyAccessor := IUnknown(mailItem.propertyAccessor) as ISafePropertyAccessor; hr := mailItem.propertyAccessor.getProperty( propertyName, value ); if hr = S_OK then begin marker := value; end else marker := ''; ... end;Slightly more verbose, but that can always be wrapped away in some convenience functions... and it sure is nice to get rid of the exception!
No comments:
Post a Comment