У меня есть процесс очистки оставшихся экземпляров взаимодействия.
Процесс работает как задумано, но я нахожу странный эффект.
Без точек останова EnvironmentFunctions.ProcessExists(ExcelAppProccessID)
возвращает True
, но если бы я поставил точку останова до EnvironmentFunctions.ProcessExists(ExcelAppProccessID)
, то метод вернул бы False
У меня были похожие проблемы, когда я былработа с VBA и решение было использовать DoEvents
. При поиске сопоставимого метода для C # я наткнулся на множество примеров, использующих Application.Current...
, но, поскольку я нахожусь в процессе выхода из приложения, возвращается null
.
Я также пытался Sleep
, но кажется, что он никогда не проснется, чтобы продолжить выполнение.
Как мне смоделировать (точку останова и возобновление) / DoEvents / Ожидание x время / Позволить другим процессам выполнить свои действия / ... так что мой метод возвращает False
Метод, связанный сна этот пост. Я разместил полный класс в нижней части этого поста.
public void BreakAllConnections()
{
try
{
if (_excelApp != null)
{
foreach (Excel.Workbook wb in _excelApp.Workbooks)
{
foreach(Excel.Worksheet ws in wb.Sheets)
{
Marshal.FinalReleaseComObject(ws);
}
wb.Close(0);
Marshal.FinalReleaseComObject(wb);
}
Marshal.FinalReleaseComObject(_excelApp.Workbooks);
_excelApp.Quit();
Marshal.FinalReleaseComObject(_excelApp);
_excelApp = null;
}
}
catch
{
try
{
Process.GetProcessById(ExcelAppProccessID).Kill();
Console.WriteLine("Had To Force Kill Excel");
}
catch
{
Console.WriteLine("Could Not Force Kill Excel");
}
}
try
{
if (_accessApp != null)
{
_accessApp.CloseCurrentDatabase();
_accessApp.Quit();
Marshal.FinalReleaseComObject(_accessApp);
_accessApp = null;
}
}
catch
{
try
{
Process.GetProcessById(AccessAppProccessID).Kill();
Console.WriteLine("Had To Force Kill Access");
}
catch
{
Console.WriteLine("Could Not Kill Access");
}
}
int c=0;
while (Marshal.AreComObjectsAvailableForCleanup() | c==0)
{
GC.Collect();
GC.WaitForPendingFinalizers();
if (c++ > 5) break;
}
if (EnvironmentFunctions.ProcessExists(ExcelAppProccessID))
{
try
{
Process.GetProcessById(ExcelAppProccessID).Kill();
Console.WriteLine("Had To Force Kill Excel Post GC");
}
catch
{
Console.WriteLine("Could Not Force Kill Excel Post GC");
}
}
if (EnvironmentFunctions.ProcessExists(AccessAppProccessID))
{
try
{
Process.GetProcessById(AccessAppProccessID).Kill();
Console.WriteLine("Had To Force Kill Access Post GC");
}
catch
{
Console.WriteLine("Could Not Force Kill Access Post GC");
}
}
GC.Collect();
GC.WaitForPendingFinalizers();
}
И мой метод ProcessExists.
static public bool ProcessExists(int id)
{
if (id == 0) return false;
return Process.GetProcesses().Any(x => x.Id == id);
}
Для справки Полный класс управления взаимодействием.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows;
using Excel = Microsoft.Office.Interop.Excel;
using Access = Microsoft.Office.Interop.Access;
using System.Windows.Threading;
using System.Reactive.Linq;
namespace Tenant_Tool_Analytics_Module.Utillity
{
public class ConnectionManager
{
[DllImport("user32.dll")]
static extern int GetWindowThreadProcessId(int hWnd, out int lpdwProcessId);
//Old Code for tying to resolve flashing access window.
//[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
//public static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);
public static readonly ConnectionManager instance = new ConnectionManager();
private ConnectionManager()
{
Console.WriteLine("Connection Manager Started");
AppDomain.CurrentDomain.ProcessExit += new EventHandler(OnProcessExit);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(OnProcessExit);
}
void OnProcessExit(object sender, EventArgs e)
{
BreakAllConnections();
}
private Excel.Application _excelApp;
private int ExcelAppProccessID;
public Excel.Application excelApp
{
get
{
if (_excelApp == null)
{
try
{
_excelApp = new Excel.Application();
GetWindowThreadProcessId(_excelApp.Hwnd, out ExcelAppProccessID);
_excelApp.ScreenUpdating = false;
}
catch
{
//TODO Move message box to parents
MessageBox.Show("Abort Error: Could not open Excel Application");
}
}
return _excelApp;
}
}
private Access.Application _accessApp;
private int AccessAppProccessID;
public Access.Application accessApp
{
get
{
if (_accessApp == null)
{
try
{
//MessageBox.Show($"OS: {EnvironmentFunctions.is64BitOperatingSystem} Process: {EnvironmentFunctions.is64BitProcess}");
if (EnvironmentFunctions.is64BitOperatingSystem && !EnvironmentFunctions.is64BitProcess)
{
string PathValue = "";
string sAdd = "";
string strCommonFiles =
System.Environment.GetEnvironmentVariable("CommonProgramFiles(x86)");
sAdd = ";" + strCommonFiles + "\\microsoft shared\\DAO";
PathValue = System.Environment.GetEnvironmentVariable("Path");
PathValue += sAdd;
Environment.SetEnvironmentVariable("path", PathValue);
}
_accessApp = new Access.Application();
GetWindowThreadProcessId(_accessApp.hWndAccessApp(), out AccessAppProccessID);
}
catch
{
MessageBox.Show("Termination Error: Could not open Access Application");
Environment.Exit(110);
}
}
return _accessApp;
}
}
public void BreakAllConnections()
{
try
{
if (_excelApp != null)
{
foreach (Excel.Workbook wb in _excelApp.Workbooks)
{
foreach(Excel.Worksheet ws in wb.Sheets)
{
Marshal.FinalReleaseComObject(ws);
}
wb.Close(0);
Marshal.FinalReleaseComObject(wb);
}
Marshal.FinalReleaseComObject(_excelApp.Workbooks);
_excelApp.Quit();
Marshal.FinalReleaseComObject(_excelApp);
_excelApp = null;
}
}
catch
{
try
{
Process.GetProcessById(ExcelAppProccessID).Kill();
Console.WriteLine("Had To Force Kill Excel");
}
catch
{
Console.WriteLine("Could Not Force Kill Excel");
}
}
try
{
if (_accessApp != null)
{
_accessApp.CloseCurrentDatabase();
_accessApp.Quit();
Marshal.FinalReleaseComObject(_accessApp);
_accessApp = null;
}
}
catch
{
try
{
Process.GetProcessById(AccessAppProccessID).Kill();
Console.WriteLine("Had To Force Kill Access");
}
catch
{
Console.WriteLine("Could Not Kill Access");
}
}
var minFrameDelay = Observable.Interval(TimeSpan.FromMilliseconds(50)).Take(1).Replay();
minFrameDelay.Connect();
// synchronously add a low-priority no-op to the Dispatcher's queue
Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(() => minFrameDelay.Wait()));
int c=0;
while (Marshal.AreComObjectsAvailableForCleanup() | c==0)
{
GC.Collect();
GC.WaitForPendingFinalizers();
if (c++ > 5) break;
}
if (EnvironmentFunctions.ProcessExists(ExcelAppProccessID))
{
try
{
Process.GetProcessById(ExcelAppProccessID).Kill();
Console.WriteLine("Had To Force Kill Excel Post GC");
}
catch
{
Console.WriteLine("Could Not Force Kill Excel Post GC");
}
}
if (EnvironmentFunctions.ProcessExists(AccessAppProccessID))
{
try
{
Process.GetProcessById(AccessAppProccessID).Kill();
Console.WriteLine("Had To Force Kill Access Post GC");
}
catch
{
Console.WriteLine("Could Not Force Kill Access Post GC");
}
}
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
}