2016-06-27 12 views
0

I-Code verfolgt habenVSTO C# MailItem.Attachments.Add() Crashes

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); 
     } 
    } 
} 

ANRUF 1:SendAttachmentsClick() zum ersten Mal aufrufen eröffnet neue E-Mail und legt alle Anlagen, um es richtig.

AUFFORDERUNG 2: Wenn ich in dieser neuen E-Mail-Nachricht auf Abbrechen klicken und SendAttachmentsClick() dann wieder aufrufen, ich kann die Ausführung verfolgen, bis Anruf oMailItemAttachments.Add(itemPath) oben (ich habe Bruchstellen in diesem Code). Sobald diese Zeile jedoch für die ersten Anhänge im zweiten Aufruf aufgerufen wird, stürzt der gesamte VSTO/Outlook ab. Ich habe versucht ... fangen, um zu versuchen, Ausnahme zu fangen, aber es wird nie eingegeben, also weiß ich nicht, was der Fehler ist.

UPDATE1: Nach einem Artikel von Eugene Astafiev bei 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 Lesen, modifizierte ich über meinen Code COM-Objekte freizugeben, und jetzt sieht es so aus, aber das Problem weiterhin besteht nach wie vor

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

Ich frage mich, wie Ihre GetAttachmentsPaths() die Pfade bekommt. Sind die Dateien auf Ihrem lokalen Computer vorhanden oder werden sie von irgendwo heruntergeladen? Wenn Sie sie von irgendwo herunterladen, könnte es sein, dass Ihre Löschlogik die Downloads löscht? – cd491415

+0

Ich glaube, du hast Recht. Was schlagen Sie vor? Sehr geschätzt – pixel

+1

Ich würde heruntergeladene Dateien in ein anderes temporäres Verzeichnis verschieben, sie von dort verarbeiten und dann das temporäre Verzeichnis löschen. Ich habe unten eine Teillösung gepostet. – cd491415

Antwort

1

Wie vorgeschlagen, würde ich es so etwas tun. Sie müssen Ihre Post nicht wie oben speichern. Beachten Sie, dass ich Ihnen die Logik für Ihre GetAttachmentsPaths-Methode nicht zur Verfügung gestellt habe, da ich nicht weiß, wie Sie das tun, aber es scheint mir, dass Sie die Dateien zuerst von irgendwo herunterladen, und Sie haben das bestätigt. Ich habe jedoch sehr gute Anweisungen gegeben, wie man diese Methode schreibt und die Pfade heruntergeladener Dateien zurückgibt. Ich hoffe, das hilft.

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

Danke nochmal! Das war der Grund, warum ich Probleme hatte. Sehr geschätzt – pixel

1

würde ich empfehlen beginnend mit der sofortigen Freigabe aller zugrunde liegenden COM-Objekte im Code. Dazu müssen Sie System.Runtime.InteropServices.Marshal.ReleaseComObject verwenden, um ein Outlook-Objekt freizugeben, wenn Sie es nicht mehr verwenden. Setzen Sie dann eine Variable auf Nothing in Visual Basic (null in C#), um den Verweis auf das Objekt freizugeben. Lesen Sie mehr dazu im Artikel Systematically Releasing Objects.

Zum Beispiel habe ich die folgende Kette von Eigentum und Methodenaufrufen bemerkt:

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

Die Attachments Eigenschaft der MailItem-Klasse gibt eine Instanz der Klasse correspondiong vom OOM. Und es sollte danach veröffentlicht werden.

Die Add-Methode der Klasse Attachments gibt ein Objekt Attachment zurück, das den neuen Anhang darstellt. Also sollte es auch veröffentlicht werden.

+0

Danke Eugene. Ich habe Ihren Blog gestern gefunden (@ 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) und Logik hinzugefügt, um ReleaseComObject aufzurufen. Bitte beachten Sie UPDATE1 oben. Das Problem besteht jedoch weiterhin. – pixel

+0

Ich sehe immer noch Codezeilen, in denen Sie keine zugrunde liegenden COM-Objekte freigeben. Zum Beispiel: if (oMailItem.Attachments.Count> 0) –

+0

Ich habe die Zeile hinzugefügt (siehe oben den aktualisierten Codeblock). Immer noch keine Wirkung.Problem existiert noch. Ich habe auch bemerkt, dass, wenn der Absturz passiert, weder meine catch noch finally Block ausgeführt wird. – pixel