Reputation: 23
Trying to use Microsoft.Office.Interop.PowerPoint to open PPT files and save as PDF (or other file types) for large batch jobs. Works great with files that have no password. With files that have a password, which I'll never know, I just want to gracefully fail. However, PowerPoint will open dialog prompt and even when my code aborts the opening thread that thread I can't use PowerPoint until that prompt is manually closed and so further processing of other files is blocked.
Suggestions?
The basis for my code is as follows:
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Threading;
using Microsoft.Office;
using Microsoft.Office.Interop.PowerPoint;
using MT = Microsoft.Office.Core.MsoTriState;
namespace PowerPointConverter
{
public class PowerPointConverter : IDisposable
{
Application app;
public PowerPointConverter()
{
app = new Microsoft.Office.Interop.PowerPoint.Application();
app.DisplayAlerts = PpAlertLevel.ppAlertsNone;
app.ShowWindowsInTaskbar = MT.msoFalse;
app.WindowState = PpWindowState.ppWindowMinimized;
}
public bool ConvertToPDF(FileInfo sourceFile, DirectoryInfo destDir)
{
bool success = true;
FileInfo destFile = new FileInfo(destDir.Name + "\\" +
Path.GetFileNameWithoutExtension(sourceFile.Name) + ".pdf");
Thread pptThread = new Thread(delegate()
{
try
{
Presentation ppt = null;
ppt = app.Presentations.Open(sourceFile.FullName, MT.msoTrue, MT.msoTrue, MT.msoFalse);
ppt.SaveAs(destFile.FullName, PpSaveAsFileType.ppSaveAsPDF, MT.msoFalse);
ppt.Close();
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(ppt);
}
catch (System.Runtime.InteropServices.COMException comEx)
{
success = false;
}
});
pptThread.Start();
if (!pptThread.Join(20000))
{
pptThread.Abort();
success = false;
}
return success;
}
public void Dispose()
{
Thread appThread = new Thread(delegate()
{
try
{
if (null != app)
{
app.Quit();
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(app);
}
}
catch (System.Runtime.InteropServices.COMException) { }
});
appThread.Start();
if (!appThread.Join(10000))
{
appThread.Abort();
}
}
}
}
Upvotes: 2
Views: 1090
Reputation: 13
Thanks Steve for your answer. This actually worked.
Before we tried to use ProtectedViewWindow for this purpose, but this actually not worked quit well in some cases:
try {
windowId = pptApp.ProtectedViewWindows.Open(pptPath,
PRESENTATION_FAKE_PASSWORD).HWND;
} catch (Exception ex) {
if (!ex.Message.Contains("could not open")) {
// Assume it is password protected.
_conversionUtil.LogError(
"Powerpoint seems to be password protected.",
_conversionRequest, ex);
}
}
Code based on your solution works quite well and doesn't require to open PP one unnecessary time for verification:
Presentation presentation;
try {
presentation = pptApplication.Presentations.Open(_localPptPath +
"::" + PRESENTATION_FAKE_PASSWORD + "::", MsoTriState.msoTrue,
MsoTriState.msoFalse, MsoTriState.msoFalse);
} catch (Exception e) {
// if error contains smth about password -
// assume file is password protected.
if (e.Message.Contains("password")) {
throw new ConversionException(
"Powerpoint seems to be password protected: " + e.Message,
ConversionStatus.FAIL_PASSWORD_PROTECTED);
}
// otherwice rethrow it
throw;
}
Upvotes: 0
Reputation: 14809
Translate this VBA to [whatever] and you should be good to go.
Dim oPres As Presentation
On Error Resume Next
Set oPres = Presentations.Open("c:\temp\open.pptx::BOGUS_PASSWORD::")
If Not Err.Number = 0 Then
MsgBox "Blimey, you trapped the error!" _
& vbCrLf & Err.Number & vbCrLf & Err.Description
End If
More generically:
Presentations.Open "filename.ext::open_password::modify_password"
If you pass a passworded file a deliberately bogus password, you get a trappable error, but PPT doesn't pop a dialog box. If you pass a non-passworded file a password, it just opens.
This should work with new or old-binary format files, and I'm told it works in versions as far back as 2003.
Upvotes: 5