我正在开发一种工具,可以为我自动执行一些操作。其中一个操作是下载excel文件,在其上运行宏,然后邮寄该文件。在某些情况下,我希望工具只运行excel宏,然后在x秒后退出excel并邮寄文件。这一切都很好,因为我可以等待一段固定的时间。但是,在某些情况下,我希望能够检查和更改excel宏检索到的数据。在这种情况下,我想保持excel打开,直到使用手动关闭excel。当我检测到excel不再打开时,我想邮寄该文件。
这最后一个案例给了我一些麻烦。因为我使用excel interlop来打开excel,所以我不能像正常进程一样使用WaitForExit()。当我手动关闭excel时,该进程也会继续在进程资源管理器中运行。
我在互联网上搜索过解决方案,但没有一个能真正起作用。有什么方法可以用简单的方式实现这个目标吗?
的更新 的 非常感谢您的回复,这对我很有帮助。等待excel现在正确地工作。我使用了以下代码:
if (Settings.ExitExcel)
{
System.Threading.Thread.Sleep(Settings.ExcelTimeout * 1000);
//Close Excel
excelWorkbook.Close();
excelApp.Quit();
}
else
{
Excel.AppEvents_WorkbookBeforeCloseEventHandler Event_BeforeBookClose;
Event_BeforeBookClose = new Excel.AppEvents_WorkbookBeforeCloseEventHandler(WorkbookBeforeClose);
excelApp.WorkbookBeforeClose += Event_BeforeBookClose;
//Wait until excel is closed
while (!isClosed)
{
Thread.Sleep(1000);
}
//Show message
MessageBox.Show("excel closed");
}
//Clean up excel.
Marshal.FinalReleaseComObject(excelSheets);
Marshal.FinalReleaseComObject(excelWorksheet);
Marshal.FinalReleaseComObject(excelWorkbook);
Marshal.FinalReleaseComObject(excelApp);
excelApp = null;
excelWorkbook = null;
excelWorksheet = null;
excelSheets = null;
GC.Collect();
现在唯一的问题是excel仍然在流程中继续运行。我没有正确关闭它吗?
答案 0 :(得分:2)
您可以使用BeforeClose事件执行此操作。基本上,您需要按照以下几点做一些事情:
代码可以是这样的:
//Outside main
private static bool isClosed = false;
....
//Let's say your Workbook object is named book
book.WorkbookBeforeClose += new Excel.AppEvents_WorkbookBeforeCloseEventHandler(app_WorkbookBeforeClose);
if(isClosed)
sendMailMethod();
...
private static void app_WorkbookBeforeClose(Excel.Workbook wb, ref bool cancel)
{
closed = !cancel;
}
此方法不要求您先杀死进程。但是,您应该释放COM对象并在Excel工作完成后结束该过程。
编辑:要关闭该过程,请尝试使用Application.Quit()方法。
答案 1 :(得分:0)
如果您还没有找到解决方案,那么以下是我整理的适用于我的东西。
private async void OnOpenWorkSheetImportCommand(object sender, ExecutedRoutedEventArgs e)
{
try
{
if (e.Parameter is IWorkSheetImportViewModel model)
{
if (WorksheetDictionaries.OfType<WorksheetDictionary>().FirstOrDefault(a => a.Header.Equals(model.Header)) is WorksheetDictionary worksheetDictionary)
{
Type officeType = Type.GetTypeFromProgID("Excel.Application", true);
if (officeType != null)
{
BeforeWorkbookDictionary = worksheetDictionary.WorkbookDictionary;
OpenInteropWorkbookDictionary(worksheetDictionary.WorkbookDictionary, worksheetDictionary, true);
}
else
{
throw new ArgumentException("Microsoft Excel is not installed!");
}
}
}
}
...
..
.
}
调用 OpenInteropWorkbookDictionary 是我设置 Microsoft.Office.Interop.Excel
的地方private void OpenInteropWorkbookDictionary(WorkbookDictionary workbookDictionary, WorksheetDictionary worksheetDictionary, bool activateWorksheet = false)
{
if (ExcelApplication != null && ExcelApplication.Visible == true)
{
ExcelApplication.ActiveWindow.Activate();
IntPtr handler = FindWindow(null, ExcelApplication.Caption);
SetForegroundWindow(handler);
}
else
{
if (ExcelApplication != null) Marshal.FinalReleaseComObject(ExcelApplication);
if (ExcelWorkbook != null) Marshal.FinalReleaseComObject(ExcelWorkbook);
if (ExcelWorksheet != null) Marshal.FinalReleaseComObject(ExcelWorksheet);
if (ExcelWorksheets != null) Marshal.FinalReleaseComObject(ExcelWorksheets);
ExcelApplication = null;
ExcelWorkbook = null;
ExcelWorksheet = null;
ExcelWorksheets = null;
ExcelApplication = new Microsoft.Office.Interop.Excel.Application
{
// if you want to make excel visible to user, set this property to true, false by default
Visible = true,
WindowState = Microsoft.Office.Interop.Excel.XlWindowState.xlMaximized
};
ExcelApplication.WindowActivate += new Microsoft.Office.Interop.Excel.AppEvents_WindowActivateEventHandler(OnWindowActivate);
ExcelApplication.WindowDeactivate += new Microsoft.Office.Interop.Excel.AppEvents_WindowDeactivateEventHandler(OnWindowDeactivate);
ExcelApplication.WorkbookOpen += new Microsoft.Office.Interop.Excel.AppEvents_WorkbookOpenEventHandler(OnWorkbookOpen);
ExcelApplication.WorkbookActivate += new Microsoft.Office.Interop.Excel.AppEvents_WorkbookActivateEventHandler(OnWorkbookActivate);
ExcelApplication.WorkbookDeactivate += new Microsoft.Office.Interop.Excel.AppEvents_WorkbookDeactivateEventHandler(OnWorkbookDeactivate);
// open an existing workbook
ExcelWorkbook = ExcelApplication.Workbooks.Open(BeforeWorkbookDictionary.FilePath, 0, false, 5, "", "", false, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "", true, false, 0, true, false, false);
ExcelWorkbook.BeforeClose += new Microsoft.Office.Interop.Excel.WorkbookEvents_BeforeCloseEventHandler(OnBeforeClose);
ExcelWorkbook.AfterSave += new Microsoft.Office.Interop.Excel.WorkbookEvents_AfterSaveEventHandler(OnAfterSave);
ExcelWorkbook.BeforeSave += new Microsoft.Office.Interop.Excel.WorkbookEvents_BeforeSaveEventHandler(OnBeforeSave);
// SheetEvents
ExcelWorkbook.SheetChange += new Microsoft.Office.Interop.Excel.WorkbookEvents_SheetChangeEventHandler(OnSheetChange);
ExcelWorkbook.SheetSelectionChange += new Microsoft.Office.Interop.Excel.WorkbookEvents_SheetSelectionChangeEventHandler(OnSheetSelectionChange);
ExcelWorkbook.NewSheet += new Microsoft.Office.Interop.Excel.WorkbookEvents_NewSheetEventHandler(OnNewSheet);
ExcelWorkbook.SheetBeforeDelete += new Microsoft.Office.Interop.Excel.WorkbookEvents_SheetBeforeDeleteEventHandler(OnSheetBeforeDelete);
ExcelWorkbook.SheetActivate += new Microsoft.Office.Interop.Excel.WorkbookEvents_SheetActivateEventHandler(OnSheetActivate);
ExcelWorkbook.SheetDeactivate += new Microsoft.Office.Interop.Excel.WorkbookEvents_SheetDeactivateEventHandler(OnSheetDeactivate);
//// get all sheets in workbook
ExcelWorksheets = ExcelWorkbook.Worksheets;
}
if (activateWorksheet)
{
ExcelWorksheet = ExcelWorkbook.Sheets[worksheetDictionary.Name];
ExcelWorksheet.Activate();
}
}
要注意:
因此在 OnWorkbook停用中:
private async void OnWorkbookDeactivate(Microsoft.Office.Interop.Excel.Workbook Wb)
{
try
{
ProgressController = default(ProgressDialogController);
if (ExcelApplication != null && ExcelApplication.Visible == true)
{
int excelProcessId = -1;
GetWindowThreadProcessId(new IntPtr(ExcelApplication.Hwnd), ref excelProcessId);
Process ExcelProc = Process.GetProcessById(excelProcessId);
if (ExcelProc != null)
{
ExitedEventArgs = Observable.FromEventPattern<object, EventArgs>(ExcelProc, MethodParameter.Exited);
DisposableExited = ExitedEventArgs.Subscribe(evt => OnExitedEvent(evt.Sender, evt.EventArgs));
ExcelProc.EnableRaisingEvents = true;
ProgressController = await _dialogCoordinator.ShowProgressAsync(this, string.Format("Workbook {0}", BeforeWorkbookDictionary.ExcelName), "Please wait! Processing any changes...");
ProgressController.SetIndeterminate();
ExcelApplication.Quit();
if (ExcelApplication != null) Marshal.FinalReleaseComObject(ExcelApplication);
if (ExcelWorkbook != null) Marshal.FinalReleaseComObject(ExcelWorkbook);
if (ExcelWorksheet != null) Marshal.FinalReleaseComObject(ExcelWorksheet);
if (ExcelWorksheets != null) Marshal.FinalReleaseComObject(ExcelWorksheets);
ExcelApplication = null;
ExcelWorkbook = null;
ExcelWorksheet = null;
ExcelWorksheets = null;
ExcelProc.WaitForExit();
ExcelProc.Refresh();
}
}
}
catch (Exception msg)
{
...
..
.
}
}
我在课堂上设置了几件事,以使所有这些正常工作:
#region DllImports
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowThreadProcessId(IntPtr hwnd, ref int lpdwProcessId);
#endregion
并且:
#region RoutedEventArgs Properties
private IDisposable disposableClosingEvent;
public IDisposable DisposableClosingEvent
{
get => this.disposableClosingEvent; set => SetProperty(ref disposableClosingEvent, value, nameof(DisposableClosingEvent));
}
private IObservable<EventPattern<object, EventArgs>> exitedEventArgs;
public IObservable<EventPattern<object, EventArgs>> ExitedEventArgs
{
get => exitedEventArgs; set => SetProperty(ref exitedEventArgs, value, nameof(ExitedEventArgs));
}
private IDisposable disposableExited;
public IDisposable DisposableExited
{
get => this.disposableExited; set => SetProperty(ref disposableExited, value, nameof(DisposableExited));
}
#endregion
最后: OnExitedEvent 进行最后一分钟的处理。
private async void OnExitedEvent(object sender, EventArgs e)
{
try
{
DisposableExited.Dispose();
using (SpreadsheetDocument s = SpreadsheetDocument.Open(SelectedWorkbookDictionaryImport.FilePath, false))
{
foreach (Sheet workbookSheet in s.WorkbookPart.Workbook.Sheets)
{
if (WorkbookDictionaryImports.OfType<WorkbookDictionary>().FirstOrDefault(d => d.ExcelName.Equals(SelectedWorkbookDictionaryImport.ExcelName)) is WorkbookDictionary workbookDictionary)
{
if (workbookDictionary.WorksheetDictionaryItems.OfType<WorksheetDictionary>().FirstOrDefault(d => d.Id.Equals(workbookSheet.Id)) == null)
{
Application.Current.Dispatcher.Invoke(() =>
{
WorksheetDictionary worksheetDictionary = new WorksheetDictionary()
{
WorksheetDictionaryId = Guid.NewGuid().ToString(),
IsSelected = false,
Id = workbookSheet.Id,
SheetId = workbookSheet.SheetId,
Name = workbookSheet.Name,
Header = workbookSheet.Name,
HeaderInfo = GetSheetStateValues(workbookSheet.State),
Code = GetSheetCodeValues(workbookSheet.Name.ToString()).ToString(),
Description = BeforeWorkbookDictionary.Subject,
WorkbookDictionary = BeforeWorkbookDictionary
};
workbookDictionary.WorksheetDictionaryItems.Add(worksheetDictionary);
});
}
}
}
}
}
catch (Exception msg)
{
...
..
.
}
finally
{
if (ProgressController != null)
{
await ProgressController.CloseAsync();
ProgressController = default(ProgressDialogController);
}
}
}
希望这会帮助您和其他人进行粗略的更改,以满足您的处理需求。