如何在C#自动化Outlook后关闭它

4

我正在创建一个将Outlook邮件转换为PDF的程序。我的做法是先将Msg文件导出为Html,然后将Html输出转换为PDF。以下是我的代码:

Microsoft.Office.Interop.Outlook.Application app = new Microsoft.Office.Interop.Outlook.Application();

string filename = System.IO.Path.GetFileNameWithoutExtension(msgLocation) + ".html";
string attachmentFiles = System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetFileNameWithoutExtension(msgLocation) + "_files");
string extractLocation = System.IO.Path.Combine(System.IO.Path.GetTempPath(), filename);

Console.WriteLine(filename);
Console.WriteLine(attachmentFiles);
Console.WriteLine(extractLocation);
var item = app.Session.OpenSharedItem(msgLocation) as Microsoft.Office.Interop.Outlook.MailItem;
item.SaveAs(extractLocation, Microsoft.Office.Interop.Outlook.OlSaveAsType.olHTML);

int att = item.Attachments.Count;
if (att > 0)
{
    for (int i = 1; i <= att; i++)
    {
        item.Attachments[i].SaveAsFile(System.IO.Path.Combine(attachmentFiles, item.Attachments[i].FileName));
    }
}

app.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(app);

MSG文件转换为HTML已经完美运行了,但为什么Outlook.exe仍在运行?我想关闭它,但app.Quit()无法关闭该应用程序。


你最终做了什么? - Andrew Truckle
2个回答

4
问题在于 Outlook COM 对象持有引用并阻止应用程序关闭。使用以下函数,并将您的 "app" 对象传递给它:
private void ReleaseObj(object obj)
{
    try 
    {
        System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
    }
    finally 
    {
        obj = null;
    }
}

请参考这篇文章,了解如何在使用Visual Studio .NET客户端自动化后安全地退出Outlook应用程序。

2
我尝试了,先生,但进程仍在运行。在我的上面的代码中,我有类似的代码System.Runtime.InteropServices.Marshal.ReleaseComObject(app); - outlook email
你在调用.Quit()之前是否调用了Release()? - Rocklan
你需要在 finally 块中将其设置为 null。 - Rocklan
也要为您的Item对象执行相同的操作。 - Rocklan
+2 分钟,推荐这些最佳实践。 - Marcelo Scofano Diniz
你的程序所持有的所有Outlook COM对象都应该这样处理。我的程序还有一个命名空间对象(持有对Outlook会话的引用)和一个文件夹对象(持有对收件箱的引用),它们也必须被释放。然而,如果你使用类似于_rows_变量(保存来自表对象的数据)的东西,那么这个对象只需要设置为null即可。调用ReleaseComObject方法将导致错误,因为它不被视为COM对象。因此,需要使用try-catch语句。 - Tristan Bailey

-1

通过引用应用程序名称,这应该适用于任何应用程序,并将终止所有应用程序实例。例如,如果您有5个记事本实例,它将终止它们所有...

要终止应用程序,请使用以下方法:

 KillProcessByPID.KillProcessByName("OUTLOOK");

请创建以下静态类(在这种情况下,我选择使用C# .NET Core 6.0,但它应该是相当通用的)。
using System.Management;
using System.Diagnostics;


public static class KillProcessByPID
{
    public static void KillProcessByName(string ProcessName)
    {
        string OutlookProcessName = "";
        foreach (Process otlk in Process.GetProcesses())
        {
            if (otlk.ProcessName.ToLower().Contains(ProcessName.ToLower())) //OUTLOOK is the one I am seeking - yours may vary
            {
                OutlookProcessName = otlk.ProcessName;
            }
        }
        //Get process ID by Name
        var processes = Process.GetProcessesByName(OutlookProcessName);
        foreach (var process in processes)
        {
            Console.WriteLine("PID={0}", process.Id);
            Console.WriteLine("Process Handle={0}", process.Handle);
            PortfolioTrackerXML.KillProcessByPID.KillProcessAndChildren(process.Id);
        }
    }


    /// <summary>
    /// Kill a process, and all of its children, grandchildren, etc.
    /// </summary>
    /// <param name="pid">Process ID.</param>
    public static void KillProcessAndChildren(int pid)
    {
        // Cannot close 'system idle process'.
        if (pid == 0)
        {
            return;
        }
        ManagementObjectSearcher searcher = new ManagementObjectSearcher
                ("Select * From Win32_Process Where ParentProcessID=" + pid);
        ManagementObjectCollection moc = searcher.Get();
        foreach (ManagementObject mo in moc)
        {
            KillProcessAndChildren(Convert.ToInt32(mo["ProcessID"]));
        }
        try
        {
            Process proc = Process.GetProcessById(pid);
            proc.Kill();
        }
        catch (ArgumentException)
        {
            // Process already exited.
        }
    }
}

我从很多人那里借鉴,但我不确定是从哪里借的,但我感谢你们所有人并给予你们所有人信用...抱歉没有直接引用你们,但这对我非常重要


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接