C#:在 Excel 关闭事件上关闭 Windows 窗体

发布于 2024-12-27 09:47:18 字数 177 浏览 2 评论 0原文

我的情况是,我正在开发一个 C# 应用程序,该应用程序正在启动 Microsoft Office Excel 应用程序的实例。
我更改了表单的一些功能,以便在关闭表单时实例化的 Excel 应用程序被终止并从内存中清除。

我想做的就是反其道而行之。我希望我的 Excel 实例在退出时关闭我的 Windows 窗体。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

流云如水 2025-01-03 09:47:18

好吧,我什至没有尝试过这个,所以我不确定它是否会起作用,但你可以尝试以下方法:

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);

更新

尝试以下代码(它不漂亮):

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();
    }
}

问题时使用 Excel 应用程序的一个特点是,即使用户关闭其主窗口,该进程也会继续在后台运行。为了完全释放它,你必须调用 Application.Quit 但你应该只在检测到用户关闭窗口时才这样做,这正是你要解决的问题......你有一个此处循环引用:D

锁定相关的 System.Diagnostics.Process 似乎也不起作用,因为 Exited 事件永远不会被触发(即使您终止来自任务管理器的后台进程)。我的猜测是,只有通过 process = Process.Start(...) 启动的进程才会触发此事件。

所以我能看到的唯一解决方案是轮询 Excel 的主窗口是否可见。一旦不是,这可能意味着用户关闭了主窗口并且 Excel 应用程序应该终止(如果在某些情况下 Excel 的主窗口的可见性可能为 false,而不是当用户想要终止进程时,则此解决方案不适用)有效的)。从那里开始就非常简单了。

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.

七七 2025-01-03 09:47:18

这就是我在同一场景中所做的。

我在类中创建了一个进程

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

然后是关闭应用程序的方法的委托

delegate void KillProcess();
KillProcess aKillProcess;

将委托设置为应用程序关闭方法

aKillProcess = CloseApp;

下面的代码写在按钮单击事件中
这将打开 Excel。这里订阅进程的 Exited 事件。

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

单击 Excel 的关闭按钮时,将调用此方法

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

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

,这将关闭应用程序。

希望这有帮助

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

绾颜 2025-01-03 09:47:18

您的第一次尝试会起作用,只需要为流程引发事件,这就是我为捕获启动的 visio 退出或崩溃所做的事情。

                    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);

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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文