找不到集合中第一项的 C# Outlook 加载项用户属性

本文关键字:Outlook 加载项 属性 用户 一项 集合 找不到 | 更新日期: 2023-09-27 17:57:10

Outlook 2016
.Net Framework 4.5

我遇到了一个非常奇怪的行为:当我在一些非常特殊的未定义情况下(我不太了解)遍历联系人文件夹的 items 集合时,集合的第一项的某些用户属性无法加载。但是,用户属性是明确设置的。

方法如下:

I open the contact folder (to which the items will be moved) in outlook.
then i execute the "test"
the execution of the test can be suammrized as following:
click button ->
  start thread
  iterate through the items (on first iteration no items are present).
  add new items{    
    create item
    set userproperty PRE before item is initially saved
    save item
    move item to desired folder
    set userproperty POST after item is moved
    save item
  }
  end thread
click button ->
  start thread
  iterate through the items (here the userproperty POST sometimes fails to load on the first item of the collection, however when i investigate it, it IS there. It only fails for the first item and succeeds for every other following item).
...END

在我看来,Outlook 不知何故无法及时更新用户属性定义。但请注意,在使用第二个后台工作线程循环访问项目时,第一个 BackgroundWorker 线程已经完成。该问题可能与以下事实有关:在添加和迭代项目时,我在资源管理器中查看文件夹。此错误很难重现,并且很少发生。但是,我真的缺乏对Outlook内部运作的洞察力,所以我只能推测。

解决方法的想法:我可以在移动之前添加一个具有所有用户属性的项目。这里的问题是,在某些情况下,在最初保存项目并将其移动到文件夹后,我需要添加新的用户属性。在少数情况下,UserProperty 键是动态创建的(使用模式),因此预定义所有用户属性并不是最佳选择。可靠地加载用户属性非常重要,因为一些重要功能基于它们。

有没有人知道问题是如何引起的以及如何解决它? 因为这种行为让我发疯。

一些代码(不是原版,但应该包含所有相关方面)

//Ribbon
    TestNS.TestCaller testCaller;
    string folderID = "00000000BDB409934ED327439481EB6E1E1CC4D3010055B62301B58E32478DCD8C0D3FA6304600002C4CA4400000";
    public void testButton0_Action(Office.IRibbonControl control)
    {
        if(testCaller == null){
            testCaller = new TestNS.TestCaller(ThisAddIn.Outlook,folderID);
        }
        testCaller.Run();
    }
//Ribbon end
using System.Runtime.InteropServices;
using Outlook = Microsoft.Office.Interop.Outlook;
using System.Diagnostics;
using System.Windows.Forms;
using System.ComponentModel;
namespace TestNS
{
    public class TestCaller{
        private Outlook.Application application;
        private BackgroundWorker worker = new BackgroundWorker();
        private Test test = null;
        private string folderId;
        private bool init = true;
        private bool busy = false;
        public TestCaller(Outlook.Application application, string folderId){
            this.application = application;
            this.folderId = folderId;
            worker.DoWork += new DoWorkEventHandler(DoWork);
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(OnCompleted);
        }
        public void Run()
        {
            if (!busy)
            {
                busy = true;
                test = new Test(application, folderId, init);
                worker.RunWorkerAsync();
            }
        }
        private void DoWork(object sender, DoWorkEventArgs e)
        {
            test.Process();
            test = null;
        }
        private void OnCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            busy = false;
            init = false;
        }
    }
    class Test
    {
        public const string key_preCreateProperty ="preCreate";
        public const string key_postCreateProperty = "postCreate";
        private Outlook.Application application;
        private string folderId;
        private bool createData;
        public Test(Outlook.Application application,string folderId,bool createData)
        {
            this.application = application;
            this.folderId = folderId;
            this.createData = createData;
        }
        public void Process(){
            Examine();
            if(createData){
                CreateData();
            }
        }
        public void CreateData()
        {
            List<Poco> pocos = new List<Poco>();
            for (int i = 0; i < 10; i++)
            {
                pocos.Add(
                    new Poco
                    {
                        Pre = "Pre" + i,
                        Post = "Post" + i
                    }
                );
            }
            CreateContactItems(folderId,pocos);
        }
        public void Examine()
        {
            bool preIsLoaded = false;
            bool postIsLoaded = false;
            Debug.WriteLine(">>>Examine");
            Outlook.MAPIFolder folder = application.Session.GetFolderFromID(folderId);
            Outlook.Items folderItems = folder.Items;
            int i = 0;
            //print UserProperties registered to the items
            foreach(Outlook.ContactItem contactItem in folderItems){
                var itemUserProperties = contactItem.UserProperties;
                string itemUserPropertiesString = "";
                foreach (var itemProp in itemUserProperties)
                {
                    Outlook.UserProperty prop = (Outlook.UserProperty)itemProp;
                    itemUserPropertiesString += " " +prop.Name + " " + prop.Value + " 'n";
                }
                //HERE: sometimes it prints only Pre on the first index of the iteration
                Debug.WriteLine(string.Format("i={0} , itemUserProperties Count={1} , following UserProperties: 'n{2}", i++, itemUserProperties.Count, itemUserPropertiesString));
                string pre = null;
                string post = null;
                try
                {
                    pre = contactItem.GetUserProperty(key_preCreateProperty);
                    preIsLoaded = true;
                }
                catch(KeyNotFoundException ex){
                    Debug.WriteLine("Error: Pre Not found"); //should not happen - doesn't happen
                }
                try
                {
                    post = contactItem.GetUserProperty(key_postCreateProperty);
                    postIsLoaded = true;
                }
                catch (KeyNotFoundException ex)
                {
                    Debug.WriteLine("Error: Post Not found"); //shoul not happen - happens rarely totally indeterminitic
                }
                Marshal.ReleaseComObject(itemUserProperties);
            }
            Debug.WriteLine("<<<Examine");
            if (folderItems.Count > 0 && (!preIsLoaded || !postIsLoaded))
            {
                MessageBox.Show("preIsLoaded="+preIsLoaded +" 'n" +"postIsLoaded="+postIsLoaded);
            }
            Marshal.ReleaseComObject(folderItems);
            Marshal.ReleaseComObject(folder);
        }
        public void CreateContactItems(string folderId,List<Poco> pocos)
        {
            Outlook.MAPIFolder folder = application.Session.GetFolderFromID(folderId);
            foreach(Poco poco in pocos){
                CreateContactItem(folder,poco);
            }
            Marshal.ReleaseComObject(folder);
        }
        public void CreateContactItem(Outlook.MAPIFolder testFolder,Poco data)
        {
            Outlook.ContactItem contactItem = application.CreateItem(Outlook.OlItemType.olContactItem);
            contactItem.SetUserProperty(key_preCreateProperty, data.Pre);
            contactItem.Save();
            Outlook.ContactItem movedContactItem = (Outlook.ContactItem)contactItem.Move(testFolder);
            Marshal.ReleaseComObject(contactItem);
            contactItem = movedContactItem;
            contactItem.FirstName = data.Pre;
            contactItem.LastName = data.Post;
            contactItem.SetUserProperty(key_postCreateProperty, data.Post);
            contactItem.Save();
            Marshal.ReleaseComObject(contactItem);
        }
    }
    public static class Util
    {
        public static void SetUserProperty(this Outlook.ContactItem item, string name, dynamic value)
        {
            Outlook.UserProperty property = item.UserProperties[name];
            if (property == null)
            {
                property = item.UserProperties.Add(name, Outlook.OlUserPropertyType.olText);
            }
            property.Value = value;
        }
        public static dynamic GetUserProperty(this Outlook.ContactItem item, string name)
        {
            Outlook.UserProperty property = item.UserProperties[name];
            if (property != null)
            {
                return property.Value;
            }
            throw new KeyNotFoundException(string.Format("UserProperty name={0} not found", name));
        }
    }
    public class Poco
    {
        public string Pre
        {
            get;
            set;
        }
        public string Post
        {
            get;
            set;
        }
    }
}

感谢您的任何回复

找不到集合中第一项的 C# Outlook 加载项用户属性

Outlook 对象模型不能在 COM 加载项中的辅助线程上使用。Outlook 2016 在检测到在辅助线程上访问的 OOM 对象时,将立即引发异常。