Delphi 使用EWS创建扩展属性并从Outlook加载项访问它

Delphi 使用EWS创建扩展属性并从Outlook加载项访问它,delphi,exchange-server,outlook-addin,extended-properties,user-defined-fields,Delphi,Exchange Server,Outlook Addin,Extended Properties,User Defined Fields,我目前正在开发EWS,以便将我们公司的应用程序与Exchange 2010进行一些集成。我正在使用EWS创建Exchange 2010的预约,它运行良好;但最近我尝试在创建约会时添加一些自定义/扩展属性,下面是我添加扩展属性的代码 Dim customField As New ExtendedPropertyDefinition(DefaultExtendedPropertySet.PublicStrings, "MyCustomField", MapiPropertyType.String)

我目前正在开发EWS,以便将我们公司的应用程序与Exchange 2010进行一些集成。我正在使用EWS创建Exchange 2010的预约,它运行良好;但最近我尝试在创建约会时添加一些自定义/扩展属性,下面是我添加扩展属性的代码

Dim customField As New ExtendedPropertyDefinition(DefaultExtendedPropertySet.PublicStrings, "MyCustomField", MapiPropertyType.String)

appointment.SetExtendedProperty(customField, "CustomFieldValue")
上述代码可以为约会创建自定义字段

现在我的问题来了。当我在Outlook中打开我创建的约会并转到“开发人员>设计此表单”,然后单击“所有字段”选项卡时,我只会看到我在“文件夹中的用户定义字段”中创建的自定义字段,而不会在“此项中的用户定义字段”中看到

当用户在Outlook中打开约会时,我还制作了一个Outlook加载项来响应我使用EWS创建的自定义字段,当我尝试查找自定义字段时,找不到自定义字段,因为自定义字段是在“文件夹中的用户定义字段”中创建的,而不是在“此项目中的用户定义字段”中创建的

这是Outlook加载项中的代码,将在用户在Outlook中打开apoint时执行。但由于自定义字段不在“in this item”中,因此.Find()不返回任何内容

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
我想要实现的是使用EWS创建带有自定义字段(扩展属性)的约会,然后在用户在Outlook中打开约会时读取Outlook加载项中的自定义字段(扩展属性)

编辑:

我使用EWS分配给自定义字段的值显示在“文件夹中的用户定义字段”中。如何从Outlook加载项检索值?也许我可以检索该值并将自定义字段添加到项中,然后使用该值

谢谢。

答案如下:

无法访问EWS使用UserProperties创建的扩展属性。但可以使用PropertyAccessor访问

outlookItem.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/string/{00020329-0000-0000-C000-000000000046}/yourProp")

我将此作为另一个答案发布,其中显示了一些实际的(Delphi)代码,因为第一个答案中缺少了这些代码。
AAppointmentItem是一个变体

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;
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;            
注意许多try例外,因为我们正在进行后期绑定;'早一点就好了 ()

此外,我们正在检索多个用户属性,因此GetProperties()实际上更好

FWIW,这是使用UserProperties的旧代码(lProperty是OLEVariant)

lProperty:=AAppointmentItem.UserProperties.Find(PROPERTY\u TIMETELLID);
如果IDispatch(lProperty)为零,则
lEvent.custsynctId:=lProperty.Value;
lProperty:=AAppointmentItem.UserProperties.Find(属性\u TIMETELLSYNCTIME);
如果IDispatch(lProperty)为零,则
lEvent.CustSyncDate:=lProperty.Value;
lProperty:=AAppointmentItem.UserProperties.Find(属性\u TIMETELLSYNCID);
如果IDispatch(lProperty)为零,则
lEvent.CustSyncEntryID:=lProperty.Value;
[编辑后添加2013-6-10]

下面是使用GetProperties()同时处理所有三个属性的代码:

lPropertyAccessor:=aappointItem.PropertyAccessor;
lSchemas:=VarArrayOf([cPublicStringNameSpace+PROPERTY_TIMETELLID,
CPPublicStringNamespace+属性_TIMETELLSYNCTIME,
cPublicStringNameSpace+属性_TIMETELLSYNCID]);
尝试
左值:=lPropertyAccessor.GetProperties(lSchemas);
如果VarType(左值[0])varError那么
lEvent.custsynctId:=左值[0];
如果VarType(左值[1])varError那么
开始
lDT:=左值[1];
lDT:=TTimeZone.Local.ToLocalTime(lDT);
lEvent.CustSyncDate:=lDT;
结束;
如果VarType(左值[2])varError那么
lEvent.CustSyncEntryID:=左值[2];
除了
结束;

请您解释一下这个答案是如何得出的?出于好奇,为什么您总是将自定义属性设置为字符串,并在阅读后将其转换为适当的格式(datetime和int)?当您设置属性时,使用正确的类型开始不是更容易吗?您是对的,这是不必要的。将左值更改为变量。
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;