using System; using System.Collections.Generic; using System.Text; using System.Reflection; using Microsoft.Win32; using System.Windows.Forms; using System.Text.RegularExpressions; namespace LBWordLibrary { public partial class LBApplicationClass : LBComObject { /// /// This gives the option of specifying Background = false to print in the foreground. /// /// boolean BackGround /// If true - document will be printed in the background /// If false - document will be printed in the foreground public void PrintOut(Boolean Background) { InvokeMethod("PrintOut", Background, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value); } public void Quit(bool save) { InvokeMethod("Quit", save, Missing.Value, Missing.Value); } public bool VolianPDFInstalled { get { foreach (string printer in System.Drawing.Printing.PrinterSettings.InstalledPrinters) if (printer == "VolianPDF Writer") return true; return false; } } public bool WordPDFExporterInstalled { get { // this is for ExportAsFixedFormat MSOffice AddIn RegistryKey key = Registry.ClassesRoot.OpenSubKey(@"Installer\Components\12B306B24E250DD428FC7016B6FB4BD8"); if (key != null) { key.Close(); return true; } return false; } } private bool CanCreatePDFFile(string pdfFileName) { System.IO.FileInfo file = new System.IO.FileInfo(pdfFileName); if (!file.Exists) return true; try { file.Delete(); return true; } catch (System.IO.IOException exio) { if (exio.Message.StartsWith("The process cannot access the file")) return false; throw new Exception(string.Format("Cannot Delete PDF file {0}", pdfFileName), exio); } catch (Exception ex) { throw new Exception(string.Format("Cannot Delete PDF file {0}", pdfFileName), ex); } } private string AvailableFileName(string pdfFileName) { if (CanCreatePDFFile(pdfFileName)) return pdfFileName; string prefix = pdfFileName.Replace(".pdf", ""); for (int i = 1; i < 1000; i++) { string newname = string.Format("{0}_{1:000}.PDF", prefix, i); if (CanCreatePDFFile(newname)) return newname; } throw new Exception("Cannot find a name to use"); } public string CreatePDF(string pdfFileName, bool openPDF) { pdfFileName = CreatePDF(pdfFileName); if (openPDF) OpenPDF(pdfFileName); return pdfFileName; } static List _AcrobatProcesses=new List(); private static void OpenPDF(string pdfFileName) { _AcrobatProcesses.Add(System.Diagnostics.Process.Start(pdfFileName)); } public static void ClosePDFs() { foreach(System.Diagnostics.Process proc in _AcrobatProcesses) if (!proc.HasExited) KillAndWait(proc); } private static void KillAndWait(System.Diagnostics.Process proc) { Console.WriteLine("{0:s.ffff} Killing Adobe", DateTime.Now); DateTime tStart = DateTime.Now; proc.Kill(); DateTime tEnd = DateTime.Now.AddMilliseconds(100); while (DateTime.Now < tEnd) { Application.DoEvents(); } Console.WriteLine("{0:yyyy-MM-dd HH:mm:ss.ffff} {1:yyyy-MM-dd HH:mm:ss.ffff} {2}", DateTime.Now, proc.ExitTime ,TimeSpan.FromTicks(proc.ExitTime.Ticks - tStart.Ticks).TotalMilliseconds); } public string CreatePDF(string pdfFileName) { pdfFileName = AvailableFileName(pdfFileName); if (Convert.ToSingle(Version) >= 12.0F && WordPDFExporterInstalled) return CreatePDF2007(pdfFileName); else if (VolianPDFInstalled) return CreatePDF2003BG(pdfFileName); else throw new Exception("No PDF Writer support installed for MS Word sections"); } public string CreatePDF2003FG(string pdfFileName, bool openPDF) { pdfFileName = CreatePDF2003FG(pdfFileName); if (openPDF) OpenPDF(pdfFileName); return pdfFileName; } public string CreatePDF2003FG(string pdfFileName) { pdfFileName = AvailableFileName(pdfFileName); if (!VolianPDFInstalled) throw new Exception("VolianPDF Writer is not installed properly"); try { string printer = ActivePrinter; RegistryKey key = Registry.CurrentUser.CreateSubKey(@"Software\VolianPDF Writer"); key.SetValue("OutputFile", pdfFileName, RegistryValueKind.String); key.SetValue("BypassSaveAs", "1", RegistryValueKind.String); key.Close(); ActivePrinter = "VolianPDF Writer"; PrintOut(false); ActivePrinter = printer; Registry.CurrentUser.DeleteSubKeyTree(@"Software\VolianPDF Writer"); return pdfFileName; } catch (Exception ex) { throw new Exception("Error creating PDF - LBApplicationClass.CreatePDF2003FG", ex); } } public string CreatePDF2003BG(string pdfFileName, bool openPDF) { pdfFileName = CreatePDF2003BG(pdfFileName); if (openPDF) OpenPDF(pdfFileName); return pdfFileName; } public string CreatePDF2003BG(string pdfFileName) { pdfFileName = AvailableFileName(pdfFileName); if (!VolianPDFInstalled) throw new Exception("VolianPDF Writer is not installed properly"); try { string printer = ActivePrinter; RegistryKey key = Registry.CurrentUser.CreateSubKey(@"Software\VolianPDF Writer"); key.SetValue("OutputFile", pdfFileName, RegistryValueKind.String); key.SetValue("BypassSaveAs", "1", RegistryValueKind.String); key.Close(); ActivePrinter = "VolianPDF Writer"; PrintOut(true); do { // Console.WriteLine("Background Printing Status = {0}", _MyApp.BackgroundPrintingStatus); Application.DoEvents(); } while (BackgroundPrintingStatus == 1); ActivePrinter = printer; Registry.CurrentUser.DeleteSubKeyTree(@"Software\VolianPDF Writer"); return pdfFileName; } catch (Exception ex) { throw new Exception("Error creating PDF - LBApplicationClass.CreatePDF2003BG", ex); } } public string CreatePDF2007(string pdfFileName, bool openPDF) { pdfFileName = CreatePDF2007(pdfFileName); if (openPDF) OpenPDF(pdfFileName); return pdfFileName; } public string CreatePDF2007(string pdfFileName) { pdfFileName = AvailableFileName(pdfFileName); if (!WordPDFExporterInstalled) throw new Exception("MS Word PDF Exporter is not installed"); try { ActiveDocument.ExportAsFixedFormat(pdfFileName, LBWdExportFormat.wdExportFormatPDF); return pdfFileName; } catch (Exception ex) { throw new Exception("Error creating PDF - LBApplicationClass.CreatePDF2007", ex); } } } public partial class LBDocuments { public LBDocumentClass Open(string fileName, Boolean addToRecentFiles) { return Open(fileName, Missing.Value, Missing.Value, addToRecentFiles); } private LBDocumentClass Open(params object[] myParams) { return new LBDocumentClass(InvokeMethod("Open", myParams)); } } public partial class LBDocumentClass : LBComObject { public void SaveAs2000(string fileName) { if (fileName.ToUpper().EndsWith("DOC")) SaveAs2000(fileName, LBWdSaveFormat.wdFormatDocument); else if (fileName.ToUpper().EndsWith("RTF")) SaveAs2000(fileName, LBWdSaveFormat.wdFormatRTF); else SaveAs2000(fileName); } public void SaveAs2000(params object[] myParams) { InvokeMethod("SaveAs2000", myParams); } public void SaveAs(string fileName) { if (fileName.ToUpper().EndsWith("DOC")) SaveAs2(fileName, LBWdSaveFormat.wdFormatDocument, Missing.Value, Missing.Value, false); else if (fileName.ToUpper().EndsWith("RTF")) SaveAs2(fileName, LBWdSaveFormat.wdFormatRTF, Missing.Value, Missing.Value, false); else if (fileName.ToUpper().EndsWith("TXT")) SaveAs2(fileName, LBWdSaveFormat.wdFormatDOSText, Missing.Value, Missing.Value, false); else if (fileName.ToUpper().EndsWith("DOCX")) SaveAs2(fileName, LBWdSaveFormat.wdFormatXMLDocument, Missing.Value, Missing.Value, false); else SaveAs2(fileName, Missing.Value, Missing.Value, Missing.Value, false); } public void SaveAs2(params object[] myParams) { InvokeMethod("SaveAs", myParams); } public void SaveAs(string fileName, LBWdSaveFormat format) { SaveAs2(fileName, format, Missing.Value, Missing.Value, false); } public LBRange Range(int Start, int End) { return new LBRange(InvokeMethod("Range", Start, End)); } /// /// Length is Pages and Partial Pages /// The integral part is the number of full pages /// The decimal part is the size of the last page divided by 7200 /// (the first two digits should be the number of inches) /// public float Length { get { ActiveWindow.ActivePane.View.Type = LBWdViewType.wdPrintView; ActiveWindow.View.Type = LBWdViewType.wdPrintView; LBPages myPages = ActiveWindow.ActivePane.Pages;// Start with pages float retval = (float)myPages.Count - 1; LBRange myRange = Range(); myRange = myRange.GoTo(LBWdGoToItem.wdGoToPercent, LBWdGoToDirection.wdGoToLast, 100); float partial = (float) myRange.get_Information(LBWdInformation.wdVerticalPositionRelativeToPage); partial += myRange.Font.Size; retval += partial / 7200; return retval; } } public string Ascii { get { LBRange myRange = Range(); myRange = myRange.GoTo(LBWdGoToItem.wdGoToPercent, LBWdGoToDirection.wdGoToLast, 100); myRange.Start = 0; return ReplaceSymbolCharacters(GetRangeText(myRange)); } } private static string[] SymbolFontName = { "VolianDraw", "WingDings", "VESymb", "VESymbFix", "Symbol" }; private static bool IsSymbolFont(string fontName) { foreach (string symbolFont in SymbolFontName) if (fontName.ToUpper().StartsWith(symbolFont.ToUpper())) return true; return false; } /// /// If document contains symbol characters, returns problem font. /// public string FontHasSymbolCharacters { get { LBRange myRange = Range(); myRange = myRange.GoTo(LBWdGoToItem.wdGoToPercent, LBWdGoToDirection.wdGoToLast, 100); myRange.Start = 0; int end = myRange.End; string myText = GetRangeText(myRange); //return _RegFindSymbol.IsMatch(myText); MatchCollection problems = _RegFindSymbol.Matches(myText); int offset = 0; foreach (Match problem in problems) { myRange.Start = problem.Index + offset; myRange.End = problem.Index + problem.Length + offset; int newOffset = FindRangeOffset(myRange, problem, offset, end); if (IsSymbolFont(myRange.Font.Name)) { Console.WriteLine("Font '{0}' has Symbols", myRange.Font.Name); //return true; } else return myRange.Font.Name; offset = newOffset; } return null; } } /// /// Checks to see if the document contains symbol characters /// /// public bool HasSymbolCharacters { get { LBRange myRange = Range(); myRange = myRange.GoTo(LBWdGoToItem.wdGoToPercent, LBWdGoToDirection.wdGoToLast, 100); myRange.Start = 0; int end = myRange.End; string myText = GetRangeText(myRange); //return _RegFindSymbol.IsMatch(myText); MatchCollection problems = _RegFindSymbol.Matches(myText); int offset = 0; foreach (Match problem in problems) { myRange.Start = problem.Index + offset; myRange.End = problem.Index + problem.Length + offset; int newOffset = FindRangeOffset(myRange, problem, offset, end); if (IsSymbolFont(myRange.Font.Name)) { Console.WriteLine("Font '{0}' has Symbols", myRange.Font.Name); //return true; } else return true; offset = newOffset; } return false; } } Regex _RegFindSymbol = new Regex("[\\uF000-\\uF0FF]+"); /// /// FixSymbolCharacters - Fix any symbol characters in the document /// public void FixSymbolCharacters() { // Set up range object to be used to process text LBRange myRange = Range(); myRange = myRange.GoTo(LBWdGoToItem.wdGoToPercent, LBWdGoToDirection.wdGoToLast, 100); int end = myRange.End; myRange.Start = 0; string myText = GetRangeText(myRange); MatchCollection problems = _RegFindSymbol.Matches(myText); int offset = 0; foreach (Match problem in problems) { myRange.Start = problem.Index + offset; myRange.End = problem.Index + problem.Length + offset; int newOffset = FindRangeOffset(myRange, problem, offset, end); ReplaceSymbolCharacters(myRange); offset = newOffset; } } /// /// Try to fix the first character in the symbol range F000 to F0FF. If it cannot be /// fixed, it is an indicator that the font is not installed properly. Regardless of /// whether there is success, the change is undone so that the document will not be /// considered dirty, i.e. will not prompt user for save. /// /// public bool AttemptToFixASymbolCharacter() { // Set up range object to be used to process text LBRange myRange = Range(); myRange = myRange.GoTo(LBWdGoToItem.wdGoToPercent, LBWdGoToDirection.wdGoToLast, 100); int end = myRange.End; myRange.Start = 0; string myText = GetRangeText(myRange); MatchCollection problems = _RegFindSymbol.Matches(myText); if (problems.Count>0) { Match problem = problems[0]; myRange.Start = problem.Index; myRange.End = myRange.Start + 1; if (IsSymbolFont(myRange.Font.Name)) return true; // if it's a symbol font already, no issue. string before = GetRangeText(myRange); string updated = ReplaceSymbolCharacters(before); myRange.Text = updated; string after = GetRangeText(myRange); Undo(1); //Console.WriteLine("Undo1 results = {0}", tst); //tst = Undo(1); //Console.WriteLine("Undo2 results = {0}", tst); //tst = Undo(1); //Console.WriteLine("Undo3 results = {0}", tst); return (updated == after); } return true; } /// /// Get the Range Text with error handling. myRange.Text sometimes will get a null reference exception. /// /// /// internal static string GetRangeText(LBRange myRange) { string text=""; try { text = myRange.Text; } catch (Exception ex) { Console.WriteLine("GetRangeText {0} - {1}", ex.GetType().Name, ex.Message); } return text; } /// /// Looks for the problem string and adjusts the range as necessary /// /// /// /// /// /// private int FindRangeOffset(LBRange myRange, Match problem, int offset, int end) { // try to find the string string text = GetRangeText(myRange); if (text != problem.Value) { // Get the entire text starting at the offset of the first match myRange.Start = problem.Index + offset; myRange.End = end; text = GetRangeText(myRange); while (!text.StartsWith(problem.Value)) { int newStart = text.IndexOf(problem.Value);// Find the string if it is not at the beginning myRange.Start += myRange.Start == newStart ? newStart + 1 : newStart; // adjust the starting location text = GetRangeText(myRange);// get the text to check } myRange.End = myRange.Start + problem.Length; // assume that the end should be the start plus the length text = GetRangeText(myRange); while (text.Length < problem.Length) // If the result is too short increase the length { myRange.End += (problem.Length - text.Length); text = GetRangeText(myRange); } } return myRange.Start - problem.Index; } /// /// ReplaceSymbolCharacters Replaces any symbol characters in the specified range /// /// private static void ReplaceSymbolCharacters(LBRange myRange) { try { if (IsSymbolFont(myRange.Font.Name)) return; string before = GetRangeText(myRange); string updated = ReplaceSymbolCharacters(before); myRange.Text = updated; string after = GetRangeText(myRange); if (after != updated) // If the Word text doesn't match try including a character before and after and do it again. { Console.WriteLine("'TryEntireRange Failed',{0},{1},'{2}','{3}','{4}'", myRange.Start, myRange.End, before, updated, after); int end = myRange.End; myRange.Start = myRange.Start - 1; myRange.End = end + 1; myRange.Text = ReplaceSymbolCharacters(GetRangeText(myRange)); Console.WriteLine("'TryEntireRange Failed',{0},{1},'{2}'", myRange.Start, myRange.End, GetRangeText(myRange)); } } catch (Exception ex) { Console.WriteLine("'TryEntireRange Exception',{0},{1},'{2}'", myRange.Start, myRange.End, ex.Message); } } /// /// ReplaceSymbolCharacters processes the string returned and changes any symbols (0xF0??) to normal characters /// /// /// private static string ReplaceSymbolCharacters(string str) { StringBuilder results = new StringBuilder(); foreach (char c in str) { if ((c & 0xFF00) == 0xF000) results.Append((char)(c & 0xFF)); else results.Append((char)(c)); } return results.ToString(); } /// /// Close the document /// /// Save Changes public void Close(bool SaveChanges) { InvokeMethod("Close", SaveChanges, Missing.Value, Missing.Value); } } public partial class LBFind { public void ReplaceAll() { this.Execute(Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, LBWdReplace.wdReplaceAll, Missing.Value, Missing.Value, Missing.Value, Missing.Value); } } public partial class LBFontClass : LBComObject { public int TextColor { get { return (int)GetProperty("Color"); } set { SetProperty("Color", value); } } } public partial class LBRange : LBComObject { public Object get_Information(LBWdInformation info) { return GetProperty("Information", info); } public LBRange GoTo(LBWdGoToItem What, LBWdGoToDirection Which, int Count) { return new LBRange(InvokeMethod("GoTo", What, Which, Count, Missing.Value)); } } public partial class LBSelection : LBComObject { public Object get_Information(LBWdInformation info) { return GetProperty("Information", info); } public int MoveStart(LBWdUnits Unit, int Count) { return InvokeMethod("MoveStart", Unit, Count) as int? ?? 0; } public int MoveEnd(LBWdUnits Unit, int Count) { return InvokeMethod("MoveEnd", Unit, Count) as int? ?? 0; } public int EndKey(LBWdUnits Unit, bool Extend) { return InvokeMethod("EndKey", Unit, Extend) as int? ?? 0; } public bool LastWasUpper { get { LBRange myRange = Range; int start = myRange.Start - 1; while (start >= 0) { myRange.Start = start; myRange.End = start + 1; string previous = LBDocumentClass.GetRangeText(myRange); if (Regex.IsMatch(previous, "[A-Z]")) return true; if (Regex.IsMatch(previous, "[a-z]")) return false; start = start - 1; } return false; } } } public partial class LBInlineShapes : LBComObjectList /* Collection */ { public LBInlineShape AddPicture(string FileName, LBRange Range) { return new LBInlineShape(InvokeMethod("AddPicture", FileName, false, true, Range)); } } public partial class LBShapes : LBComObjectList /* Collection */ { public LBShape AddPicture(string FileName, float Left, float Top, LBRange Anchor) { return new LBShape(InvokeMethod("AddPicture", FileName, false, true, Left, Top, Missing.Value, Missing.Value, Anchor)); } public LBShape AddPicture(string FileName, float Left, float Top) { return new LBShape(InvokeMethod("AddPicture", FileName, false, true, Left, Top, Missing.Value, Missing.Value, Missing.Value)); } } public enum LBMsoTriState { msoCTrue = 1, msoFalse = 0, msoTriStateMixed = -2, msoTriStateToggle = -3, msoTrue = -1 } //public partial class ProcessKiller //{ // System.Diagnostics.Process _MyProcess; // private bool _Exited = false; // public ProcessKiller(System.Diagnostics.Process myProcess) // { // _MyProcess = myProcess; // _MyProcess.Exited += new EventHandler(_MyProcess_Exited); // _MyProcess.Kill(); // DateTime next = DateTime.Now.AddMilliseconds(200); // while (DateTime.Now < next) // Application.DoEvents(); // while (!_Exited) // Application.DoEvents(); // } // void _MyProcess_Exited(object sender, EventArgs e) // { // Console.WriteLine("Exited"); // _Exited = true; // } //} }