【问题标题】:Is Folder.PropertyAccessor safe to call from managed code?从托管代码调用 Folder.PropertyAccessor 是否安全?
【发布时间】:2015-04-22 04:07:33
【问题描述】:

我们最近完成了 VSTO Outlook 插件的开发。对于某些配置数据,它使用Folder 上的自定义olText 属性。

当我们的插件检测到这些属性不可用时,它会使用文件夹的 UserDefinedProperties 属性来Find/Add我们的自定义属性(如果它们不存在)。

if (folder.UserDefinedProperties.Find(propertyName) == null)
    folder.UserDefinedProperties.Add(propertyName, OlUserPropertyType.olText);

当我们的加载项运行时,我们会多次获取和设置这些属性。我们使用PropertyAccessor GetProperty 和 SetProperty 方法来做到这一点。同样,我们所有的属性都是 OlUserPropertyType.olText 类型。此外,我们总是在获取和设置属性时调度到 Outlook 的 UI 线程。

//set
string value = "blah";
folder.PropertyAccessor.SetProperty(GetSchemaName(propertyName), value);

// get
string value = folder.PropertyAccessor.GetProperty(GetSchemaName(propertyName)

GetSchemaName 返回 ("http://schemas.microsoft.com/mapi/string/" + assemblyGuid + "/" + propertyName)。

但是,我们在文件夹的 PropertyAccessor 上使用 GetProperty 和 SetProperty 会导致频繁的运行时 COMException。下面是调用 GetProperty 的示例异常。我们在 Outlook 2010 和 2013 中都发现了这个问题。

System.Runtime.InteropServices.COMException (0x80020005): Type mismatch.
(Exception from HRESULT: 0x80020005 (DISP_E_TYPEMISMATCH))
at Microsoft.Office.Interop.Outlook._PropertyAccessor.GetProperty(String SchemaName)

我的问题是:使用文件夹 PropertyAccessor 在 VSTO 中获取和设置属性是否存在已知问题?如果不是,为什么会这样?

【问题讨论】:

    标签: c# .net outlook vsto outlook-addin


    【解决方案1】:

    不,这不是已知问题。

    GetSchemaName(propertyName)

    传递给 Get/SetProperty 方法的实际值是多少?

    无论如何,我建议改用 StorageItem 类。以下是 MSDN 的声明:

    GetStorage 方法使用由 StorageIdentifier 指定的标识符获取文件夹对象上的 StorageItem,并具有由 StorageIdentifierType 指定的标识符类型。 StorageItem是Folder中的隐藏项,随账号漫游,线上线下均可使用。

    如果您使用 StorageIdentifierType 的 olIdentifyByEntryID 值指定 StorageItem 的 EntryID,则 GetStorage 方法将返回具有指定 EntryID 的 StorageItem。如果无法使用该 EntryID 找到 StorageItem,或者如果 StorageItem 不存在,则 GetStorage 方法将引发错误。

    如果您使用 StorageIdentifierType 的 olIdentifyByMessageClass 值指定 StorageItem 的消息类,则 GetStorage 方法将返回具有指定消息类的 StorageItem。如果有多个具有相同消息类的项目,则 GetStorage 方法返回具有最新 PR_LAST_MODIFICATION_TIME 的项目。如果不存在具有指定消息类的 StorageItem,则 GetStorage 方法使用由 StorageIdentifier 指定的消息类创建一个新的 StorageItem。

    如果您指定 StorageItem 的 Subject,则 GetStorage 方法将返回带有在 GetStorage 调用中指定的 Subject 的 StorageItem。如果有多个具有相同主题的项目,则 GetStorage 方法将返回具有最新 PR_LAST_MODIFICATION_TIME 的项目。如果指定 Subject 的 StorageItem 不存在,则 GetStorage 方法将使用 StorageIdentifier 指定的 Subject 创建一个新的 StorageItem。

    使用 Folder 类的 GetStorage 方法获取父文件夹上的 StorageItem 对象,以存储 Outlook 解决方案的数据。

    更多信息请参见Storing Data for Solutions

    【讨论】:

    • GetSchemaName 返回 ("schemas.microsoft.com/mapi/string" + assemblyGuid + "/" + propertyName)。
    • 改用 StorageItem。
    • 谢谢。我们重写以使用 StorageItem。
    【解决方案2】:

    您最终会在文件夹上设置命名的 MAPI 属性。请记住,虽然 PST 提供程序支持这一点,但 Exchange 提供程序不支持。您需要重新考虑将属性存储在文件夹本身上的需要,或者在文件夹中的隐藏(关联)消息上设置此类属性。这就是MAPIFolder.GetStorage 使用的方式,也是 Outlook 存储其自己的每个文件夹设置(例如视图)的方式。查看OutlookSpy 中的现有数据(Inbox 是一个不错的候选)(单击 IMAPIFolder,转到“Associated Contents”选项卡。

    【讨论】:

    • 我们永远不会使用 Exchange 文件夹来存储这些,但这很有帮助。你和 Eugene 都提到了 GetStore,听起来我们可能想改用它。
    • 除非您正在为非常特定的客户创建插件,否则我不知道您如何摆脱不支持 Exchange - 这是大多数大公司使用的。 Office 365 也是 Exchange。
    • 我们从我们的企业软件应用程序同步日历。我们不想同步到 Exchange 日历,因为这会导致 Exchange 和我们的软件中的约会重复。相反,当用户在 Exchange 上时,我们会创建一个新日历并与之同步。
    猜你喜欢
    • 2013-08-24
    • 1970-01-01
    • 2010-09-18
    • 1970-01-01
    • 1970-01-01
    • 2015-02-24
    • 1970-01-01
    • 2011-04-29
    • 2013-12-29
    相关资源
    最近更新 更多