简体   繁体   中英

C# : Closing a windows form on excel closing event

My situation is that I'm developing a C# application which is launching an instance of a Microsoft Office Excel Application.
I change some of the Form's functions so that the instantiated Excel Application is being killed and cleaned up from memory when my Form's being closed.

What I want to do is to perform the opposite. I'd like my instance of Excel to close my windows Form when it's being exited.

This is what i did for the same scenario.

I created a process within the class

System.Diagnostics.Process myProcess = new System.Diagnostics.Process();

Then a delegate to method which closes the app

delegate void KillProcess();
KillProcess aKillProcess;

Setting the delegate to the app closing method

aKillProcess = CloseApp;

This below code is written inside the button click event This opens the excel. Here subscribe for the Exited event of the process

myProcess.StartInfo = new System.Diagnostics.ProcessStartInfo (@"D:\SomeExcel.xlsx");
myProcess.Start();
myProcess.EnableRaisingEvents = true;
myProcess.Exited += new EventHandler(ProcessKilled);

On clicking close button of the excel, this method will be called

private void ProcessKilled(object sender, EventArgs e)
{
    if (this.InvokeRequired)
        this.Invoke(aKillProcess);
    else
        this.Close();
}

void CloseApp()
{
   this.Close();
}

This will close the app.

Hope this helps

Ok, I haven't even tried this so I'm not sure if it will work, but you could try something along these lines:

Microsoft.Office.Interop.Excel.Application excel = ...;

System.Diagnostics.Process excelProcess = null;
var processes = System.Diagnostics.Process.GetProcesses();

foreach (var process in processes)
{
        if (process.Handle.ToInt32() == excel.Hwnd)
            excelProcess = process;
}

excelProcess.Exited += new EventHandler(excelProcess_Exited);

UPDATE

Try the following code (its not pretty):

Microsoft.Office.Interop.Excel.Application xlsApp;
Process xlsProcess;
Timer timer;

public Form1()
{
    xlsApp = new Microsoft.Office.Interop.Excel.Application();
    xlsApp.Visible = true;

    foreach (var p in Process.GetProcesses()) //Get the relevant Excel process.
    {
        if (p.MainWindowHandle == new IntPtr(xlsApp.Hwnd))
        {
            xlsProcess = p;
            break;
        }
    }

    if (xlsProcess != null)
    {
        timer = new Timer();
        timer.Interval = 500;
        timer.Tick += new EventHandler(timer_Tick);
        timer.Start();
    }
}

void timer_Tick(object sender, EventArgs e)
{
    if (xlsApp != null && !xlsApp.Visible)
    {
        //Clean up to make sure the background Excel process is terminated.
        xlsApp.Quit();
        System.Runtime.InteropServices.Marshal.ReleaseComObject(xlsApp);
        xlsApp = null;
    }

    if (xlsProcess.HasExited)
    {
        //The event is not fired but the property is eventually set once the process is terminated
        this.timer.Dispose();
        this.Close();
    }
}

The problem when working with an Excel Application is that even if the user closes it's main window, the process will keep on running in the background. In order to release it completely you have to call Application.Quit but you should only do that when you detect the user closing the window which is exactly the problem you are trying to solve...you have a circular reference here :D

Latching to the relevant System.Diagnostics.Process doesn't seem to work either, as the Exited event never gets fired (not even if you terminate the background process from the task manager). My guess is that this event is fired only with processes launched through process = Process.Start(...) .

So the only solution I can see is polling if Excel`s main window is visible. Once it is not, that probably means the user closed the main window and the Excel application should be terminated (if there is some scenario where Excel's main window's visibility can be false other than when the user wants to terminate the process then this solution is not valid). From there it is pretty straightforward.

Your first try would have worked, just needed to enavle raising of events for the process, this is what I did to catch a launched visio exit or crash.

                    foreach (var process in processes)
                    {
                        try
                        {
                            if (process.MainWindowHandle == new IntPtr(app.WindowHandle32))
                                visioProcess = process;
                        }
                        catch
                        {

                        }
                    }

                    visioProcess.EnableRaisingEvents = true;

                    visioProcess.Exited += new EventHandler(visioProcess_Exited);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM