VSTO C#MailItem.Attachments.Add()崩溃

问题描述:

我有下面的代码VSTO C#MailItem.Attachments.Add()崩溃

public void SendAttachmentsClick() 
{ 
    Microsoft.Office.Interop.Outlook.MailItem oMailItem = HostAddIn.Application.CreateItem(Microsoft.Office.Interop.Outlook.OlItemType.olMailItem); 
    oMailItem.BodyFormat = Microsoft.Office.Interop.Outlook.OlBodyFormat.olFormatHTML; 

    // //returns strings representing paths to documents I want to attach 
    List<string> paths = GetAttachmentsPaths(); 
    if (paths.Count > 0) 
    { 
     foreach (string itemPath in paths) 
     { 
      oMailItem.Attachments.Add(itemPath); 
     } 

     if (oMailItem.Attachments.Count > 0) 
     { 
      oMailItem.Display(false); 
     } 
    } 
} 

CALL 1:调用SendAttachmentsClick()为第1时间打开了新的电子邮件,并适当重视所有附件它。

CALL 2:如果我在这个新的电子邮件消息中单击取消,然后再次调用SendAttachmentsClick(),我可以跟踪执行,直到调用上述oMailItemAttachments.Add(itemPath)(我在这个代码断点)。但是,一旦第二次调用中的第一个附件被调用时,整个VSTO/Outlook就会崩溃。我添加了try ... catch来试图捕获异常,但是它永远不会被输入,所以我不知道错误是什么。

UPDATE1:https://www.add-in-express.com/creating-addins-blog/2011/08/10/how-to-add-attachment-to-e-mail-message/?thank=you&t=1467071796#comment-413803读尤金Astafiev的文章之后,我修改了上面的代码释放COM对象,现在它看起来是这样,但问题仍然存在

public void SendAttachmentsClick() 
{ 
    Microsoft.Office.Interop.Outlook.MailItem oMailItem = HostAddIn.Application.CreateItem(Microsoft.Office.Interop.Outlook.OlItemType.olMailItem); 
    oMailItem.BodyFormat = Microsoft.Office.Interop.Outlook.OlBodyFormat.olFormatHTML; 
    Selection olSelection = HostAddIn.ActiveExplorer.Selection; 

    // //returns strings representing paths to documents I want to attach 
    List<string> paths = GetAttachmentsPaths(); 
    if (paths.Count > 0) 
    { 
     try 
     { 
      Microsoft.Office.Interop.Outlook.Attachments mailAttachments = oMailItem.Attachments; 
      foreach (string itemPath in paths) 
      { 
       Microsoft.Office.Interop.Outlook.Attachment newAttachment = mailAttachments.Add(itemPath); 
       oMailItem.Save(); 
       if (newAttachment != null) Marshal.ReleaseComObject(newAttachment); 
      } 

      if (oMailItem.Attachments.Count > 0) 
      { 
       oMailItem.Display(false); 
      } 

      if (mailAttachments != null) 
       Marshal.ReleaseComObject(mailAttachments); 
      if (oMailItem.Attachments != null) 
       Marshal.ReleaseComObject(oMailItem.Attachments); 


     } 
     catch (Exception ex) 
     { 
      MessageBox.Show(ex.Message); 
     } 
     finally 
     { 
      if (oMailItem != null) 
      { 
       Marshal.ReleaseComObject(oMailItem); 
       oMailItem = null; 
      } 
      Marshal.ReleaseComObject(olSelection); 
     } 
    } 
} 
+1

我想知道你的GetAttachmentsPaths()是如何获取路径的。这些文件是否存在于您的本地计算机上,或者您正在从某处下载它们?如果您从某处下载它们,是否可能是您的取消逻辑删除了下载内容? – cd491415

+0

我相信你是对的。你有什么建议?非常感谢 – pixel

+1

我会将下载的文件移动到另一个临时目录,从那里处理它们,然后删除临时目录。我在下面发布了部分解 – cd491415

按照建议,我会这样做。您不必像上面那样保存邮件。请注意,我没有为您提供GetAttachmentsPaths方法的逻辑,因为我不知道您是如何做到这一点的,但是在我看来,您是先从某处下载文件并确认了这一点。然而,我提供了很好的指导,说明如何编写此方法并返回下载文件的路径。希望有所帮助。

public async void SendAttachmentByMailClick() 
{ 
    // delete temp directory if it exists, then create brand new one each time 
    var tempFolder = Path.Combine(Path.GetTempPath(), "MyTempFolder"); 
    if (Directory.Exists(tempFolder)) 
    { 
     Directory.Delete(tempFolder, true); 
    } 
    Directory.CreateDirectory(tempFolder); 

    // get your list asynchronously 
    List<string> paths = null; 
    try 
    { 
     // I am doing this asynchronously but awaiting until I get files. I 
     // would use a TaskCompletionSource (google for it) and once you 
     // receive each file, store it's path in a List<string> object. 
     // Check that the List<string> Count is equal to passed in 
     // selection.Count and when it is, pass the list to TrySetResult() 
     // of TaskCompletionSource. Wrap that in try...catch and in catch 
     // block pass the exception to TrySetException method of 
     // TaskCompletionSource. This method should await and return 
     // Task object of TaskCompletionSource which will then contain the 
     // list of paths to your downloaded files. Then you move one with 
     // logic below to copy them to temp location and attach them from 
     // there. 
     paths = await GetAttachmentsPaths(MyAddIn.ActiveExplorer.Selection); 
    } 
    catch (Exception e) 
    { 
     // handle exceptions 
     return; 
    } 

    // create new message 
    Microsoft.Office.Interop.Outlook.MailItem oMailItem = MyAddIn.Application.CreateItem(Microsoft.Office.Interop.Outlook.OlItemType.olMailItem); 

    if (paths != null && paths.Count > 0) 
    { 
     var attachmentFileName = String.Empty; 
     try 
     { 
      // if list has downloaded files, copy them to tempFolder 
      List<string> copiedPaths = GetCopiedPaths(tempFolder, paths); 

      if (copiedPaths.Count > 0) 
      { 
       // then attach each from that location 
       foreach (var itemPath in copiedPaths) 
       { 
        FileInfo fInfo = new FileInfo(itemPath); 
        if (fInfo.Exists) 
        { 
         attachmentFileName = fInfo.Name; 
         oMailItem.Attachments.Add(itemPath, OlAttachmentType.olByValue, 1, fInfo.Name); 
        } 
        // delete file once attached to clean up 
        fInfo.Delete(); 
       } 
      } 

      if (oMailItem.Attachments.Count > 0) 
      { 
       oMailItem.Display(false); 
      } 
     } 
     catch (Exception ex) 
     { 
      // handle exceptions 
     } 
     finally 
     { 
      // delete temporary folder once done 
      if (Directory.Exists(tempFolder)) 
      { 
       Directory.Delete(tempFolder, true); 
      } 
     } 
    } 
} 
+0

再次感谢!这就是我遇到问题的原因。非常感激 – pixel

我建议从代码中立即释放所有底层COM对象开始。为此,您需要使用System.Runtime.InteropServices.Marshal.ReleaseComObject才能在完成使用后释放Outlook对象。然后在Visual Basic中将变量设置为Nothing(C#中为null)以释放对该对象的引用。请阅读Systematically Releasing Objects文章中的更多内容。

例如,我注意到的财产和方法调用以下链:

foreach (string itemPath in paths) 
    { 
     oMailItem.Attachments.Add(itemPath); 
    } 

MailItem类的Attachments属性从OOM返回correspondiong类的一个实例。它应该在发布后发布。

Attachments类的Add方法返回代表新附件的Attachment对象。所以,它也应该发布。

+0

谢谢尤金。我昨天找到了你的博客(@ https://www.add-in-express.com/creating-addins-blog/2011/08/10/how-to-add-attachment-to-e-mail-message/? thank = you&t = 1467071796#comment-413803)并添加了调用ReleaseComObject的逻辑。请参阅上面的UPDATE1。问题仍然存在。 – pixel

+0

我仍然可以看到你不释放底层COM对象的代码行。例如:if(oMailItem.Attachments.Count> 0) –

+0

我添加了该行(请参阅上面更新的代码块)。仍然没有效果。问题依然存在。我还注意到,如果发生崩溃,我的catch和finally块都不会执行。 – pixel