I need to convert a PowerPoint (ppt/pptx) file to PDF using C#
Currently, I'm using this code:
public void PPTXToPDF(string originalPptPath, string pdfPath) {
// Create COM Objects
Microsoft.Office.Interop.PowerPoint.Application pptApplication = null;
Microsoft.Office.Interop.PowerPoint.Presentation pptPresentation = null;
try {
object unknownType = Type.Missing;
//start power point
pptApplication = new Microsoft.Office.Interop.PowerPoint.Application();
//open powerpoint document
pptPresentation = pptApplication.Presentations.Open(originalPptPath,
Microsoft.Office.Core.MsoTriState.msoTrue, Microsoft.Office.Core.MsoTriState.msoTrue,
Microsoft.Office.Core.MsoTriState.msoFalse);
// save PowerPoint as PDF
pptPresentation.ExportAsFixedFormat(pdfPath,
Microsoft.Office.Interop.PowerPoint.PpFixedFormatType.ppFixedFormatTypePDF,
Microsoft.Office.Interop.PowerPoint.PpFixedFormatIntent.ppFixedFormatIntentPrint,
MsoTriState.msoFalse, Microsoft.Office.Interop.PowerPoint.PpPrintHandoutOrder.ppPrintHandoutVerticalFirst,
Microsoft.Office.Interop.PowerPoint.PpPrintOutputType.ppPrintOutputSlides, MsoTriState.msoFalse, null,
Microsoft.Office.Interop.PowerPoint.PpPrintRangeType.ppPrintAll, string.Empty, true, true, true,
true, false, unknownType);
} finally {
// Close and release the Document object.
if (pptPresentation != null) {
pptPresentation.Close();
pptPresentation = null;
}
// Quit PowerPoint and release the ApplicationClass object.
if(pptApplication != null) {
pptApplication.Quit();
pptApplication = null;
}
}
}
This snippet uses the Interop libraries, which create an instance of the PowerPoint application and use it programmatically.
The problem is that the application randomly crashes.
Sometimes in the finally block, pptApplication comes null, which means that the application didn't even open, sometimes it says The message filter indicated that the application is busy, sometimes I see a dialog titled "Exporting..." with a progressbar showing the export progress, then the dialog disappears and the program hangs forever until I force-close it.
The application fails randomly with the same file: I run it once, it works, I run it again, it works, I run it again, it doesn't work, etc...
I cannot have an application that sometimes works and sometimes fails, so my question is: Is there a reliable alternative for converting PowerPoint files to PDF which doesn't use Interop? Did Microsoft provide an alternative API to do these things without opening an instance of PowerPoint?
The reason why I'm using Interop at the moment is that I also have to read the PowerPoint file and search for shapes in slides, if that matters.
UPDATE
The PC I'm running my application is a Windows 7 PC with Office installed. I cannot install anything else, that's why I need to find an independent library.
Only other way that comes to my mind is try using libreoffice for the same task. It has headless mode (no UI) and can be called from command line, like this:
"C:\Program Files (x86)\LibreOffice 5\program\soffice.exe" --headless --convert-to pdf:writer_pdf_Export test.pptx
Note that it will exit immeditaly (because it is designed for batched processing), but you can watch output directory using FileSystemWatcher and when desired file was created there (and when you are able to acquire exclusive lock on it) - it is done. You can also do batch processing with it, for more options available look here - https://help.libreoffice.org/Common/Starting_the_Software_With_Parameters. I used it for some conversions and had no problems doing that.
Using interop you can try to generate the pdf using this approach:
I have tested making fifty exports at one time and worked fine.
_oPresentation.SaveAs(outputFullPath,
PowerPoint.PpSaveAsFileType.ppSaveAsPDF,
Microsoft.Office.Core.MsoTriState.msoCTrue);
Note: _oPresentation is just the interop presentation instance (Microsoft.Office.Interop.PowerPoint.Presentation).
Related
I have a C# application that creates an excel file. But if the file is left open and the app is run the second time, it throws IO exception (since, in the code I am replacing the existing file with new one)
Now, I want to check if the file is open and kill the excel.exe process that is referencing this file.
Is there any way this can be achieved?
Note: There might be several excel files open. I want to close only the process that is using my file.
xlFilePath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
File.Copy(xlFilePath + "\\file.xlsx", String.Format("{0}\\OutputFile{1}.{2}.xlsx", xlFilePath, DateTime.Now.Year, DateTime.Now.Month), true);
xlFilePath = Path.Combine(xlFilePath, String.Format("{0}\\OutputFile{1}.{2}.xlsx", xlFilePath, DateTime.Now.Year, DateTime.Now.Month));
appl = new Excel.Application(Visible = false);
wbookss = appl.Workbooks;
wbook = wbookss.Open(xlFilePath);
//Excel.Worksheets wsheetss = appl.Worksheets;
wsheet = wbook.Sheets["Sheet1"];
Application_GenerateReport(wsheet);
Clipboard.Clear();
wbook.Close(true);
wbookss.Close();
appl.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(wsheet);
System.Runtime.InteropServices.Marshal.ReleaseComObject(wbook);
System.Runtime.InteropServices.Marshal.ReleaseComObject(wbookss);
System.Runtime.InteropServices.Marshal.ReleaseComObject(appl);
EDIT: The file remains open if there was an exception in the last run. If it is opened by a user, it can be killed by checking the MainWindowTitle property (As suggested by Yeldar).
Another solution could be:
System.Diagnostics.Process.Start("CMD.exe","taskkill /f /im excel.exe");
This line will call command prompt and running the command taskkill.
All opening excel programs will be killed in this way.
Updated: (For one file)
System.Diagnostics.Process.Start("CMD.exe","taskkill /FI "WindowTitle eq Microsoft Excel - filename.xls");
As Excel stores the name of the opened file in its title like this:
Microsoft Excel - filename.xls
You can iterate through the processes and kill the one with the given name:
string filename = "mylist.xls";
var excelProcesses = Process.GetProcessesByName("excel");
foreach (var process in excelProcesses)
{
if (process.MainWindowTitle == $"Microsoft Excel - {filename}") // String.Format for pre-C# 6.0
{
process.Kill();
}
}
Note that:
it will also close all opened files with the same name
it will abandon any changes that user could change
title of Excel window may (or not, not sure, need to check) vary from version to version
However, as I said in comments, it is better to fix causes, but not consequences - just make your program start new Excel application without errors.
I am creating a command line application and I would like to connect to a SharePoint site that has a workbook that I want to update.
I don't even know where to start but I guess the questions I have are.
What API can I use for this? It has to be something that is already built-in and not a third party API if possible :)
Once the connection is done and I am able to open the spreadsheet, will I be able to also switch from one sheet to another?
I've tried to use some code like this but it did not work.
private static void GetExcelSheetNames(string filename)
{
var xls = new Microsoft.Office.Interop.Excel.Application();
xls.Visible = true;
xls.DisplayAlerts = false;
var workbook = xls.Workbooks.Open(Filename: filename, IgnoreReadOnlyRecommended: true, ReadOnly: false);
try
{
// Refresh the data from data connections
workbook.RefreshAll();
// Wait for the refresh occurs - *wish there was a better way than this.
System.Threading.Thread.Sleep(5000);
// Save the workbook back again
workbook.SaveAs(Filename: filename); // This is when the Exception is thrown
// Close the workbook
workbook.Close(SaveChanges: false);
}
catch (Exception ex)
{
//Exception message is "Cannot save as that name. Document was opened as read-only."
}
finally
{
xls.Application.Quit();
xls = null;
}
}
The Exception that I get was:
Microsoft Excel cannot access the file 'https//url/bla/bla/bla/workbook.xlsx There are several possible reasons:
The file name or path does not exist.
The file is being used by another program.
The workbook you are trying to save has the same name as a currently open workbook.
Actually, it seems like it is trying to open an instance of Excel Desktop in my machine.
Sorry for such an open question but I don't really know how can I connect to a SharePoint site.
Thanks in advance!
If you're using a document in a document library, check to make sure that it is checking out the document before you try to save it. I am working with a similar process but using a report library instead of a document library and am able to save documents without check out/in.
Please can someone help with a problem opening a Word2003 file in code using Microsoft.Office.Interop.Word?
My code is below. The document is created fine and if I pause the code after creating it I can open the file via explorer. The code freezes on the final line. At this point one can see a file locking metafile appear in explorer as well as the original. There is no error generated that I can see. Maybe there is an invisible dialog but otherwise I'm stumped.
Thanks in advance.
Firstly write a byte array to a file
var tmpFile = #"C:\donkey.doc";
File.WriteAllBytes(tmpFile, binary_document);
Open the file as a document object of some type
Application app = new Application();
Document CurrDoc = app.Documents.Open(#"C:\donkey.doc");
Solution to freeze was re-installing Word2003 although I have actually abandoned the approach altogether due to the server issues identified here http://support.microsoft.com/kb/257757. Thanks for all help.
Try this it may help you.
Create a new "Desktop" directory inside of "C:\Windows\SysWOW64\config\systemprofile\"
it works for me after a long long long day searching for the solution.
It seams to be a profile problem.
What I will check in same situation
Permission access
Create a file outside C# and only remain the file open part
When stuck at open command, task manager has Microsoft Word exe running?
Suggestion to Solve
1) Run as Console Application (those posts I mentioned they work well in Console)
2) Try to put CurrDoc.Activate() after CurrDoc = app.Documents.Open(#"C:\donkey.doc");
3) Try to declare byte[] binary_document = { 112 }; but not using your current array to let File.WriteAllBytes() finish its work faster.
4) Try Highest vote post of Interop.Word Documents.Open is null
5) Try Suggestion for XP (search "xp") in Word 2007 Documents.Open returns null in ASP.NET
6) Try catch the exception (but seem like your case is not exception)
try
{
CurrDoc = app.Documents.Open(tmpFile);
}
catch (Exception eX)
{
//MessageBox.Show(eX.ToString());
Console.WriteLine(eX);
}
Sorry hope I'm not confusing you.
Work For Me
Refer to #Mike Miller, the main point is app.Visible is not set to true; The app is active but Only it is NOT visible!! Learn something new. thanks.
I am using Microsoft Word 2010 and Windows 7 Home Premium 64 bit.
Document CurrDoc;
//avoid ambiguity so put in missing argument
object missing = System.Reflection.Missing.Value;
Microsoft.Office.Interop.Word.Application app;
private void btnMakeandOpenDoc_Click(object sender, EventArgs e)
{
//put in some byte value into the array
byte[] binary_document = { 112, 132, 32, 33,231,125,87 };
var tmpFile = #"C:\donkey.doc";
File.WriteAllBytes(tmpFile, binary_document);
app = new Microsoft.Office.Interop.Word.Application();
CurrDoc = app.Documents.Open(#"C:\donkey.doc");
//main point
app.Visible = true;
}
//close the opening doc file also
private void btnCloseDoc_Click(object sender, EventArgs e)
{
CurrDoc.Close(ref missing, ref missing, ref missing);
app.Application.Quit(ref missing, ref missing, ref missing);
}
While debugging, if you manually open this file through explorer, the last line will also try and do the same thing. Now, I cannot remember Office 2003 behaviour any more but 2010 does prompt that you are trying to open same file again (or at least it does that to me). This could well be the reason.
Solution to freeze was re-installing Word2003 although I have actually abandoned the approach altogether due to the server issues identified here http://support.microsoft.com/kb/257757. Thanks for all help.
I created a desktop folder but in this folder: C:\Windows\System32\config\systemprofile and gave the service account access to the folder. Do not know if the access is neccessary but it worked.
After doing some research, it seems that you can use Word Interlop to manipulate Word document (Open, modify, change etc.). Like this:
class Program
{
static void Main(string[] args)
{
Application ap = new Application();
Document doc = ap.Documents.Open(#"C:\temp\TestDoc.docx");
doc.Activate();
}
}
But doing it that way, the MS word application itself with the GUI are not showing. I suspect it does not get started at all. I can only see WINWORD.EXE in the Processes tab of the Windows Task Manager but not in Applications tab.
What I want to do is:
Starting the MS Word application
open the document
Show it to the end user, so they can modify/save it.
How can I do this?
Unless you need to control Word application simple Process.Start may be enough:
Process.Start(#"C:\temp\TestDoc.docx")
If you want to stick with using Office Interop, then I think you can get what you're looking for by setting the Visible property of the Application instance to true after you open the document.
ap.Visible = true;
Use Process.Start instead.
That's all you need here and will produce the behavior you're after.
I am using Ms Office Interop assemblies to create a MS Project file. To save the file created, I am using FileSaveAs method and it prompts a message saying that if you want to replace the existing file.
I want to suppress the message, and I didn't find any parameter in FileSaveAs method for this purpose.
Any Idea on this?
I'am using C# as my programming language.
I ran into this issue when working with Excel Interop. The best I've been able to find is to disable all Office alerts, like this:
Microsoft.Office.Interop.MSProject.Application msProjectApp = new Microsoft.Office.Interop.MSProject.Application();
msProjectApp.DisplayAlerts = false;
Never double dot COM objects, as they will not be released and this will leave excel open on your server. Unfortunately I have crashed servers because of this.
private void InitialiseExcel()
{
if (excelApp == null)
excelApp = new Excel.Application();
// Turn off User Prompts
excelApp.DisplayAlerts = false;
// Turn off screen updating so we do not get flicker
var app = excelApp.Application;
app.ScreenUpdating = false;
// Specifies the state of the window;
excelApp.WindowState = Excel.XlWindowState.xlMinimized;
Marshal.ReleaseComObject(app);
}