Hey I'm automating PowerPoint and Excel from a C# WinForms application; what I do is read slides from PowerPoint and save them in Excel and then quit both apps. Excel quits successfully but PowerPoints doesn't quits. The problem is when I convert first time it doesnt quits, but when I convert again it does.
嘿我从C#WinForms应用程序自动化PowerPoint和Excel;我所做的是从PowerPoint中读取幻灯片并将其保存在Excel中,然后退出这两个应用程序。 Excel退出成功但PowerPoints不退出。问题是当我第一次转换它不退出时,但当我再次转换时它确实。
Here is my code
这是我的代码
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();
}
6 个解决方案
#1
Shutting down your Microsoft Office application can seem tricky to get right at first, but once you establish the correct order of operations, it's actually not very hard at all.
关闭你的Microsoft Office应用程序起初看起来很难,但是一旦你建立了正确的操作顺序,它实际上并不是很难。
Releasing your MS Office application can be done safely and effectively in two stages:
释放MS Office应用程序可以分两个阶段安全有效地完成:
(1) First release all the minor objects to which you do not hold a reference within a named variable. You do this via a call to GC.Collect() and then GC.WaitForPendingFinalizers() . Note that if you are using Visual Studio Tools for Office (VSTO), then you need to call this pair of commands twice in order to get the COM objects to successfully release. You are not using VSTO, however, so calling them once is sufficient.
(1)首先释放在命名变量中没有引用的所有次要对象。您可以通过调用GC.Collect()然后调用GC.WaitForPendingFinalizers()来完成此操作。请注意,如果您使用的是Visual Studio Tools for Office(VSTO),则需要调用此对命令两次才能使COM对象成功释放。但是,您没有使用VSTO,因此调用它们就足够了。
(2) Then explicitly release the objects which you hold via a named variable using a call to Marshall.FinalReleaseComObject() on each variable you have.
(2)然后使用对每个变量的Marshall.FinalReleaseComObject()调用,通过命名变量显式释放您保存的对象。
Remember to explicitly release all variables that you have to COM components. If you miss even one, then your MS Office application will hang. In your code, you seem to have three named variables that hold a reference to your PowerPoint application: ppApp
, ppPres
, and cell
.
请记住明确释放COM组件的所有变量。如果您错过了一个,那么您的MS Office应用程序将挂起。在您的代码中,您似乎有三个命名变量,它们包含对PowerPoint应用程序的引用:ppApp,ppPres和cell。
Taking this all into account, I think that your cleanup should look something like the following, which makes use of using System.Runtime.InteropServices
either within the namespace or at the top of the code document:
考虑到这一点,我认为您的清理应该类似于以下内容,它使用在命名空间内或代码文档顶部使用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);
Give it a try, I think this should work for you... (If not, you might have to show even more of your code.) For further information, I give a detailed explanation on how to properly release an Excel application here:
尝试一下,我认为这应该对你有用...(如果没有,你可能需要显示更多代码。)有关详细信息,我将详细解释如何在此处正确发布Excel应用程序:
How to properly clean up Excel interop objects in C#.
如何在C#中正确清理Excel互操作对象。
Hope this helps, let us know how it goes...
希望这有帮助,让我们知道它是怎么回事......
-- Mike
#2
Here is a MSDN article that describes the problem and solution
这是一篇描述问题和解决方案的MSDN文章
http://msdn.microsoft.com/en-us/library/aa679807%28office.11%29.aspx
basically recomondation is to do(Note : two iterations of GC.Collect()
基本上重新推荐(注意:GC.Collect()的两次迭代
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
#3
Hie folks.lately i have observed that nothing worked out for me from garbage collect to quitting and closing objects. so i came up with an alternative. i found out the running process once my job was done,and then killed it through code.
Hie folks.lately我发现从垃圾收集到退出和关闭物体对我来说没有任何效果。所以我提出了另一种选择。我的工作完成后,我发现了正在运行的进程,然后通过代码将其杀死。
Code:
Process[] pros = Process.GetProcesses();
for (int i = 0; i < pros.Count(); i++)
{
if (pros[i].ProcessName.ToLower().Contains("powerpnt"))
{
pros[i].Kill();
}
}
#4
It looks like you are making the Power Point application instance visible, but if not, it's possible that there is a dialog being presented that you don't see - perhaps a save changes dialog. If the app is running hidden, make it visible to see if any such dialogs are popping up, preventing Power Point from closing.
看起来您正在使Power Point应用程序实例可见,但如果没有,则可能会出现一个您看不到的对话框 - 可能是保存更改对话框。如果应用程序正在隐藏运行,请将其显示以查看是否弹出任何此类对话框,从而阻止Power Point关闭。
#5
After invoking Quit() for your ppApp object try the following
在为ppApp对象调用Quit()之后,请尝试以下操作
System.Runtime.InteropServices.Marshal.ReleaseComObject(ppApp);
No promises however, it might work, or it might do nothing at all. Properly closing down Office COM stuff has always been a bit like voodoo for me.
然而,没有承诺,它可能会起作用,或者它根本不会做任何事情。正确关闭Office COM的东西对我来说总是有点像伏都教。
#6
This Work for me
这对我有用
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();
#1
Shutting down your Microsoft Office application can seem tricky to get right at first, but once you establish the correct order of operations, it's actually not very hard at all.
关闭你的Microsoft Office应用程序起初看起来很难,但是一旦你建立了正确的操作顺序,它实际上并不是很难。
Releasing your MS Office application can be done safely and effectively in two stages:
释放MS Office应用程序可以分两个阶段安全有效地完成:
(1) First release all the minor objects to which you do not hold a reference within a named variable. You do this via a call to GC.Collect() and then GC.WaitForPendingFinalizers() . Note that if you are using Visual Studio Tools for Office (VSTO), then you need to call this pair of commands twice in order to get the COM objects to successfully release. You are not using VSTO, however, so calling them once is sufficient.
(1)首先释放在命名变量中没有引用的所有次要对象。您可以通过调用GC.Collect()然后调用GC.WaitForPendingFinalizers()来完成此操作。请注意,如果您使用的是Visual Studio Tools for Office(VSTO),则需要调用此对命令两次才能使COM对象成功释放。但是,您没有使用VSTO,因此调用它们就足够了。
(2) Then explicitly release the objects which you hold via a named variable using a call to Marshall.FinalReleaseComObject() on each variable you have.
(2)然后使用对每个变量的Marshall.FinalReleaseComObject()调用,通过命名变量显式释放您保存的对象。
Remember to explicitly release all variables that you have to COM components. If you miss even one, then your MS Office application will hang. In your code, you seem to have three named variables that hold a reference to your PowerPoint application: ppApp
, ppPres
, and cell
.
请记住明确释放COM组件的所有变量。如果您错过了一个,那么您的MS Office应用程序将挂起。在您的代码中,您似乎有三个命名变量,它们包含对PowerPoint应用程序的引用:ppApp,ppPres和cell。
Taking this all into account, I think that your cleanup should look something like the following, which makes use of using System.Runtime.InteropServices
either within the namespace or at the top of the code document:
考虑到这一点,我认为您的清理应该类似于以下内容,它使用在命名空间内或代码文档顶部使用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);
Give it a try, I think this should work for you... (If not, you might have to show even more of your code.) For further information, I give a detailed explanation on how to properly release an Excel application here:
尝试一下,我认为这应该对你有用...(如果没有,你可能需要显示更多代码。)有关详细信息,我将详细解释如何在此处正确发布Excel应用程序:
How to properly clean up Excel interop objects in C#.
如何在C#中正确清理Excel互操作对象。
Hope this helps, let us know how it goes...
希望这有帮助,让我们知道它是怎么回事......
-- Mike
#2
Here is a MSDN article that describes the problem and solution
这是一篇描述问题和解决方案的MSDN文章
http://msdn.microsoft.com/en-us/library/aa679807%28office.11%29.aspx
basically recomondation is to do(Note : two iterations of GC.Collect()
基本上重新推荐(注意:GC.Collect()的两次迭代
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
#3
Hie folks.lately i have observed that nothing worked out for me from garbage collect to quitting and closing objects. so i came up with an alternative. i found out the running process once my job was done,and then killed it through code.
Hie folks.lately我发现从垃圾收集到退出和关闭物体对我来说没有任何效果。所以我提出了另一种选择。我的工作完成后,我发现了正在运行的进程,然后通过代码将其杀死。
Code:
Process[] pros = Process.GetProcesses();
for (int i = 0; i < pros.Count(); i++)
{
if (pros[i].ProcessName.ToLower().Contains("powerpnt"))
{
pros[i].Kill();
}
}
#4
It looks like you are making the Power Point application instance visible, but if not, it's possible that there is a dialog being presented that you don't see - perhaps a save changes dialog. If the app is running hidden, make it visible to see if any such dialogs are popping up, preventing Power Point from closing.
看起来您正在使Power Point应用程序实例可见,但如果没有,则可能会出现一个您看不到的对话框 - 可能是保存更改对话框。如果应用程序正在隐藏运行,请将其显示以查看是否弹出任何此类对话框,从而阻止Power Point关闭。
#5
After invoking Quit() for your ppApp object try the following
在为ppApp对象调用Quit()之后,请尝试以下操作
System.Runtime.InteropServices.Marshal.ReleaseComObject(ppApp);
No promises however, it might work, or it might do nothing at all. Properly closing down Office COM stuff has always been a bit like voodoo for me.
然而,没有承诺,它可能会起作用,或者它根本不会做任何事情。正确关闭Office COM的东西对我来说总是有点像伏都教。
#6
This Work for me
这对我有用
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();