I am currently working on EWS to have some integration of our company application with Exchange 2010. I am using EWS to create appoinment to Exchange 2010 and it works fine; but recently I tried to add some custom/extended property when creating the appointment, below is my code to add the extended property.
Dim customField As New ExtendedPropertyDefinition(DefaultExtendedPropertySet.PublicStrings, "MyCustomField", MapiPropertyType.String)
appointment.SetExtendedProperty(customField, "CustomFieldValue")
The above codes able to create the custom field to the appointment.
Now here is my problem. When I open up the appointment in Outlook that I created and go to "Developer > Design This Form", then "All Fields" tab, I only see the custom field I created in the "User-defined field in folder" but not in "User-defined field in this item".
I also making an Outlook Add-in to react to the custom field that I created using the EWS when user opens up the appointment in Outlook, when I tried to look for the custom field, couldn't find the custom field, because the custom field is created in "User-defined field in folder" but not in "User-defined field in this item".
This is the codes in the Outlook Add-in and will execute when user opens an apointment in Outlook. But because the custom field is not in "in this item", the .Find() returns Nothing.
Dim appt As Outlook.AppointmentItem
appt = TryCast(inspector.CurrentItem, Outlook.AppointmentItem)
If appt.UserProperties.Find("MyCustomField") Is Nothing Then
'Some action
Else
'Some action
End If
What I want to achieve is to create an appointment with the custom field (extended property) using EWS, and then read the custom field (extended property) in Outlook Add-in when user open the appointment in Outlook.
EDIT:
The value that I assigned to the custom field using EWS is shown in the "User-defined field in folder". How do I retrieve the value from my Outlook Add-in? Maybe I can retrieve the value and add the custom field to the item and with the value?
Thanks.
The answer is here:
http://social.technet.microsoft.com/Forums/en-US/exchangesvrdevelopment/thread/2a98b4ab-0fbc-4863-8303-48711a18a050
Can't access the extended property created by EWS using UserProperties. But can access using PropertyAccessor.
outlookItem.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/string/{00020329-0000-0000-C000-000000000046}/yourProp")
I'm posting this as another answer showing some actual (Delphi) code, because that was missing from the first answer.
AAppointmentItem is an OLEVariant
const
GUID_PS_PUBLIC_STRINGS = '{00020329-0000-0000-C000-000000000046}';
cPublicStringNameSpace = 'http://schemas.microsoft.com/mapi/string/' + GUID_PS_PUBLIC_STRINGS + '/';
var
lPropertyAccessor: OleVariant;
lSchemaName, lValue: String;
begin
// Use the PropertyAccessor because Outlook UserProperties() can't access the extended properties created by EWS
// Use the 'string subnamespace of the MAPI namespace' (http://msdn.microsoft.com/en-us/library/office/ff868915.aspx)
// with the PS_PUBLIC_STRINGS GUID from http://msdn.microsoft.com/en-us/library/bb905283%28v=office.12%29.aspx
lPropertyAccessor := AAppointmentItem.PropertyAccessor;
lSchemaName := cPublicStringNameSpace + PROPERTY_TIMETELLID; // Name constants defined elsewhere
try
lSchemaName := cPublicStringNameSpace + PROPERTY_TIMETELLID;
lValue := lPropertyAccessor.GetProperty(lSchemaName);
lEvent.CustSyncTTID := StrToInt(lValue);
except
end;
try
lSchemaName := cPublicStringNameSpace + PROPERTY_TIMETELLSYNCTIME;
lValue := lPropertyAccessor.GetProperty(lSchemaName);
lEvent.CustSyncDate := UTCString2LocalDateTime(lValue);
except
end;
try
lSchemaName := cPublicStringNameSpace + PROPERTY_TIMETELLSYNCID;
lValue := lPropertyAccessor.GetProperty(lSchemaName);
lEvent.CustSyncEntryID := lValue;
except
end;
Note the many try excepts because we are doing late binding; 'early' would've been better
(http://blog.depauptits.nl/2012/04/safely-accessing-named-properties-in.html)
Also, We are retrieving multiple user properties, so GetProperties() is actually better.
FWIW, this was the old code using UserProperties (lProperty is OLEVariant)
lProperty := AAppointmentItem.UserProperties.Find(PROPERTY_TIMETELLID);
if IDispatch(lProperty) <> nil then
lEvent.CustSyncTTID := lProperty.Value;
lProperty := AAppointmentItem.UserProperties.Find(PROPERTY_TIMETELLSYNCTIME);
if IDispatch(lProperty) <> nil then
lEvent.CustSyncDate := lProperty.Value;
lProperty := AAppointmentItem.UserProperties.Find(PROPERTY_TIMETELLSYNCID);
if IDispatch(lProperty) <> nil then
lEvent.CustSyncEntryID := lProperty.Value;
[Edited to add 2013-6-10]
And here is the code modified to handle all three properties at once using GetProperties (as MS recommends):
lPropertyAccessor := AAppointmentItem.PropertyAccessor;
lSchemas := VarArrayOf([cPublicStringNameSpace + PROPERTY_TIMETELLID,
cPublicStringNameSpace + PROPERTY_TIMETELLSYNCTIME,
cPublicStringNameSpace + PROPERTY_TIMETELLSYNCID]);
try
lValues := lPropertyAccessor.GetProperties(lSchemas);
if VarType(lValues[0]) <> varError then
lEvent.CustSyncTTID := lValues[0];
if VarType(lValues[1]) <> varError then
begin
lDT := lValues[1];
lDT := TTimeZone.Local.ToLocalTime(lDT);
lEvent.CustSyncDate := lDT;
end;
if VarType(lValues[2]) <> varError then
lEvent.CustSyncEntryID := lValues[2];
except
end;