2017-07-29 27 views
1

在VSTO添加用於Outlook單擊按鈕火災2種方法:第一種執行上MailItem Object簡單的操作和運行快,第二個執行需要更多的計算時間等多項任務。我希望第二個在「後臺」運行,以便MailItem Object上的操作能夠快速響應。現在我無法弄清楚如何做到這一點,只有在完成2種方法後,MailItem Object上的操作才能在Outlook中看到。C#VSTO附加任務序列

public void ButtonAction(Office.IRibbonControl control) 
{ 
    bool processed = ActionsOnMailItem(); 
    string output = OtherTasks(processed); 
} 

public static bool ActionsOnMailItem() 
{ 
    Outlook.Selection selected = olApplication.ActiveExplorer().Selection; 
    bool isEmailProcessed = false; 
    try 
    { 
     foreach (Outlook.MailItem mailItem in selected) 
     { 
      mailItem.SaveAs(saveItemPath, Outlook.OlSaveAsType.olMSG); 
     } 
     isEmailProcessed = true; 
    } 
    catch (Exception ex) 
    { 
     Debug.WriteLine(ex.Message); 
     isEmailProcessed = false; 
    } 
    return isEmailProcessed; 
} 

public static string OtherTasks(bool isEmailProcessed) 
{ 
    if (isEmailProcessed) 
    { 
     // Perform several tasks requiring computing time 
     ... 
    } 
} 

我已經與async方法,但都沒有成功(沒有僵局但是對於第一種方法沒有快速反應既不)嘗試。在深入研究之前,我想知道這是否是正確的道路,或者是否有更直接的方法來實現。

+1

嘗試從VSTO插件內的不同線程訪問COM對象可能不是一個好主意 – MickyD

回答

1

首先你必須要知道,從後臺線程訪問COM對象涉及編組其中,總之,需要時間的。 Further reading...

對於你的任務,你需要制定解決方案,它採用BackgroundWorker類。 BackgroundWorker有上MainThread工程兩個事件分別是:

  • ProgressChanged
  • RunWorkerCompleted

OtherTasks方法應使用其中一個處理來自後臺任務結果。

對於VSTO同樣重要的是使用的BackgroundWorker類 例如前使用WindowsFormsSynchronizationContext

// Forces BackgroundWorker to run ProgressChanged and RunWorkerCompleted events on VSTA_Main thread. It's important, 
// because this thread manages Word COM objects. 
System.Threading.SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext()); 

BackgroundWorker worker = new BackgroundWorker(); 
worker.WorkerReportsProgress = true; 

worker.DoWork += delegate(object sender, DoWorkEventArgs e) 
{ 
    // do stuff not using COM object 
    worker.ReportProgress(0); 
}; 
worker.ProgressChanged += delegate(object sender, ProgressChangedEventArgs e) 
{ 
    // do stuff on main thread (on COM objects) 
}; 
worker.RunWorkerCompleted += delegate(object sender, RunWorkerCompletedEventArgs e) 
{ 

}; 

worker.RunWorkerAsync(); 
+1

完全按照預期工作! –

3

如Outlook 2016,一個異常會盡快Outlook檢測上比其他線程訪問募集主要的Outlook線程。這僅適用於COM外接程序,因爲在外部應用程序(外部)應用程序中,所有調用都會被整理到主Outlook線程中,因此您的應用程序中的多線程成爲一個有爭議的問題。

您可以在輔助線程上使用Extended MAPI(C++或Delphi) - 讀取主線程上的Namespace.MAPIOBJECT屬性(它返回IMAPISession對象)並將其存儲在變量中。在輔助線程,調用MAPIInitialize從主線程中使用的IMAPISesion - 不像OOM對象,它可以從多個線程中使用。對於除C++或Delphi等語言,你可以使用Redemption及其RDO家庭的對象 - 這是一個包裝周圍擴展MAPI,可以在二級線程使用。輔助線程上創建RDOSession的一個實例,其MAPIOBJECT屬性設置爲從Namespace.MAPIOBJECT主線程上檢索到的值。

+0

我剛剛在Outlook 2016中使用過tinamou的解決方案(使用'BackgroundWorker'類),並且不會引發異常。也許我必須精確地說,在後臺調用的方法(在我的問題中爲'OtherTasks')不使用'Globals.ThisAddIn.Application'來訪問'MailItem對象',而是'win32com.client.Dispatch(「Outlook.Application」)。GetNamespace (「MAPI」)從一個「外部」應用程序調用(如你所說)。 –

+0

但是,這是從外部應用程序使用Python,而不是COM插件,對不對? –

+0

是的:COM插件調用直接訪問'MailItem對象'的第一個方法,第二個方法使用'win32com.client.Dispatch(「Outlook.Application」)運行可執行版本的Python腳本。GetNamespace(「 MAPI「)'來訪問'MailItem對象'。 –