2016-06-27 11 views
0

私は、コードを次している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()を呼び出すには、新しい電子メールを開いて、適切にそこにすべての添付ファイルを添付します。

CALL 2:私は、この新しい電子メールメッセージで[キャンセル]をクリックし、再度SendAttachmentsClick()を呼び出す場合、私は(私はこのコードにブレークポイントを持っている)上記oMailItemAttachments.Add(itemPath)への呼び出しまで実行をトレースすることができます。ただし、2番目の呼び出しの最初の添付ファイルに対してこの行が呼び出されると、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

答えて

1

提案したとおり、私はこのようなことをします。上記のようにメールアイテムを保存する必要はありません。私はあなたの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

1

を持続すべての基になるCOMオブジェクトをコード内で即座に解放することから始まります。そのためには、Outlookオブジェクトの使用を終了したら、System.Runtime.InteropServices.Marshal.ReleaseComObjectを使用してOutlookオブジェクトを解放する必要があります。 Visual Basicでは変数をNothingに設定し(C#ではnull)、オブジェクトへの参照を解放します。詳細については、Systematically Releasing Objectsの記事をご覧ください。例えば

、Iプロパティの次のチェーンに気づいており、メソッド呼び出し:

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

という行を追加しました(上記の更新されたコードブロックを参照してください)。まだ効果はありません。問題は依然として存在します。私はまた、クラッシュが発生した場合、私のキャッチもブロックも実行されないことに気付きました。 – pixel

関連する問題