using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Reflection; using Foo.Platform; using Foo.Platform.Win32; using System.Diagnostics; using System.Runtime.InteropServices; //// // Ignore 'Ambiguity' warning message, seems like no way around those //// #pragma warning disable 0467 namespace Foo.WorkspaceMgr.Closers { class Closer_Office : IClose { #region IClose Members /// /// Dispatches the QueryClose Request to the Proper Office Closer /// /// /// public FuncDepBoolType IQueryClose(string strArtifactLocation) { switch (Win32_WrapperFunc.GetRegisteredExeForFile(strArtifactLocation)) { case "WINWORD.EXE": return QueryClose_MSWord(strArtifactLocation); case "EXCEL.EXE": return QueryClose_MSExcel(strArtifactLocation); case "POWERPNT.EXE": return QueryClose_MSPowerPoint(strArtifactLocation); case "MSPUB.EXE": return QueryClose_MSPublisher(strArtifactLocation); case "VISIO.EXE": return QueryClose_MSVisio(strArtifactLocation); case "MSACCESS.EXE": return QueryClose_MSAccess(strArtifactLocation); } return FuncDepBoolType.FunctionallityNotSupported; } /// /// Dispatches the Close Request to the Proper Office Closer /// /// /// public FuncDepBoolType IClose(string strArtifactLocation) { switch (Win32_WrapperFunc.GetRegisteredExeForFile(strArtifactLocation)) { case "WINWORD.EXE": return Close_MSWord(strArtifactLocation); case "EXCEL.EXE": return Close_MSExcel(strArtifactLocation); case "POWERPNT.EXE": return Close_MSPowerPoint(strArtifactLocation); case "MSPUB.EXE": return Close_MSPublisher(strArtifactLocation); case "VISIO.EXE": return Close_MSVisio(strArtifactLocation); case "MSACCESS.EXE": return Close_MSAccess(strArtifactLocation); } return FuncDepBoolType.FunctionallityNotSupported; } #endregion #region Microsoft Word IClose Members public const string Word_ProgId = "Word.Application"; /// /// To Do : Test This - Let's us know if the user has unsaved data /// /// /// public FuncDepBoolType QueryClose_MSWord(string strArtifactLocation) { try { // Microsoft.Office.Interop.Word.Application app = null; // app = Win32Functions.GetCOMObject(Word_ProgId) as Microsoft.Office.Interop.Word.Application; var RunningWordDocuments = Win32Functions.GetRunningObjectsOfType(); foreach (Microsoft.Office.Interop.Word.Document doc in RunningWordDocuments) { if (doc.FullName.ToLower() == strArtifactLocation.ToLower()) { if (doc.Saved) return FuncDepBoolType.Success; else return FuncDepBoolType.Failed; } } } catch (Exception e) { string message = e.Message; message = message + ""; // TODO: Log Something here return FuncDepBoolType.ErrorThrown; } //**** Another Way Stored here for Later **** // may be this is helpful.. //using ComTypes = System.Runtime.InteropServices.ComTypes; //ComTypes.IPersistFile persistFile = (ComTypes.IPersistFile)document; //Checks an object for changes since it was last saved to its current file. //if (persistFile.IsDirty) //{ //do your stuff //} return FuncDepBoolType.Failed; } /// /// *** Technically ** Here we want to close the Word Document (Not Prompt the user at all) /// **** we could close it with a WM_CLOSE or WM_SCLOSE or with the DOM. ~for now it's the /// DOM, however more testing to be done here /// /// /// public FuncDepBoolType Close_MSWord(string strArtifactLocation) { if (!String.IsNullOrEmpty(strArtifactLocation)) { try { var RunningWordDocuments = Win32Functions.GetRunningObjectsOfType(); foreach (Microsoft.Office.Interop.Word.Document doc in RunningWordDocuments) { if (doc.FullName.ToLower() == strArtifactLocation.ToLower()) { // Found the document to close * Close it Without Prompting * object saveOption = Microsoft.Office.Interop.Word.WdSaveOptions.wdSaveChanges; object originalFormat = Microsoft.Office.Interop.Word.WdOriginalFormat.wdOriginalDocumentFormat; object routeDocument = false; var app = doc.Application; // Let's get the Window that belongs to this document Microsoft.Office.Interop.Word.Window docWindow = null; foreach (Microsoft.Office.Interop.Word.Window window in doc.Windows) { if (window.Document.FullName.ToLower() == strArtifactLocation.ToLower()) { docWindow = window; } } //Object missing = Missing.Value; doc.Close(ref saveOption, ref originalFormat, ref routeDocument); Marshal.FinalReleaseComObject(doc); // force clean-up // Close the Window if (docWindow != null) docWindow.Close(ref saveOption, ref routeDocument); // Close Word if this is the Last Document Instance if (app.Documents.Count == 0) { app.Quit(ref saveOption, ref originalFormat, ref routeDocument); Marshal.FinalReleaseComObject(app); // force clean-up, closes Process for sure } return FuncDepBoolType.Success; } } return FuncDepBoolType.Failed; } catch (Exception e) { string message = e.Message; message = message + ""; // TODO: Log Something here return FuncDepBoolType.ErrorThrown; } } return FuncDepBoolType.ParametersInvalid; } #endregion #region Microsoft Excel IClose Members public const string Excel_ProgId = "Excel.Application"; /// /// To Do : Test This - Let's us know if the user has unsaved data /// /// /// public FuncDepBoolType QueryClose_MSExcel(string strArtifactLocation) { if (!String.IsNullOrEmpty(strArtifactLocation)) { var RunningExcelWorkbooks = Win32Functions.GetRunningObjectsOfType(); foreach (Microsoft.Office.Interop.Excel.Workbook book in RunningExcelWorkbooks) { if (book.FullName.ToLower() == strArtifactLocation.ToLower()) { if(book.Saved) return FuncDepBoolType.Success; else return FuncDepBoolType.Failed; } } return FuncDepBoolType.ArtifactLocationUnavailable; } return FuncDepBoolType.ParametersInvalid; } /// /// *** Technically ** Here we want to close the Excel Workbook (Not Prompt the user at all) /// **** we could close it with a WM_CLOSE or WM_SCLOSE or with the DOM. ~for now it's the /// DOM, however more testing to be done here /// /// /// public FuncDepBoolType Close_MSExcel(string strArtifactLocation) { if (!String.IsNullOrEmpty(strArtifactLocation)) { try { var RunningExcelWorkbooks = Win32Functions.GetRunningObjectsOfType(); foreach (Microsoft.Office.Interop.Excel.Workbook book in RunningExcelWorkbooks) { if (book.FullName.ToLower() == strArtifactLocation.ToLower()) { // In case there is a running rogue excel process left open, // we can always force it to close by closing the process // int hWnd = app.Hwnd; // Process process = Win32Functions.GetProcessFromHandle((IntPtr) hWnd); var app = book.Application; // Close the Workbook book.Close(true, strArtifactLocation, false); Marshal.FinalReleaseComObject(book); // force clean-up // Close Excel if this is the last Workbook if (app.Workbooks.Count == 0) { app.Quit(); Marshal.FinalReleaseComObject(app); // force clean-up, should clean up excel process //process.Close(); } return FuncDepBoolType.Success; } } return FuncDepBoolType.ArtifactLocationUnavailable; } catch (Exception e) { string message = e.Message; message = message + ""; // TODO: Log Something here return FuncDepBoolType.ErrorThrown; } } return FuncDepBoolType.ParametersInvalid; } #endregion #region Microsoft PowerPoint IClose Members public const string PowerPoint_ProgId = "PowerPoint.Application"; /// /// To Do : Test This - Let's us know if the user has unsaved data /// /// /// public FuncDepBoolType QueryClose_MSPowerPoint(string strArtifactLocation) { if (!String.IsNullOrEmpty(strArtifactLocation)) { try { //Microsoft.Office.Interop.PowerPoint.Application app = null; //app = Win32Functions.GetCOMObject(PowerPoint_ProgId) as Microsoft.Office.Interop.PowerPoint.Application; //foreach (Microsoft.Office.Interop.PowerPoint.Presentation presentation in app.Presentations) var RunningPowerPoints = Win32Functions.GetRunningObjectsOfType(); foreach (Microsoft.Office.Interop.PowerPoint.Presentation presentation in RunningPowerPoints) { if (presentation.FullName.ToLower() == strArtifactLocation.ToLower()) { switch (presentation.Saved) { case Microsoft.Office.Core.MsoTriState.msoTrue: return FuncDepBoolType.Success; case Microsoft.Office.Core.MsoTriState.msoFalse: return FuncDepBoolType.Failed; } } } } catch (Exception e) { string message = e.Message; message = message + ""; // TODO: Log Something here return FuncDepBoolType.ErrorThrown; } } return FuncDepBoolType.ParametersInvalid; } /// /// *** Technically ** Here we want to close the Word Document (Not Prompt the user at all) /// **** we could close it with a WM_CLOSE or WM_SCLOSE or with the DOM. ~for now it's the /// DOM, however more testing to be done here /// /// /// public FuncDepBoolType Close_MSPowerPoint(string strArtifactLocation) { if (!String.IsNullOrEmpty(strArtifactLocation)) { try { //Microsoft.Office.Interop.PowerPoint.Application app = null; //app = Win32Functions.GetCOMObject(PowerPoint_ProgId) as Microsoft.Office.Interop.PowerPoint.Application; //foreach (Microsoft.Office.Interop.PowerPoint.Presentation presentation in app.Presentations) var RunningPowerPoints = Win32Functions.GetRunningObjectsOfType(); foreach (Microsoft.Office.Interop.PowerPoint.Presentation presentation in RunningPowerPoints) { if (presentation.FullName.ToLower() == strArtifactLocation.ToLower()) { var app = presentation.Application; // Save this Presentation presentation.Save(); // Close this Presentation presentation.Close(); Marshal.FinalReleaseComObject(presentation); // force clean-up // Close PowerPoint if there are no more Presentations if (app.Presentations.Count == 0) { app.Quit(); Marshal.FinalReleaseComObject(app); // force clean-up, kill application for sure } return FuncDepBoolType.Success; } } return FuncDepBoolType.Failed; } catch (Exception e) { string message = e.Message; message = message + ""; // TODO: Log Something here return FuncDepBoolType.ErrorThrown; } } return FuncDepBoolType.ParametersInvalid; } #endregion #region Microsoft Publisher IClose Members public const string Publisher_ProgId = "Publisher.Application"; /// /// To Do : Test This - Let's us know if the user has unsaved data /// /// /// public FuncDepBoolType QueryClose_MSPublisher(string strArtifactLocation) { var RunningPublisherApps = Win32Functions.GetRunningObjectsOfType(); foreach (Microsoft.Office.Interop.Publisher.Application app in RunningPublisherApps) { foreach (Microsoft.Office.Interop.Publisher.Document pubDoc in app.Documents) { if (pubDoc.FullName.ToLower() == strArtifactLocation.ToLower()) { try { if (pubDoc.Saved) return FuncDepBoolType.Success; else return FuncDepBoolType.Failed; } catch (Exception e) { string message = e.Message; message = message + ""; // TODO: Log Something here } break; } } } return FuncDepBoolType.Success; } /// /// *** Technically ** Here we want to close the Word Document (Not Prompt the user at all) /// **** we could close it with a WM_CLOSE or WM_SCLOSE or with the DOM. ~for now it's the /// DOM, however more testing to be done here /// /// /// public FuncDepBoolType Close_MSPublisher(string strArtifactLocation) { IntPtr hWnd = IntPtr.Zero; try { var RunningPublisherApps = Win32Functions.GetRunningObjectsOfType(); foreach (Microsoft.Office.Interop.Publisher.Application app in RunningPublisherApps) { foreach (Microsoft.Office.Interop.Publisher.Document pubDoc in app.Documents) { if (pubDoc.FullName.ToLower() == strArtifactLocation.ToLower()) { // Save the Document pubDoc.Save(); // Get the Handle hWnd = (IntPtr)pubDoc.ActiveWindow.Hwnd; goto FOUND_DOCUMENT_HWND; } } } return FuncDepBoolType.Failed; } catch (Exception e) { string message = e.Message; message = message + ""; // TODO: Log Something here } FOUND_DOCUMENT_HWND: // Get the Process Process process = Win32Functions.GetProcessFromHandle(hWnd); // Send Close Message if (Win32Functions.SendMessage((IntPtr)hWnd, (int)WindowMessage.WM_CLOSE, IntPtr.Zero, IntPtr.Zero) == 0) { process.Kill(); return FuncDepBoolType.Success; } else { return FuncDepBoolType.Failed; } } #endregion #region Microsoft Visio IClose Members public const string Visio_ProgId = "Visio.Application"; /// /// To Do : Test This - Let's us know if the user has unsaved data /// /// /// public FuncDepBoolType QueryClose_MSVisio(string strArtifactLocation) { var RunningVisioDocs = Win32Functions.GetRunningObjectsOfType(); foreach (Microsoft.Office.Interop.Visio.Document doc in RunningVisioDocs) { if (doc.FullName.ToLower() == strArtifactLocation.ToLower()) { try { if (doc.Saved) return FuncDepBoolType.Success; else return FuncDepBoolType.Failed; } catch (Exception e) { string message = e.Message; message = message + ""; // TODO: Log Something here } break; } } return FuncDepBoolType.Success; } /// /// *** Technically ** Here we want to close the Word Document (Not Prompt the user at all) /// **** we could close it with a WM_CLOSE or WM_SCLOSE or with the DOM. ~for now it's the /// DOM, however more testing to be done here /// /// /// public FuncDepBoolType Close_MSVisio(string strArtifactLocation) { var RunningVisioDocs = Win32Functions.GetRunningObjectsOfType(); foreach (Microsoft.Office.Interop.Visio.Document doc in RunningVisioDocs) { if (doc.FullName.ToLower() == strArtifactLocation.ToLower()) { try { doc.Save(); var app = doc.Application; doc.Close(); Marshal.FinalReleaseComObject(doc); // Force Clean-up if (app.Documents.Count == 0) { app.Quit(); Marshal.FinalReleaseComObject(app); // force clean-up } return FuncDepBoolType.Success; } catch (Exception e) { string message = e.Message; message = message + ""; // TODO: Log Something here } } } return FuncDepBoolType.Success; } #endregion #region Microsoft Access IClose Members public const string Access_ProgId = "Access.Application"; /// /// To Do : Test This - Let's us know if the user has unsaved data /// /// /// public FuncDepBoolType QueryClose_MSAccess(string strArtifactLocation) { var RunningAccessApps = Win32Functions.GetRunningObjectsOfType(); foreach (Microsoft.Office.Interop.Access.Application app in RunningAccessApps) { if (app.CurrentProject.FullName.ToLower() == strArtifactLocation.ToLower()) { return FuncDepBoolType.Success; } } return FuncDepBoolType.Failed; } /// /// *** Technically ** Here we want to close the Word Document (Not Prompt the user at all) /// **** we could close it with a WM_CLOSE or WM_SCLOSE or with the DOM. ~for now it's the /// DOM, however more testing to be done here /// /// /// public FuncDepBoolType Close_MSAccess(string strArtifactLocation) { var RunningAccessApps = Win32Functions.GetRunningObjectsOfType(); foreach (Microsoft.Office.Interop.Access.Application app in RunningAccessApps) { if (app.CurrentProject.FullName.ToLower() == strArtifactLocation.ToLower()) { // Get Handle and Process IntPtr hWnd = (IntPtr) app.hWndAccessApp(); Process process = Win32Functions.GetProcessFromHandle((IntPtr)hWnd); // Close the database //app.CloseCurrentDatabase(); app.Quit(Microsoft.Office.Interop.Access.AcQuitOption.acQuitSaveAll); Marshal.FinalReleaseComObject(app); // force clean-up // Kill the process process.Kill(); return FuncDepBoolType.Success; } } return FuncDepBoolType.Failed; } #endregion } }