9

嘿,我正在从 C# WinForms 应用程序自动化 PowerPoint 和 Excel;我所做的是从 PowerPoint 中读取幻灯片并将它们保存在 Excel 中,然后退出这两个应用程序。Excel 成功退出,但 PowerPoints 没有退出。问题是当我第一次转换时它不会退出,但是当我再次转换时它会退出。

这是我的代码

try
{
    PowerPoint.Application ppApp;
    PowerPoint.Presentation ppPres;
    List<Company> companies = new List<Company>();

    ppApp = new PowerPoint.Application();
    ppApp.Visible = Microsoft.Office.Core.MsoTriState.msoTrue;
    ppApp.WindowState = Microsoft.Office.Interop.PowerPoint.PpWindowState.ppWindowMinimized;

    ppPres = ppApp.Presentations.Open(fileTxtBox.Text,
                                      Microsoft.Office.Core.MsoTriState.msoFalse,
                                      Microsoft.Office.Core.MsoTriState.msoFalse,
                                      Microsoft.Office.Core.MsoTriState.msoTrue);

    int slides = ppPres.Slides.Count;

    for (int slide = 1; slide <= slides; slide++)
    {
        int rows = 1;
        PowerPoint.Cell cell;
        int shape = 1;

        for (; shape < ppPres.Slides[slide].Shapes.Count; shape++)
        {
            if (ppPres.Slides[slide].Shapes[shape].HasTable == Microsoft.Office.Core.MsoTriState.msoTrue)
            {
                cell = ppPres.Slides[slide].Shapes[shape].Table.Cell(1, 1);

                if (cell.Shape.TextFrame.TextRange.Text.Trim().ToLower().Contains("realized"))
                {
                    rows = ppPres.Slides[slide].Shapes[shape].Table.Rows.Count;
                    break;
                }
            }
        }

        Company comp = new Company(rows);
        InitializeCompany(ref comp, ppPres.Slides[slide]);
        companies.Add(comp);
    }

    SaveInExcel(companies);

    ppPres.Close();
    ppPres = null;
    ppApp.Quit();
    ppApp = null;

    return;
}

catch (Exception ex)
{
    MessageBox.Show(ex.Message);
}

finally
{
    GC.Collect();
    GC.WaitForPendingFinalizers();
}
4

7 回答 7

12

关闭 Microsoft Office 应用程序一开始似乎很棘手,但一旦确定了正确的操作顺序,实际上一点也不难。

可以分两个阶段安全有效地发布您的 MS Office 应用程序:

(1) 首先释放命名变量中没有引用的所有次要对象。您可以通过调用 GC.Collect()然后调用 GC.WaitForPendingFinalizers()来执行此操作。请注意,如果您使用的是 Visual Studio Tools for Office (VSTO),则需要两次调用这对命令才能使 COM 对象成功发布。但是,您没有使用 VSTO,因此调用它们一次就足够了。

(2) 然后使用对您拥有的每个变量的Marshall.FinalReleaseComObject()的调用,通过命名变量显式释放您持有的对象。

请记住显式释放您对 COM 组件所拥有的所有变量。如果您错过了一个,那么您的 MS Office 应用程序将挂起。在您的代码中,您似乎有三个命名变量,它们包含对您的 PowerPoint 应用程序的引用:ppAppppPrescell.

考虑到这一切,我认为您的清理应该如下所示,它using System.Runtime.InteropServices在命名空间内或代码文档顶部使用:

// using System.Runtime.InteropServices

// Cleanup:
GC.Collect();
GC.WaitForPendingFinalizers();

Marshal.ReleaseComObject(cell);

ppPres.Close();
Marshal.ReleaseComObject(ppPres);

ppApp.Quit();
Marshal.ReleaseComObject(ppApp);

试一试,我认为这对你有用......(如果没有,你可能需要显示更多代码。)有关更多信息,我将在此处详细说明如何正确发布 Excel 应用程序:

如何在 C# 中正确清理 Excel 互操作对象

希望这会有所帮助,让我们知道它是怎么回事......

——迈克

于 2009-06-11T16:03:04.157 回答
2

这是描述问题和解决方案的 MSDN 文章

http://msdn.microsoft.com/en-us/library/aa679807%28office.11​​%29.aspx

基本上推荐是要做的(注意:GC.Collect()的两次迭代

 GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
            GC.WaitForPendingFinalizers(); 
于 2009-12-21T21:28:26.307 回答
2

嗨,伙计们。最近我观察到,从垃圾收集到退出和关闭对象,我没有任何解决办法。所以我想出了一个替代方案。一旦我的工作完成,我就发现了正在运行的进程,然后通过代码将其杀死。

代码:

 Process[] pros = Process.GetProcesses();
  for (int i = 0; i < pros.Count(); i++)
   {
   if (pros[i].ProcessName.ToLower().Contains("powerpnt"))
        {
          pros[i].Kill();
        }
   }
于 2013-06-11T06:57:07.837 回答
1

看起来您正在使 Power Point 应用程序实例可见,但如果不可见,则可能存在一个您看不到的对话框 - 可能是一个保存更改对话框。如果应用程序处于隐藏状态,请使其可见,以查看是否弹出任何此类对话框,以防止 Power Point 关闭。

于 2009-06-11T14:55:18.920 回答
0

为您的ppApp对象调用Quit()后,请尝试以下操作

System.Runtime.InteropServices.Marshal.ReleaseComObject(ppApp);

然而,没有任何承诺,它可能会起作用,或者它可能什么都不做。正确关闭 Office COM 的东西对我来说一直有点像巫术。

于 2009-06-11T15:00:00.610 回答
0

为我工作

       var app = new PowerPoint.Application();
            PowerPoint.Presentations pres = app.Presentations;
            PowerPoint.Presentation ActivePresentation = pres.Open(fileIn, MsoTriState.msoTrue, MsoTriState.msoTrue, MsoTriState.msoFalse);
(...)
            ActivePresentation.SaveAs(fileOut, PowerPoint.PpSaveAsFileType.ppSaveAsDefault, MsoTriState.msoTrue);

            ActivePresentation.Close();
            app.Quit();
于 2017-02-02T14:28:40.427 回答
0

我在 VS2019 中使用 VSTO 来管理 Office-365 应用程序,并且使用“Application.Quit()”一切正常 - 除了 Powerpoint!

PP 有时会冻结,有时它会在退出之前出现很多“ThreadException”(我猜它真的中止了它的线程)。我已经测试了上述所有代码以及在 Google 中找到的许多其他提示,但均未成功。

这是一个肮脏的解决方案,但它可以在保存演示文稿后立即工作并关闭 PP。

但我建议您,我的解决方案是通过自定义 RIBBON GROUP 中按钮的单击事件启动的;否则您将不得不以编程方式“找到” PP 窗口并选择它(将焦点放在它上面)。

GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()

SendKeys.Send("%{F4}")

人家就是这样...

于 2021-07-14T23:24:45.847 回答