Как приостановить выполнение кода в методе, вызываемом при выходе из приложения - PullRequest
0 голосов
/ 04 ноября 2019

У меня есть процесс очистки оставшихся экземпляров взаимодействия.

Процесс работает как задумано, но я нахожу странный эффект.

Без точек останова 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();
        }
    }
}
...