Exemple #1
0
        // 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);
            }
        }
Exemple #3
0
        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);
        }
Exemple #4
0
        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);
            }
        }
Exemple #5
0
        // 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);
        }
Exemple #6
0
        /// <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);
            }
        }
Exemple #7
0
        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);
        }