// update all fields in a range private static void updateFieldsInRange(Range range, Microsoft.Office.Interop.Word.Application word, String filename) { var rangeFields = range.Fields; if (rangeFields.Count > 0) { for (var i = 1; i <= rangeFields.Count; i++) { var field = rangeFields[i]; WordConverter.updateField(field, word, filename); Converter.releaseCOMObject(field); } } Converter.releaseCOMObject(rangeFields); }
/// <summary> /// Convert a Word file to PDF /// </summary> /// <param name="inputFile">Full path of the input Word file</param> /// <param name="outputFile">Full path of the output PDF</param> /// <returns></returns> public static new int Convert(String inputFile, String outputFile, Hashtable options) { Boolean running = (Boolean)options["noquit"]; Application word = null; object oMissing = System.Reflection.Missing.Value; Template tmpl; String temporaryStorageDir = null; float wordVersion = 0; List <AppOption> wordOptionList = new List <AppOption>(); try { String filename = (String)inputFile; Boolean hasSignatures = WordConverter.HasDigitalSignatures(filename); Boolean visible = !(Boolean)options["hidden"]; Boolean openAndRepair = !(Boolean)options["word_no_repair"]; Boolean nowrite = (Boolean)options["readonly"]; Boolean includeProps = !(Boolean)options["excludeprops"]; Boolean includeTags = !(Boolean)options["excludetags"]; Boolean bitmapMissingFonts = !(Boolean)options["word_ref_fonts"]; Boolean autosave = options.ContainsKey("IsTempWord") && (Boolean)options["IsTempWord"]; bool pdfa = (Boolean)options["pdfa"] ? true : false; String writePassword = ""; String readPassword = ""; int maxPages = 0; WdExportOptimizeFor quality = WdExportOptimizeFor.wdExportOptimizeForPrint; WdExportItem showMarkup = WdExportItem.wdExportDocumentContent; WdExportCreateBookmarks bookmarks = (Boolean)options["bookmarks"] ? WdExportCreateBookmarks.wdExportCreateHeadingBookmarks : WdExportCreateBookmarks.wdExportCreateNoBookmarks; Options wdOptions = null; Documents documents = null; Template normalTemplate = null; tmpl = null; try { word = (Microsoft.Office.Interop.Word.Application)Marshal.GetActiveObject("Word.Application"); } catch (System.Exception) { int tries = 10; word = new Microsoft.Office.Interop.Word.Application(); running = false; while (tries > 0) { try { // Try to set a property on the object word.ScreenUpdating = false; } catch (COMException) { // Decrement the number of tries and have a bit of a snooze tries--; Thread.Sleep(500); continue; } // Looks ok, so bail out of the loop break; } if (tries == 0) { ReleaseCOMObject(word); return((int)ExitCode.ApplicationError); } } wdOptions = word.Options; word.DisplayAlerts = WdAlertLevel.wdAlertsNone; // Issue #48 - we should allow control over whether the history is lost if (!(Boolean)options["word_keep_history"]) { word.DisplayRecentFiles = false; } word.DisplayDocumentInformationPanel = false; word.FeatureInstall = Microsoft.Office.Core.MsoFeatureInstall.msoFeatureInstallNone; wordVersion = (float)System.Convert.ToDecimal(word.Version, new CultureInfo("en-US")); // Set the Word options in a way that allows us to reset the options when we finish try { wordOptionList.Add(new AppOption("AlertIfNotDefault", false, ref wdOptions)); wordOptionList.Add(new AppOption("AllowReadingMode", false, ref wdOptions)); wordOptionList.Add(new AppOption("PrecisePositioning", true, ref wdOptions)); wordOptionList.Add(new AppOption("UpdateFieldsAtPrint", false, ref wdOptions)); wordOptionList.Add(new AppOption("UpdateLinksAtPrint", false, ref wdOptions)); wordOptionList.Add(new AppOption("UpdateLinksAtOpen", false, ref wdOptions)); wordOptionList.Add(new AppOption("UpdateFieldsWithTrackedChangesAtPrint", false, ref wdOptions)); wordOptionList.Add(new AppOption("WarnBeforeSavingPrintingSendingMarkup", false, ref wdOptions)); wordOptionList.Add(new AppOption("BackgroundSave", true, ref wdOptions)); wordOptionList.Add(new AppOption("SavePropertiesPrompt", false, ref wdOptions)); wordOptionList.Add(new AppOption("DoNotPromptForConvert", true, ref wdOptions)); wordOptionList.Add(new AppOption("PromptUpdateStyle", false, ref wdOptions)); wordOptionList.Add(new AppOption("ConfirmConversions", false, ref wdOptions)); wordOptionList.Add(new AppOption("CheckGrammarAsYouType", false, ref wdOptions)); wordOptionList.Add(new AppOption("CheckGrammarWithSpelling", false, ref wdOptions)); wordOptionList.Add(new AppOption("CheckSpellingAsYouType", false, ref wdOptions)); wordOptionList.Add(new AppOption("DisplaySmartTagButtons", false, ref wdOptions)); wordOptionList.Add(new AppOption("EnableLivePreview", false, ref wdOptions)); wordOptionList.Add(new AppOption("ShowReadabilityStatistics", false, ref wdOptions)); wordOptionList.Add(new AppOption("SuggestSpellingCorrections", false, ref wdOptions)); wordOptionList.Add(new AppOption("AllowDragAndDrop", false, ref wdOptions)); wordOptionList.Add(new AppOption("EnableMisusedWordsDictionary", false, ref wdOptions)); wordOptionList.Add(new AppOption("ShowFormatError", false, ref wdOptions)); wordOptionList.Add(new AppOption("StoreRSIDOnSave", false, ref wdOptions)); wordOptionList.Add(new AppOption("SaveNormalPrompt", false, ref wdOptions)); wordOptionList.Add(new AppOption("AllowFastSave", false, ref wdOptions)); wordOptionList.Add(new AppOption("BackgroundOpen", false, ref wdOptions)); wordOptionList.Add(new AppOption("ShowMarkupOpenSave", false, ref wdOptions)); wordOptionList.Add(new AppOption("SaveInterval", 0, ref wdOptions)); } catch (SystemException) { } // Set up the PDF output quality if ((Boolean)options["print"]) { quality = WdExportOptimizeFor.wdExportOptimizeForPrint; } if ((Boolean)options["screen"]) { quality = WdExportOptimizeFor.wdExportOptimizeForOnScreen; } if ((Boolean)options["markup"]) { showMarkup = WdExportItem.wdExportDocumentWithMarkup; } if (!String.IsNullOrEmpty((String)options["password"])) { readPassword = (String)options["password"]; } if (!String.IsNullOrEmpty((String)options["writepassword"])) { writePassword = (String)options["writepassword"]; } // Large Word files may simply not print reliably - if the word_max_pages // configuration option is set, then we must close up and forget about // converting the file. maxPages = (int)options[@"word_max_pages"]; documents = word.Documents; normalTemplate = word.NormalTemplate; // Check for password protection and no password if (IsPasswordProtected(inputFile) && String.IsNullOrEmpty(readPassword)) { normalTemplate.Saved = true; Console.WriteLine("Unable to open password protected file"); return((int)ExitCode.PasswordFailure); } // If we are opening a document with a write password and no read password, and // we are not in read only mode, we should follow the document properties and // enforce a read only open. If we do not, Word pops up a dialog if (!nowrite && String.IsNullOrEmpty(writePassword) && IsReadOnlyEnforced(inputFile)) { nowrite = true; } // Having signatures means we should open the document very carefully if (hasSignatures) { nowrite = true; autosave = false; openAndRepair = false; } Document doc = null; try { if ((bool)options["merge"] && !String.IsNullOrEmpty((string)options["template"]) && File.Exists((string)options["template"]) && System.Text.RegularExpressions.Regex.IsMatch((string)options["template"], @"^.*\.dot[mx]?$", System.Text.RegularExpressions.RegexOptions.IgnoreCase)) { // Create a new document based on a template doc = documents.Add((string)options["template"]); Object rStart = 0; Object rEnd = 0; Range range = doc.Range(rStart, rEnd); range.InsertFile(inputFile); ReleaseCOMObject(range); // Make sure we save the file with the original filename so // filename fields update correctly temporaryStorageDir = Path.GetTempFileName(); File.Delete(temporaryStorageDir); Directory.CreateDirectory(temporaryStorageDir); doc.SaveAs(Path.Combine(temporaryStorageDir, Path.GetFileName(inputFile))); } else { // Open the source document doc = documents.OpenNoRepairDialog(FileName: filename, ReadOnly: nowrite, PasswordDocument: readPassword, WritePasswordDocument: writePassword, Visible: visible, OpenAndRepair: openAndRepair); } } catch (COMException) { Console.WriteLine("Unable to open file"); return((int)ExitCode.FileOpenFailure); } // Check if there are signatures in the document which changes how we do things if (hasSignatures) { // Add in a delay to allow signatures to load Thread.Sleep(500); } else { Window docWin = null; View docWinView = null; doc.Activate(); // Check if there are too many pages if (maxPages > 0) { var pageCount = doc.ComputeStatistics(WdStatistic.wdStatisticPages, false); doc.Saved = true; if (pageCount > maxPages) { throw new Exception(String.Format("Too many pages to process ({0}). More than {1}", pageCount, maxPages)); } } // Prevent "property not available" errors, see http://blogs.msmvps.com/wordmeister/2013/02/22/word2013bug-not-available-for-reading/ docWin = doc.ActiveWindow; docWinView = docWin.View; if (wordVersion >= 15) { docWinView.ReadingLayout = false; } // Sometimes the print view will not be available (e.g. for a blog post) // Try and switch view try { docWinView.Type = WdViewType.wdPrintPreview; } catch (Exception) { } // Hide comments try { word.PrintPreview = false; docWinView.RevisionsView = WdRevisionsView.wdRevisionsViewFinal; docWinView.ShowRevisionsAndComments = false; docWinView.ShowComments = false; docWinView.ShowFormatChanges = false; docWinView.ShowInkAnnotations = false; docWinView.ShowInsertionsAndDeletions = false; } catch (SystemException e) { Console.WriteLine("Failed to set revision settings {0}", e.Message); } // Try to avoid Word thinking any changes are happening to the document doc.SpellingChecked = true; doc.GrammarChecked = true; // Changing these properties may be disallowed if the document is protected // and is not signed if (doc.ProtectionType == WdProtectionType.wdNoProtection && !hasSignatures) { if (autosave) { doc.Save(); doc.Saved = true; } doc.TrackMoves = false; doc.TrackRevisions = false; doc.TrackFormatting = false; if ((Boolean)options["word_fix_table_columns"]) { FixWordTableColumnWidths(doc); } } normalTemplate.Saved = true; // Hide the document window if need be if ((Boolean)options["hidden"]) { var activeWin = word.ActiveWindow; activeWin.Visible = false; activeWin.WindowState = WdWindowState.wdWindowStateMinimize; ReleaseCOMObject(activeWin); } // Check if we have a template file to apply to this document // The template must be a file and must end in .dot, .dotx or .dotm if (!String.IsNullOrEmpty((String)options["template"]) && !(bool)options["merge"]) { string template = (string)options["template"]; if (File.Exists(template) && System.Text.RegularExpressions.Regex.IsMatch(template, @"^.*\.dot[mx]?$")) { doc.set_AttachedTemplate(template); doc.UpdateStyles(); tmpl = doc.get_AttachedTemplate(); } else { Console.WriteLine("Invalid template '{0}'", template); } } // See if we have to update fields if (!(Boolean)options["word_no_field_update"]) { UpdateDocumentFields(doc, word, inputFile, options); } var pageSetup = doc.PageSetup; if ((float)options["word_header_dist"] >= 0) { pageSetup.HeaderDistance = (float)options["word_header_dist"]; } if ((float)options["word_footer_dist"] >= 0) { pageSetup.FooterDistance = (float)options["word_footer_dist"]; } ReleaseCOMObject(pageSetup); try { // Make sure we are not in a header footer view docWinView.SeekView = WdSeekView.wdSeekPrimaryHeader; docWinView.SeekView = WdSeekView.wdSeekPrimaryFooter; docWinView.SeekView = WdSeekView.wdSeekMainDocument; } catch (Exception) { // We might fail when switching views } normalTemplate.Saved = true; if (autosave) { doc.Save(); } doc.Saved = true; ReleaseCOMObject(docWinView); ReleaseCOMObject(docWin); } // Set up a delegate function if we're using a printer PrintDocument printFunc = delegate(string destination, string printerName) { word.ActivePrinter = printerName; doc.PrintOut(Background: false, OutputFileName: destination); }; if (String.IsNullOrEmpty((string)options["printer"])) { // No printer given, so export try { doc.ExportAsFixedFormat(outputFile, WdExportFormat.wdExportFormatPDF, false, quality, WdExportRange.wdExportAllDocument, 1, 1, showMarkup, includeProps, true, bookmarks, includeTags, bitmapMissingFonts, pdfa); } catch (Exception) { // Couldn't export, so see if there is a fallback printer if (!String.IsNullOrEmpty((string)options["fallback_printer"])) { PrintToGhostscript((string)options["fallback_printer"], outputFile, printFunc); } else { throw; } } } else { PrintToGhostscript((string)options["printer"], outputFile, printFunc); } if (tmpl != null) { tmpl.Saved = true; } object saveChanges = autosave? WdSaveOptions.wdSaveChanges : WdSaveOptions.wdDoNotSaveChanges; if (nowrite) { doc.Saved = true; } normalTemplate.Saved = true; ((_Document)doc).Close(ref saveChanges, ref oMissing, ref oMissing); // Reset options foreach (AppOption opt in wordOptionList) { opt.ResetValue(ref wdOptions); } ReleaseCOMObject(wdOptions); ReleaseCOMObject(documents); ReleaseCOMObject(doc); ReleaseCOMObject(tmpl); ReleaseCOMObject(normalTemplate); return((int)ExitCode.Success); } catch (Exception e) { Console.WriteLine(e.Message); return((int)ExitCode.UnknownError); } finally { if (temporaryStorageDir != null && Directory.Exists(temporaryStorageDir)) { try { if (File.Exists(Path.Combine(temporaryStorageDir, Path.GetFileName(inputFile)))) { File.Delete(Path.Combine(temporaryStorageDir, Path.GetFileName(inputFile))); } Directory.Delete(temporaryStorageDir); } catch (Exception) { } } if (word != null && !running) { CloseWordApplication(word); } ReleaseCOMObject(word); } }
private static void updateDocumentFields(Document doc, Microsoft.Office.Interop.Word.Application word, String inputFile, Hashtable options) { // Update fields quickly if it is safe to do so. We have // to check for broken links as they may raise Word dialogs if ((Boolean)options["word_field_quick_update"] || ((Boolean)options["word_field_quick_update_safe"] && !hasBrokenLinks(doc))) { var fields = doc.Fields; fields.Update(); Converter.releaseCOMObject(fields); return; } try { // Update some of the field types in the document so the printed // PDF looks correct. Skips some field types (such as ASK) that would // create dialogs foreach (Microsoft.Office.Interop.Word.Section section in doc.Sections) { var sectionRange = section.Range; var sectionFields = sectionRange.Fields; var zeroHeader = true; var zeroFooter = true; foreach (Field sectionField in sectionFields) { WordConverter.updateField(sectionField, word, inputFile); } var sectionPageSetup = section.PageSetup; var headers = section.Headers; foreach (Microsoft.Office.Interop.Word.HeaderFooter header in headers) { if (header.Exists) { var range = header.Range; var rangeFields = range.Fields; foreach (Field rangeField in rangeFields) { WordConverter.updateField(rangeField, word, inputFile); } // Simply querying the range of the header will create it. // If the header is empty, this can introduce additional space // between the non-existant header and the top of the page. // To counter this for empty headers, we manually set the header // distance to zero here var shapes = header.Shapes; var rangeShapes = range.ShapeRange; if ((shapes.Count > 0) || !String.IsNullOrWhiteSpace(range.Text) || (rangeShapes.Count > 0)) { zeroHeader = false; } Converter.releaseCOMObject(shapes); Converter.releaseCOMObject(rangeShapes); Converter.releaseCOMObject(rangeFields); Converter.releaseCOMObject(range); } } var footers = section.Footers; foreach (Microsoft.Office.Interop.Word.HeaderFooter footer in footers) { if (footer.Exists) { var range = footer.Range; var rangeFields = range.Fields; foreach (Field rangeField in rangeFields) { WordConverter.updateField(rangeField, word, inputFile); } // Simply querying the range of the footer will create it. // If the footer is empty, this can introduce additional space // between the non-existant footer and the bottom of the page. // To counter this for empty footers, we manually set the footer // distance to zero here var shapes = footer.Shapes; var rangeShapes = range.ShapeRange; if (shapes.Count > 0 || !String.IsNullOrWhiteSpace(range.Text) || rangeShapes.Count > 0) { zeroFooter = false; } Converter.releaseCOMObject(shapes); Converter.releaseCOMObject(rangeShapes); Converter.releaseCOMObject(rangeFields); Converter.releaseCOMObject(range); } } if (doc.ProtectionType == WdProtectionType.wdNoProtection) { if (zeroHeader) { sectionPageSetup.HeaderDistance = 0; } if (zeroFooter) { sectionPageSetup.FooterDistance = 0; } } Converter.releaseCOMObject(sectionFields); Converter.releaseCOMObject(sectionRange); Converter.releaseCOMObject(headers); Converter.releaseCOMObject(footers); Converter.releaseCOMObject(sectionPageSetup); } } catch (COMException) { // There can be odd errors when column widths are out of the page boundaries // See github issue #14 } var docFields = doc.Fields; foreach (Field docField in docFields) { WordConverter.updateField(docField, word, inputFile); } var storyRanges = doc.StoryRanges; foreach (Range range in storyRanges) { var rangeFields = range.Fields; foreach (Field field in rangeFields) { WordConverter.updateField(field, word, inputFile); } Converter.releaseCOMObject(rangeFields); } Converter.releaseCOMObject(storyRanges); Converter.releaseCOMObject(docFields); }
public static new int Convert(String inputFile, String outputFile, Hashtable options) { Boolean running = (Boolean)options["noquit"]; Microsoft.Office.Interop.Outlook.Application app = null; String tmpDocFile = null; try { try { app = (Microsoft.Office.Interop.Outlook.Application)Marshal.GetActiveObject("Outlook.Application"); } catch (System.Exception) { app = new Microsoft.Office.Interop.Outlook.Application(); running = false; } if (app == null) { Console.WriteLine("Unable to start outlook instance"); return((int)ExitCode.ApplicationError); } var session = app.Session; FileInfo fi = new FileInfo(inputFile); // Create a temporary doc file from the message tmpDocFile = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".doc"; switch (fi.Extension.ToLower()) { case ".msg": var message = (MailItem)session.OpenSharedItem(inputFile); if (message == null) { Converter.releaseCOMObject(message); Converter.releaseCOMObject(session); return((int)ExitCode.FileOpenFailure); } message.SaveAs(tmpDocFile, Microsoft.Office.Interop.Outlook.OlSaveAsType.olDoc); ((_MailItem)message).Close(OlInspectorClose.olDiscard); Converter.releaseCOMObject(message); Converter.releaseCOMObject(session); break; case ".vcf": var contact = (ContactItem)session.OpenSharedItem(inputFile); if (contact == null) { Converter.releaseCOMObject(contact); Converter.releaseCOMObject(session); return((int)ExitCode.FileOpenFailure); } contact.SaveAs(tmpDocFile, Microsoft.Office.Interop.Outlook.OlSaveAsType.olDoc); Converter.releaseCOMObject(contact); Converter.releaseCOMObject(session); break; case ".ics": // Issue #47 - there is a problem opening some ics files - looks like the issue is down to // it trying to open the icalendar format // See https://msdn.microsoft.com/en-us/library/office/bb644609.aspx object item = null; try { session.GetDefaultFolder(OlDefaultFolders.olFolderCalendar); item = session.OpenSharedItem(inputFile); } catch { } if (item != null) { // We were able to read in the item // See if it is an item that can be converted to an intermediate Word document string itemType = (string)(string)item.GetType().InvokeMember("MessageClass", System.Reflection.BindingFlags.GetProperty, null, item, null); switch (itemType) { case "IPM.Appointment": var appointment = (AppointmentItem)item; if (appointment != null) { appointment.SaveAs(tmpDocFile, Microsoft.Office.Interop.Outlook.OlSaveAsType.olDoc); Converter.releaseCOMObject(appointment); } break; case "IPM.Schedule.Meeting.Request": var meeting = (MeetingItem)item; if (meeting != null) { meeting.SaveAs(tmpDocFile, Microsoft.Office.Interop.Outlook.OlSaveAsType.olDoc); Converter.releaseCOMObject(meeting); } break; case "IPM.Task": var task = (TaskItem)item; if (task != null) { task.SaveAs(tmpDocFile, Microsoft.Office.Interop.Outlook.OlSaveAsType.olDoc); Converter.releaseCOMObject(task); } break; default: Console.WriteLine("Unable to convert ICS type " + itemType); break; } Converter.releaseCOMObject(item); } else { Console.WriteLine("Unable to convert this type of ICS file"); } Converter.releaseCOMObject(session); break; } if (!File.Exists(tmpDocFile)) { return((int)ExitCode.UnknownError); } // Convert the doc file to a PDF options["IsTempWord"] = true; return(WordConverter.Convert(tmpDocFile, outputFile, options)); } catch (System.Exception e) { Console.WriteLine(e.Message); return((int)ExitCode.UnknownError); } finally { if (tmpDocFile != null && File.Exists(tmpDocFile)) { try { System.IO.File.Delete(tmpDocFile); } catch (System.Exception) { } } // If we were not already running, quit and release the outlook object if (app != null && !running) { ((Microsoft.Office.Interop.Outlook._Application)app).Quit(); } Converter.releaseCOMObject(app); } }
// Update all the fields in a document private static void updateDocumentFields(Microsoft.Office.Interop.Word.Document doc, Microsoft.Office.Interop.Word.Application word, String inputFile, Hashtable options) { // Update fields quickly if it is safe to do so. We have // to check for broken links as they may raise Word dialogs or leave broken content if ((Boolean)options["word_field_quick_update"] || ((Boolean)options["word_field_quick_update_safe"] && !hasBrokenLinks(doc))) { var fields = doc.Fields; fields.Update(); Converter.releaseCOMObject(fields); return; } try { // Update some of the field types in the document so the printed // PDF looks correct. Skips some field types (such as ASK) that would // create dialogs var docSections = doc.Sections; if (docSections.Count > 0) { for (var dsi = 1; dsi <= docSections.Count; dsi++) { var section = docSections[dsi]; var sectionRange = section.Range; var sectionFields = sectionRange.Fields; var headers = section.Headers; var footers = section.Footers; if (sectionFields.Count > 0) { for (var si = 1; si <= sectionFields.Count; si++) { var sectionField = sectionFields[si]; WordConverter.updateField(sectionField, word, inputFile); Converter.releaseCOMObject(sectionField); } } updateHeaderFooterFields(headers, word, inputFile); updateHeaderFooterFields(footers, word, inputFile); Converter.releaseCOMObject(footers); Converter.releaseCOMObject(headers); Converter.releaseCOMObject(sectionFields); Converter.releaseCOMObject(sectionRange); Converter.releaseCOMObject(section); } } Converter.releaseCOMObject(docSections); } catch (COMException) { // There can be odd errors when column widths are out of the page boundaries // See github issue #14 } var docFields = doc.Fields; var storyRanges = doc.StoryRanges; if (docFields.Count > 0) { for (var fi = 1; fi <= docFields.Count; fi++) { var docField = docFields[fi]; WordConverter.updateField(docField, word, inputFile); Converter.releaseCOMObject(docField); } } foreach (Range range in storyRanges) { updateFieldsInRange(range, word, inputFile); Converter.releaseCOMObject(range); } Converter.releaseCOMObject(storyRanges); Converter.releaseCOMObject(docFields); }
/// <summary> /// Convert a Word file to PDF /// </summary> /// <param name="inputFile">Full path of the input Word file</param> /// <param name="outputFile">Full path of the output PDF</param> /// <returns></returns> public static new int Convert(String inputFile, String outputFile, Hashtable options) { Boolean running = (Boolean)options["noquit"]; Microsoft.Office.Interop.Word.Application word = null; object oMissing = System.Reflection.Missing.Value; Microsoft.Office.Interop.Word.Template tmpl; String temporaryStorageDir = null; try { tmpl = null; try { word = (Microsoft.Office.Interop.Word.Application)Marshal.GetActiveObject("Word.Application"); } catch (System.Exception) { word = new Microsoft.Office.Interop.Word.Application(); running = false; } word.DisplayAlerts = WdAlertLevel.wdAlertsNone; word.DisplayRecentFiles = false; word.DisplayDocumentInformationPanel = false; word.FeatureInstall = Microsoft.Office.Core.MsoFeatureInstall.msoFeatureInstallNone; var wdOptions = word.Options; try { wdOptions.UpdateFieldsAtPrint = false; wdOptions.UpdateLinksAtPrint = false; wdOptions.WarnBeforeSavingPrintingSendingMarkup = false; wdOptions.BackgroundSave = true; wdOptions.SavePropertiesPrompt = false; wdOptions.DoNotPromptForConvert = true; wdOptions.PromptUpdateStyle = false; wdOptions.ConfirmConversions = false; wdOptions.CheckGrammarAsYouType = false; wdOptions.CheckGrammarWithSpelling = false; wdOptions.CheckSpellingAsYouType = false; wdOptions.DisplaySmartTagButtons = false; wdOptions.EnableLivePreview = false; wdOptions.ShowReadabilityStatistics = false; wdOptions.SuggestSpellingCorrections = false; wdOptions.AllowDragAndDrop = false; wdOptions.EnableMisusedWordsDictionary = false; } catch (SystemException) { } Object filename = (Object)inputFile; Boolean visible = !(Boolean)options["hidden"]; Boolean nowrite = (Boolean)options["readonly"]; Boolean includeProps = !(Boolean)options["excludeprops"]; Boolean includeTags = !(Boolean)options["excludetags"]; bool pdfa = (Boolean)options["pdfa"] ? true : false; WdExportOptimizeFor quality = WdExportOptimizeFor.wdExportOptimizeForPrint; if ((Boolean)options["print"]) { quality = WdExportOptimizeFor.wdExportOptimizeForPrint; } if ((Boolean)options["screen"]) { quality = WdExportOptimizeFor.wdExportOptimizeForOnScreen; } WdExportCreateBookmarks bookmarks = (Boolean)options["bookmarks"] ? WdExportCreateBookmarks.wdExportCreateHeadingBookmarks : WdExportCreateBookmarks.wdExportCreateNoBookmarks; WdExportItem showMarkup = WdExportItem.wdExportDocumentContent; if ((Boolean)options["markup"]) { showMarkup = WdExportItem.wdExportDocumentWithMarkup; } var documents = word.Documents; var normalTemplate = word.NormalTemplate; String readPassword = ""; if (!String.IsNullOrEmpty((String)options["password"])) { readPassword = (String)options["password"]; } Object oReadPass = (Object)readPassword; String writePassword = ""; if (!String.IsNullOrEmpty((String)options["writepassword"])) { writePassword = (String)options["writepassword"]; } Object oWritePass = (Object)writePassword; // Check for password protection and no password if (Converter.IsPasswordProtected(inputFile) && String.IsNullOrEmpty(readPassword)) { normalTemplate.Saved = true; Console.WriteLine("Unable to open password protected file"); return((int)ExitCode.PasswordFailure); } Document doc = null; try { if ((bool)options["merge"] && !String.IsNullOrEmpty((string)options["template"]) && File.Exists((string)options["template"]) && System.Text.RegularExpressions.Regex.IsMatch((string)options["template"], @"^.*\.dot[mx]?$")) { // Create a new document based on a template doc = documents.Add((string)options["template"]); Object rStart = 0; Object rEnd = 0; Range range = doc.Range(rStart, rEnd); range.InsertFile(inputFile); Converter.ReleaseCOMObject(range); // Make sure we save the file with the original filename so // filename fields update correctly temporaryStorageDir = Path.GetTempFileName(); File.Delete(temporaryStorageDir); Directory.CreateDirectory(temporaryStorageDir); doc.SaveAs(Path.Combine(temporaryStorageDir, Path.GetFileName(inputFile))); } else { // Open the source document doc = documents.OpenNoRepairDialog(ref filename, ref oMissing, nowrite, ref oMissing, ref oReadPass, ref oMissing, ref oMissing, ref oWritePass, ref oMissing, ref oMissing, ref oMissing, visible, true, ref oMissing, ref oMissing, ref oMissing); } } catch (System.Runtime.InteropServices.COMException) { Console.WriteLine("Unable to open file"); return((int)ExitCode.FileOpenFailure); } doc.Activate(); // Prevent "property not available" errors, see http://blogs.msmvps.com/wordmeister/2013/02/22/word2013bug-not-available-for-reading/ var docWin = doc.ActiveWindow; var docWinView = docWin.View; docWinView.Type = WdViewType.wdPrintPreview; // Try to avoid Word thinking any changes are happening to the document doc.SpellingChecked = true; doc.GrammarChecked = true; // Changing these properties may be disallowed if the document is protected if (doc.ProtectionType == WdProtectionType.wdNoProtection) { doc.TrackMoves = false; doc.TrackRevisions = false; doc.TrackFormatting = false; } normalTemplate.Saved = true; // Hide the document window if need be if ((Boolean)options["hidden"]) { var activeWin = word.ActiveWindow; activeWin.Visible = false; activeWin.WindowState = WdWindowState.wdWindowStateMinimize; Converter.ReleaseCOMObject(activeWin); } // Check if we have a template file to apply to this document // The template must be a file and must end in .dot, .dotx or .dotm if (!String.IsNullOrEmpty((String)options["template"]) && !(bool)options["merge"]) { string template = (string)options["template"]; if (File.Exists(template) && System.Text.RegularExpressions.Regex.IsMatch(template, @"^.*\.dot[mx]?$")) { doc.set_AttachedTemplate(template); doc.UpdateStyles(); tmpl = (Microsoft.Office.Interop.Word.Template)doc.get_AttachedTemplate(); } else { Console.WriteLine("Invalid template '{0}'", template); } } // Update some of the field types in the document so the printed // PDF looks correct. Skips some field types (such as ASK) that would // create dialogs foreach (Microsoft.Office.Interop.Word.Section section in doc.Sections) { var sectionRange = section.Range; var sectionFields = sectionRange.Fields; foreach (Field sectionField in sectionFields) { WordConverter.UpdateField(sectionField, word, inputFile); } var sectionPageSetup = section.PageSetup; var headers = section.Headers; foreach (Microsoft.Office.Interop.Word.HeaderFooter header in headers) { if (header.Exists) { var range = header.Range; var rangeFields = range.Fields; foreach (Field rangeField in rangeFields) { WordConverter.UpdateField(rangeField, word, inputFile); } // Simply querying the range of the header will create it. // If the header is empty, this can introduce additional space // between the non-existant header and the top of the page. // To counter this for empty footers, we manually set the header // distance to zero here var shapes = header.Shapes; if (shapes.Count == 0) { sectionPageSetup.HeaderDistance = 0; } Converter.ReleaseCOMObject(shapes); Converter.ReleaseCOMObject(rangeFields); Converter.ReleaseCOMObject(range); } } var footers = section.Footers; foreach (Microsoft.Office.Interop.Word.HeaderFooter footer in footers) { if (footer.Exists) { var range = footer.Range; var rangeFields = range.Fields; foreach (Field rangeField in rangeFields) { WordConverter.UpdateField(rangeField, word, inputFile); } // Simply querying the range of the footer will create it. // If the footer is empty, this can introduce additional space // between the non-existant footer and the bottom of the page. // To counter this for empty footers, we manually set the footer // distance to zero here var shapes = footer.Shapes; if (shapes.Count == 0) { sectionPageSetup.FooterDistance = 0; } Converter.ReleaseCOMObject(shapes); Converter.ReleaseCOMObject(rangeFields); Converter.ReleaseCOMObject(range); } } Converter.ReleaseCOMObject(sectionFields); Converter.ReleaseCOMObject(sectionRange); Converter.ReleaseCOMObject(headers); Converter.ReleaseCOMObject(footers); Converter.ReleaseCOMObject(sectionPageSetup); } var docFields = doc.Fields; foreach (Field docField in docFields) { WordConverter.UpdateField(docField, word, inputFile); } var storyRanges = doc.StoryRanges; foreach (Range range in storyRanges) { var rangeFields = range.Fields; foreach (Field field in rangeFields) { WordConverter.UpdateField(field, word, inputFile); } Converter.ReleaseCOMObject(rangeFields); } Converter.ReleaseCOMObject(storyRanges); Converter.ReleaseCOMObject(docFields); var pageSetup = doc.PageSetup; if ((float)options["word_header_dist"] >= 0) { pageSetup.HeaderDistance = (float)options["word_header_dist"]; } if ((float)options["word_footer_dist"] >= 0) { pageSetup.FooterDistance = (float)options["word_footer_dist"]; } normalTemplate.Saved = true; doc.Saved = true; doc.ExportAsFixedFormat(outputFile, WdExportFormat.wdExportFormatPDF, false, quality, WdExportRange.wdExportAllDocument, 1, 1, showMarkup, includeProps, true, bookmarks, includeTags, true, pdfa); if (tmpl != null) { tmpl.Saved = true; } object saveChanges = WdSaveOptions.wdDoNotSaveChanges; if (nowrite) { doc.Saved = true; } normalTemplate.Saved = true; ((_Document)doc).Close(ref saveChanges, ref oMissing, ref oMissing); Converter.ReleaseCOMObject(pageSetup); Converter.ReleaseCOMObject(docWinView); Converter.ReleaseCOMObject(docWin); Converter.ReleaseCOMObject(wdOptions); Converter.ReleaseCOMObject(documents); Converter.ReleaseCOMObject(doc); Converter.ReleaseCOMObject(tmpl); Converter.ReleaseCOMObject(normalTemplate); return((int)ExitCode.Success); } catch (Exception e) { Console.WriteLine(e.Message); return((int)ExitCode.UnknownError); } finally { if (temporaryStorageDir != null && Directory.Exists(temporaryStorageDir)) { if (File.Exists(Path.Combine(temporaryStorageDir, Path.GetFileName(inputFile)))) { File.Delete(Path.Combine(temporaryStorageDir, Path.GetFileName(inputFile))); } Directory.Delete(temporaryStorageDir); } if (word != null && !running) { ((_Application)word).Quit(ref oMissing, ref oMissing, ref oMissing); } Converter.ReleaseCOMObject(word); } }
static void Main(string[] args) { string[] files = new string[2]; int filesSeen = 0; Boolean postProcessPDF = false; Boolean postProcessPDFSecurity = false; Hashtable options = new Hashtable(); List <PDFBookmark> documentBookmarks = new List <PDFBookmark>(); // Loop through the input, grabbing switches off the command line options["hidden"] = false; options["markup"] = false; options["readonly"] = false; options["bookmarks"] = false; options["print"] = true; options["screen"] = false; options["pdfa"] = false; options["verbose"] = false; options["excludeprops"] = false; options["excludetags"] = false; options["noquit"] = false; options["merge"] = false; options["template"] = ""; options["password"] = ""; options["excel_show_formulas"] = false; options["excel_show_headings"] = false; options["excel_auto_macros"] = false; options["excel_template_macros"] = false; options["excel_active_sheet"] = false; options["excel_no_link_update"] = false; options["excel_no_recalculate"] = false; options["excel_max_rows"] = (int)0; options["excel_worksheet"] = (int)0; options["word_field_quick_update"] = false; options["word_field_quick_update_safe"] = false; options["word_no_field_update"] = false; options["word_header_dist"] = (float)-1; options["word_footer_dist"] = (float)-1; options["word_max_pages"] = (int)0; options["word_ref_fonts"] = false; options["word_keep_history"] = false; options["original_filename"] = ""; options["original_basename"] = ""; options["pdf_page_mode"] = null; options["pdf_layout"] = null; options["pdf_merge"] = (int)MergeMode.None; options["pdf_clean_meta"] = (int)MetaClean.None; options["pdf_owner_pass"] = ""; options["pdf_user_pass"] = ""; options["pdf_restrict_annotation"] = false; options["pdf_restrict_extraction"] = false; options["pdf_restrict_assembly"] = false; options["pdf_restrict_forms"] = false; options["pdf_restrict_modify"] = false; options["pdf_restrict_print"] = false; options["pdf_restrict_annotation"] = false; options["pdf_restrict_accessibility_extraction"] = false; options["pdf_restrict_full_quality"] = false; Regex switches = new Regex(@"^/(version|hidden|markup|readonly|bookmarks|merge|noquit|print|screen|pdfa|template|writepassword|password|help|verbose|exclude(props|tags)|excel_(max_rows|show_formulas|show_headings|auto_macros|template_macros|active_sheet|worksheet|no_recalculate|no_link_update)|word_(header_dist|footer_dist|ref_fonts|no_field_update|field_quick_update(_safe)?|max_pages|keep_history)|pdf_(page_mode|append|prepend|layout|clean_meta|owner_pass|user_pass|restrict_(annotation|extraction|assembly|forms|modify|print|accessibility_extraction|full_quality))|\?)$", RegexOptions.IgnoreCase); for (int argIdx = 0; argIdx < args.Length; argIdx++) { string item = args[argIdx]; // see if this starts with a / Match m = Regex.Match(item, @"^/"); if (m.Success) { // This is an option Match itemMatch = switches.Match(item); if (itemMatch.Success) { if (itemMatch.Groups[1].Value.ToLower().Equals("help") || itemMatch.Groups[1].Value.Equals("?")) { showHelp(); } switch (itemMatch.Groups[1].Value.ToLower()) { case "pdf_page_mode": if (argIdx + 2 < args.Length) { postProcessPDF = true; var pageMode = args[argIdx + 1]; pageMode = pageMode.ToLower(); switch (pageMode) { case "full": options["pdf_page_mode"] = PdfPageMode.FullScreen; break; case "none": options["pdf_page_mode"] = PdfPageMode.UseNone; break; case "bookmarks": options["pdf_page_mode"] = PdfPageMode.UseOutlines; break; case "thumbs": options["pdf_page_mode"] = PdfPageMode.UseThumbs; break; default: Console.WriteLine("Invalid PDF page mode ({0}). It must be one of full, none, outline or thumbs", args[argIdx + 1]); Environment.Exit((int)(ExitCode.Failed | ExitCode.InvalidArguments)); break; } argIdx++; } break; case "pdf_clean_meta": if (argIdx + 2 < args.Length) { postProcessPDF = true; var cleanType = args[argIdx + 1]; cleanType = cleanType.ToLower(); switch (cleanType) { case "basic": options["pdf_clean_meta"] = MetaClean.Basic; break; case "full": options["pdf_clean_meta"] = MetaClean.Full; break; default: Console.WriteLine("Invalid PDF meta-data clean value ({0}). It must be one of full or basic", args[argIdx + 1]); Environment.Exit((int)(ExitCode.Failed | ExitCode.InvalidArguments)); break; } argIdx++; } break; case "pdf_layout": if (argIdx + 2 < args.Length) { postProcessPDF = true; var pdfLayout = args[argIdx + 1]; pdfLayout = pdfLayout.ToLower(); switch (pdfLayout) { case "onecol": options["pdf_layout"] = PdfPageLayout.OneColumn; break; case "single": options["pdf_layout"] = PdfPageLayout.SinglePage; break; case "twocolleft": options["pdf_layout"] = PdfPageLayout.TwoColumnLeft; break; case "twocolright": options["pdf_layout"] = PdfPageLayout.TwoColumnRight; break; case "twopageleft": options["pdf_layout"] = PdfPageLayout.TwoPageLeft; break; case "twopageright": options["pdf_layout"] = PdfPageLayout.TwoPageRight; break; default: Console.WriteLine("Invalid PDF layout ({0}). It must be one of onecol, single, twocolleft, twocolright, twopageleft or twopageright", args[argIdx + 1]); Environment.Exit((int)(ExitCode.Failed | ExitCode.InvalidArguments)); break; } argIdx++; } break; case "pdf_owner_pass": case "pdf_user_pass": if (argIdx + 2 < args.Length) { postProcessPDF = true; postProcessPDFSecurity = true; var pass = args[argIdx + 1]; // Set the password options[itemMatch.Groups[1].Value.ToLower()] = pass; argIdx++; } break; case "template": // Only accept the next option if there are enough options if (argIdx + 2 < args.Length) { if (File.Exists(args[argIdx + 1])) { FileInfo templateInfo = new FileInfo(args[argIdx + 1]); options[itemMatch.Groups[1].Value.ToLower()] = templateInfo.FullName; } else { Console.WriteLine("Unable to find {0} {1}", itemMatch.Groups[1].Value.ToLower(), args[argIdx + 1]); } argIdx++; } break; case "excel_max_rows": // Only accept the next option if there are enough options if (argIdx + 2 < args.Length) { if (Regex.IsMatch(args[argIdx + 1], @"^\d+$")) { options[itemMatch.Groups[1].Value.ToLower()] = (int)Convert.ToInt32(args[argIdx + 1]); } else { Console.WriteLine("Maximum number of rows ({0}) is invalid", args[argIdx + 1]); Environment.Exit((int)(ExitCode.Failed | ExitCode.InvalidArguments)); } argIdx++; } break; case "excel_worksheet": // Only accept the next option if there are enough options if (argIdx + 2 < args.Length) { if (Regex.IsMatch(args[argIdx + 1], @"^\d+$")) { options[itemMatch.Groups[1].Value.ToLower()] = (int)Convert.ToInt32(args[argIdx + 1]); } else { Console.WriteLine("Excel worksheet ({0}) is invalid", args[argIdx + 1]); Environment.Exit((int)(ExitCode.Failed | ExitCode.InvalidArguments)); } argIdx++; } break; case "word_header_dist": case "word_footer_dist": // Only accept the next option if there are enough options if (argIdx + 2 < args.Length) { if (Regex.IsMatch(args[argIdx + 1], @"^[\d\.]+$")) { try { options[itemMatch.Groups[1].Value.ToLower()] = (float)Convert.ToDouble(args[argIdx + 1]); } catch (Exception) { Console.WriteLine("Header/Footer distance ({0}) is invalid", args[argIdx + 1]); Environment.Exit((int)(ExitCode.Failed | ExitCode.InvalidArguments)); } } else { Console.WriteLine("Header/Footer distance ({0}) is invalid", args[argIdx + 1]); Environment.Exit((int)(ExitCode.Failed | ExitCode.InvalidArguments)); } argIdx++; } break; case "word_max_pages": // Only accept the next option if there are enough options if (argIdx + 2 < args.Length) { if (Regex.IsMatch(args[argIdx + 1], @"^\d+$")) { options[itemMatch.Groups[1].Value.ToLower()] = (int)Convert.ToInt32(args[argIdx + 1]); } else { Console.WriteLine("Maximum number of pages ({0}) is invalid", args[argIdx + 1]); Environment.Exit((int)(ExitCode.Failed | ExitCode.InvalidArguments)); } argIdx++; } break; case "password": case "writepassword": // Only accept the next option if there are enough options if (argIdx + 2 < args.Length) { options[itemMatch.Groups[1].Value.ToLower()] = args[argIdx + 1]; argIdx++; } break; case "screen": options["print"] = false; options[itemMatch.Groups[1].Value.ToLower()] = true; break; case "print": options["screen"] = false; options[itemMatch.Groups[1].Value.ToLower()] = true; break; case "version": Assembly asm = Assembly.GetExecutingAssembly(); FileVersionInfo fv = System.Diagnostics.FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location); Console.WriteLine(String.Format("{0}", fv.FileVersion)); Environment.Exit((int)ExitCode.Success); break; case "pdf_append": if ((MergeMode)options["pdf_merge"] != MergeMode.None) { Console.WriteLine("Only one of /pdf_append or /pdf_prepend can be used"); Environment.Exit((int)(ExitCode.Failed | ExitCode.InvalidArguments)); } postProcessPDF = true; options["pdf_merge"] = MergeMode.Append; break; case "pdf_prepend": if ((MergeMode)options["pdf_merge"] != MergeMode.None) { Console.WriteLine("Only one of /pdf_append or /pdf_prepend can be used"); Environment.Exit((int)(ExitCode.Failed | ExitCode.InvalidArguments)); } postProcessPDF = true; options["pdf_merge"] = MergeMode.Prepend; break; case "pdf_restrict_annotation": case "pdf_restrict_extraction": case "pdf_restrict_assembly": case "pdf_restrict_forms": case "pdf_restrict_modify": case "pdf_restrict_print": case "pdf_restrict_full_quality": case "pdf_restrict_accessibility_extraction": postProcessPDFSecurity = true; options[itemMatch.Groups[1].Value.ToLower()] = true; break; default: options[itemMatch.Groups[1].Value.ToLower()] = true; break; } } else { Console.WriteLine("Unknown option: {0}", item); Environment.Exit((int)(ExitCode.Failed | ExitCode.InvalidArguments)); } } else if (filesSeen < 2) { files[filesSeen++] = item; } } // Need to error here, as we need input and output files as the // arguments to this script if (filesSeen != 1 && filesSeen != 2) { showHelp(); } // Make sure we only choose one of /screen or /print options if ((Boolean)options["screen"] && (Boolean)options["print"]) { Console.WriteLine("You can only use one of /screen or /print - not both"); Environment.Exit((int)(ExitCode.Failed | ExitCode.InvalidArguments)); } // Make sure the input file looks like something we can handle (i.e. has an office // filename extension) Regex fileMatch = new Regex(@"\.(((ppt|pps|pot|do[ct]|xls|xlt)[xm]?)|xlsb|od[spt]|rtf|csv|vsd[xm]?|vd[xw]|em[fz]|dwg|dxf|wmf|pub|msg|vcf|ics|mpp|svg|txt|html?|wpd)$", RegexOptions.IgnoreCase); if (fileMatch.Matches(files[0]).Count != 1) { Console.WriteLine("Input file can not be handled. Must be Word, PowerPoint, Excel, Outlook, Publisher or Visio"); Environment.Exit((int)(ExitCode.Failed | ExitCode.UnsupportedFileFormat)); } if (filesSeen == 1) { // If only one file is seen, we just swap the extension files[1] = Path.ChangeExtension(files[0], "pdf"); } else { // If the second file is a directory, then we want to create the PDF // with the same name as the original (changing the extension to pdf), // but in the directory given by the path if (Directory.Exists(files[1])) { files[1] = Path.Combine(files[1], Path.GetFileNameWithoutExtension(files[0]) + ".pdf"); } } String inputFile = ""; String outputFile = ""; String finalOutputFile = ""; // Make sure the input file exists and is readable FileInfo info; try { info = new FileInfo(files[0]); if (info == null || !info.Exists) { Console.WriteLine("Input file doesn't exist"); Environment.Exit((int)(ExitCode.Failed | ExitCode.FileNotFound)); } inputFile = info.FullName; options["original_filename"] = info.Name; options["original_basename"] = info.Name.Substring(0, info.Name.Length - info.Extension.Length); } catch { Console.WriteLine("Unable to open input file"); Environment.Exit((int)(ExitCode.Failed | ExitCode.FileOpenFailure)); } // Make sure the destination location exists FileInfo outputInfo = new FileInfo(files[1]); // Remove the destination unless we're doing a PDF merge if (outputInfo != null) { outputFile = finalOutputFile = outputInfo.FullName; if (outputInfo.Exists) { if ((MergeMode)options["pdf_merge"] == MergeMode.None) { // We are not merging, so delete the final destination System.IO.File.Delete(outputInfo.FullName); } else { // We are merging, so make a temporary file outputFile = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".pdf"; } } else { // If there is no current output, no need to merge options["pdf_merge"] = MergeMode.None; } } else { Console.WriteLine("Unable to determine output location"); Environment.Exit((int)(ExitCode.Failed | ExitCode.DirectoryNotFound)); } if (!System.IO.Directory.Exists(outputInfo.DirectoryName)) { Console.WriteLine("Output directory does not exist"); Environment.Exit((int)(ExitCode.Failed | ExitCode.DirectoryNotFound)); } // Now, do the cleverness of determining what the extension is, and so, which // conversion class to pass it to int converted = (int)ExitCode.UnknownError; Match extMatch = fileMatch.Match(inputFile); if (extMatch.Success) { // Set and environment variable so Office application VBA // code can check for un-attended conversion and avoid showing // blocking dialogs Environment.SetEnvironmentVariable("OFFICE2PDF_AUTO_CONVERT", "1"); if ((Boolean)options["verbose"]) { Console.WriteLine("Converting {0} to {1}", inputFile, finalOutputFile); } switch (extMatch.Groups[1].ToString().ToLower()) { case "rtf": case "odt": case "doc": case "dot": case "docx": case "dotx": case "docm": case "dotm": case "txt": case "html": case "htm": case "wpd": // Word if ((Boolean)options["verbose"]) { Console.WriteLine("Converting with Word converter"); } converted = WordConverter.Convert(inputFile, outputFile, options); break; case "csv": case "ods": case "xls": case "xlsx": case "xlt": case "xltx": case "xlsm": case "xltm": case "xlsb": // Excel if ((Boolean)options["verbose"]) { Console.WriteLine("Converting with Excel converter"); } converted = ExcelConverter.Convert(inputFile, outputFile, options); break; case "odp": case "ppt": case "pptx": case "pptm": case "pot": case "potm": case "potx": case "pps": case "ppsx": case "ppsm": // Powerpoint if ((Boolean)options["verbose"]) { Console.WriteLine("Converting with Powerpoint converter"); } converted = PowerpointConverter.Convert(inputFile, outputFile, options, ref documentBookmarks); break; case "vsd": case "vsdm": case "vsdx": case "vdx": case "vdw": case "svg": case "emf": case "emz": case "dwg": case "dxf": case "wmf": // Visio if ((Boolean)options["verbose"]) { Console.WriteLine("Converting with Visio converter"); } converted = VisioConverter.Convert(inputFile, outputFile, options); break; case "pub": // Publisher if ((Boolean)options["verbose"]) { Console.WriteLine("Converting with Publisher converter"); } converted = PublisherConverter.Convert(inputFile, outputFile, options, ref documentBookmarks); break; case "msg": case "vcf": case "ics": // Outlook if ((Boolean)options["verbose"]) { Console.WriteLine("Converting with Outlook converter"); } converted = OutlookConverter.Convert(inputFile, outputFile, options); break; case "mpp": // Project if ((Boolean)options["verbose"]) { Console.WriteLine("Converting with Project converter"); } converted = ProjectConverter.Convert(inputFile, outputFile, options); break; } } if (converted != (int)ExitCode.Success) { Console.WriteLine("Did not convert"); // Return the general failure code and the specific failure code Environment.Exit((int)ExitCode.Failed | converted); } else { if ((Boolean)options["verbose"]) { Console.WriteLine("Completed Conversion"); } if (documentBookmarks.Count > 0) { addPDFBookmarks(outputFile, documentBookmarks, options, null); } // Determine if we have to post-process the PDF if (postProcessPDF) { postProcessPDFFile(outputFile, finalOutputFile, options, postProcessPDFSecurity); } Environment.Exit((int)ExitCode.Success); } }
public static new int Convert(String inputFile, String outputFile, Hashtable options) { Boolean running = (Boolean)options["noquit"]; Microsoft.Office.Interop.Outlook.Application app = null; String tmpDocFile = null; try { try { app = (Microsoft.Office.Interop.Outlook.Application)Marshal.GetActiveObject("Outlook.Application"); } catch (System.Exception) { app = new Microsoft.Office.Interop.Outlook.Application(); running = false; } var session = app.Session; FileInfo fi = new FileInfo(inputFile); // Create a temporary doc file from the message tmpDocFile = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".doc"; switch (fi.Extension) { case ".msg": var message = (MailItem)session.OpenSharedItem(inputFile); if (message == null) { return((int)ExitCode.FileOpenFailure); } message.SaveAs(tmpDocFile, Microsoft.Office.Interop.Outlook.OlSaveAsType.olDoc); Converter.ReleaseCOMObject(message); Converter.ReleaseCOMObject(session); break; case ".vcf": var contact = (ContactItem)session.OpenSharedItem(inputFile); if (contact == null) { return((int)ExitCode.FileOpenFailure); } contact.SaveAs(tmpDocFile, Microsoft.Office.Interop.Outlook.OlSaveAsType.olDoc); Converter.ReleaseCOMObject(contact); Converter.ReleaseCOMObject(session); break; case ".ics": var item = session.OpenSharedItem(inputFile); string itemType = (string)(string)item.GetType().InvokeMember("MessageClass", System.Reflection.BindingFlags.GetProperty, null, item, null); switch (itemType) { case "IPM.Appointment": var appointment = (AppointmentItem)item; if (appointment != null) { appointment.SaveAs(tmpDocFile, Microsoft.Office.Interop.Outlook.OlSaveAsType.olDoc); } break; default: Console.WriteLine("Unable to convert ICS type " + itemType); break; } Converter.ReleaseCOMObject(item); Converter.ReleaseCOMObject(session); break; } if (!File.Exists(tmpDocFile)) { return((int)ExitCode.UnknownError); } // Convert the doc file to a PDF return(WordConverter.Convert(tmpDocFile, outputFile, options)); } catch (System.Exception e) { Console.WriteLine(e.Message); return((int)ExitCode.UnknownError); } finally { if (tmpDocFile != null && File.Exists(tmpDocFile)) { System.IO.File.Delete(tmpDocFile); } // If we were not already running, quit and release the outlook object if (app != null && !running) { ((Microsoft.Office.Interop.Outlook._Application)app).Quit(); } Converter.ReleaseCOMObject(app); } }
public static int ConvertOfficeToPDF(string[] args) { string[] files = new string[2]; int filesSeen = 0; Hashtable options = new Hashtable { // Loop through the input, grabbing switches off the command line ["hidden"] = false, ["markup"] = false, ["readonly"] = false, ["bookmarks"] = false, ["print"] = true, ["screen"] = false, ["pdfa"] = false, ["verbose"] = false, ["excludeprops"] = false, ["excludetags"] = false, ["noquit"] = false, ["merge"] = false, ["template"] = "", ["password"] = "", ["excel_show_formulas"] = false, ["excel_show_headings"] = false, ["excel_auto_macros"] = false, ["excel_max_rows"] = (int)0, ["word_header_dist"] = (float)-1, ["word_footer_dist"] = (float)-1 }; Regex switches = new Regex(@"^/(hidden|markup|readonly|bookmarks|merge|noquit|print|screen|pdfa|template|writepassword|password|help|verbose|exclude(props|tags)|excel_max_rows|excel_show_formulas|excel_show_headings|excel_auto_macros|word_header_dist|word_footer_dist|\?)$", RegexOptions.IgnoreCase); for (int argIdx = 0; argIdx < args.Length; argIdx++) { string item = args[argIdx]; // see if this starts with a / Match m = Regex.Match(item, @"^/"); if (m.Success) { // This is an option Match itemMatch = switches.Match(item); if (itemMatch.Success) { if (itemMatch.Groups[1].Value.ToLower().Equals("help") || itemMatch.Groups[1].Value.Equals("?")) { ShowHelp(); } switch (itemMatch.Groups[1].Value.ToLower()) { case "template": // Only accept the next option if there are enough options if (argIdx + 2 < args.Length) { if (File.Exists(args[argIdx + 1])) { FileInfo templateInfo = new FileInfo(args[argIdx + 1]); options[itemMatch.Groups[1].Value.ToLower()] = templateInfo.FullName; } else { message = "Unable to find " + itemMatch.Groups[1].Value.ToLower() + " " + args[argIdx + 1]; } argIdx++; } break; case "excel_max_rows": // Only accept the next option if there are enough options if (argIdx + 2 < args.Length) { if (Regex.IsMatch(args[argIdx + 1], @"^\d+$")) { options[itemMatch.Groups[1].Value.ToLower()] = (int)Convert.ToInt32(args[argIdx + 1]); } else { message = "Maximum number of rows (" + args[argIdx + 1] + ") is invalid"; return((int)(ExitCode.Failed | ExitCode.InvalidArguments)); } argIdx++; } break; case "word_header_dist": case "word_footer_dist": // Only accept the next option if there are enough options if (argIdx + 2 < args.Length) { if (Regex.IsMatch(args[argIdx + 1], @"^[\d\.]+$")) { try { options[itemMatch.Groups[1].Value.ToLower()] = (float)Convert.ToDouble(args[argIdx + 1]); } catch (Exception) { message = "Header/Footer distance (" + args[argIdx + 1] + ") is invalid"; return((int)(ExitCode.Failed | ExitCode.InvalidArguments)); } } else { message = "Header/Footer distance (" + args[argIdx + 1] + ") is invalid"; return((int)(ExitCode.Failed | ExitCode.InvalidArguments)); } argIdx++; } break; case "password": case "writepassword": // Only accept the next option if there are enough options if (argIdx + 2 < args.Length) { options[itemMatch.Groups[1].Value.ToLower()] = args[argIdx + 1]; argIdx++; } break; case "screen": options["print"] = false; options[itemMatch.Groups[1].Value.ToLower()] = true; break; case "print": options["screen"] = false; options[itemMatch.Groups[1].Value.ToLower()] = true; break; default: options[itemMatch.Groups[1].Value.ToLower()] = true; break; } } else { message = "Unknown option: " + item; return((int)(ExitCode.Failed | ExitCode.InvalidArguments)); } } else if (filesSeen < 2) { files[filesSeen++] = item; } } // Need to error here, as we need input and output files as the // arguments to this script if (filesSeen != 1 && filesSeen != 2) { ShowHelp(); } // Make sure we only choose one of /screen or /print options if ((Boolean)options["screen"] && (Boolean)options["print"]) { message = "You can only use one of /screen or /print - not both"; return((int)(ExitCode.Failed | ExitCode.InvalidArguments)); } // Make sure the input file looks like something we can handle (i.e. has an office // filename extension) Regex fileMatch = new Regex(@"\.(((ppt|pps|pot|do[ct]|xls|xlt)[xm]?)|od[cpt]|rtf|csv|vsd[xm]?|pub|msg|vcf|ics|mpp|svg|txt|html?)$", RegexOptions.IgnoreCase); if (fileMatch.Matches(files[0]).Count != 1) { message = "Input file can not be handled. Must be Word, PowerPoint, Excel, Outlook, Publisher or Visio"; return((int)(ExitCode.Failed | ExitCode.UnsupportedFileFormat)); } if (filesSeen == 1) { files[1] = Path.ChangeExtension(files[0], "pdf"); } String inputFile = ""; String outputFile; // Make sure the input file exists and is readable FileInfo info; try { info = new FileInfo(files[0]); if (info == null || !info.Exists) { message = "Input file doesn't exist"; return((int)(ExitCode.Failed | ExitCode.FileNotFound)); } inputFile = info.FullName; } catch { message = "Unable to open input file"; return((int)(ExitCode.Failed | ExitCode.FileOpenFailure)); } // Make sure the destination location exists FileInfo outputInfo = new FileInfo(files[1]); if (outputInfo != null && outputInfo.Exists) { System.IO.File.Delete(outputInfo.FullName); } if (!System.IO.Directory.Exists(outputInfo.DirectoryName)) { message = "Output directory does not exist"; return((int)(ExitCode.Failed | ExitCode.DirectoryNotFound)); } outputFile = outputInfo.FullName; // Now, do the cleverness of determining what the extension is, and so, which // conversion class to pass it to int converted = (int)ExitCode.UnknownError; Match extMatch = fileMatch.Match(inputFile); if (extMatch.Success) { if ((Boolean)options["verbose"]) { message = "Converting " + inputFile + " to " + outputFile; } switch (extMatch.Groups[1].ToString().ToLower()) { case "rtf": case "odt": case "doc": case "dot": case "docx": case "dotx": case "docm": case "dotm": case "txt": case "html": case "htm": // Word if ((Boolean)options["verbose"]) { message = "Converting with Word converter"; } converted = WordConverter.Convert(inputFile, outputFile, options); break; case "csv": case "odc": case "xls": case "xlsx": case "xlt": case "xltx": case "xlsm": case "xltm": // Excel if ((Boolean)options["verbose"]) { message = "Converting with Excel converter"; } converted = ExcelConverter.Convert(inputFile, outputFile, options); break; case "odp": case "ppt": case "pptx": case "pptm": case "pot": case "potm": case "potx": case "pps": case "ppsx": case "ppsm": // Powerpoint if ((Boolean)options["verbose"]) { message = "Converting with Powerpoint converter"; } converted = PowerpointConverter.Convert(inputFile, outputFile, options); break; case "vsd": case "vsdm": case "vsdx": case "svg": // Visio if ((Boolean)options["verbose"]) { message = "Converting with Visio converter"; } converted = VisioConverter.Convert(inputFile, outputFile, options); break; case "pub": // Publisher if ((Boolean)options["verbose"]) { message = "Converting with Publisher converter"; } converted = PublisherConverter.Convert(inputFile, outputFile, options); break; case "msg": case "vcf": case "ics": // Outlook if ((Boolean)options["verbose"]) { message = "Converting with Outlook converter"; } converted = OutlookConverter.Convert(inputFile, outputFile, options); break; case "mpp": // Project if ((Boolean)options["verbose"]) { message = "Converting with Project converter"; } converted = ProjectConverter.Convert(inputFile, outputFile, options); break; } } if (converted != (int)ExitCode.Success) { message = "Did not convert"; // Return the general failure code and the specific failure code return((int)ExitCode.Failed | converted); } else if ((Boolean)options["verbose"]) { message = "Completed Conversion"; } return((int)ExitCode.Success); }