0

我有以下代码

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

呼叫 1:第一次呼叫SendAttachmentsClick()打开新电子邮件并正确附加所有附件。

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

UPDATE1: 阅读 Eugene Astafiev 在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,我修改了上面的代码以释放 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);
        }
    }
}
4

2 回答 2

1

我建议从立即在代码中释放所有底层 COM 对象开始。为此,您需要在使用完毕后使用System.Runtime.InteropServices.Marshal.ReleaseComObject释放 Outlook 对象。然后在 Visual Basic 中将变量设置为 Nothing(在 C# 中为 null)以释放对对象的引用。在系统地释放对象文章中阅读更多相关信息。

例如,我注意到以下属性和方法调用链:

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

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

该类的Add方法Attachments返回一个表示新附件的附件对象。所以,它也应该被释放。

于 2016-06-28T07:12:44.047 回答
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); 
            }
        }
    }  
}
于 2016-08-24T16:11:43.970 回答