在面板中杀死进程

时间:2014-07-14 22:11:36

标签: c# winforms forms process handle

我有一个Win Forms应用程序,我在其中从一个不同的.exe文件开始一个进程,然后将它的Handle属性设置为我的Win Form应用程序中的一个面板。这样可以在Win Forms应用程序中运行其他应用程序。

以下是我如何实现这一目标:

[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr SetParent(IntPtr hwc, IntPtr hwp);

string exepath = "myProgram.exe";
ProcessStartInfo p = new ProcessStartInfo(exepath);
process = Process.Start(p);
Thread.Sleep(500);  //sleep to allow program to start up properly        
SetParent(process.MainWindowHandle, pictureBox1.Handle); //then set the handle to give the effect of being run inside the win forms app

现在我知道我可以在FormClosed事件中调用process.Kill(),这会在关闭此窗体时终止进程,但是如果我的Win Form应用程序被强制退出,我将如何杀死该进程?这甚至可能吗?

由于进程的句柄设置为Win Form应用程序中的面板,因此它不会出现在任务栏上,但如果未调用process.Kill(),它仍将继续运行当Win Form强行关闭时会发生。这意味着每次我必须通过任务管理器将其关闭,这很痛苦。

如果无法做到这一点,我不会费心将把手设置到面板上,我将在新窗口中打开它。

由于

2 个答案:

答案 0 :(得分:1)

尝试使用此代码,我使用了很长时间:

public partial class Launcher : Form
{
    /// <summary>Collection of process. </summary>
    private Dictionary<IntPtr, Process> _processCollection = new Dictionary<IntPtr, Process>();

    #region DLL Import


    [DllImport("user32.dll")]
    public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);


    [DllImport("user32.dll", SetLastError = true)]
    public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);

    #endregion


    /// <summary>Default constructor. </summary>
    public Launcher()
    {
        InitializeComponent();

        try {
            FormClosing += Launcher_FormClosing;
            StartInstances();
        }
        catch (Exception ex) {
            MessageBox.Show(ex.Message);
        }
    }

    /// <summary>Starts the instances. </summary>
    private void StartInstances()
    {
        var path = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase);
        var numberOfInstances = Int32.Parse(ConfigurationManager.AppSettings["NumerOfInstances"]);
        for (int i = 0; i < numberOfInstances; i++) {
            StartInstance(i, path);
        }
    }

    /// <summary>Starts an instance. </summary>
    private void StartInstance(int instanceId, string path)
    {
        Process proc = Process.Start(path + "\\foo.exe", instanceId.ToString());
        IntPtr handlerDocked = IntPtr.Zero;

        Panel panel = new Panel();
        panel.Size = new Size(flwPanel.Width / 3, flwPanel.Height / 2);
        flwPanel.Controls.Add(panel);

        do {
            try {
                proc.WaitForInputIdle(1000); //wait for the window to be ready for input;
                proc.Refresh();              //update process info
                if (proc.HasExited) {
                    return; //abort if the process finished before we got a handle.
                }
                handlerDocked = proc.MainWindowHandle;  //cache the window handle
            }
            catch {
                Thread.Sleep(500);
            }

        } while (handlerDocked == IntPtr.Zero);

        //hWndOriginalParent = SetParent(hWndDocked, panel1.Handle);
        SetParent(handlerDocked, panel.Handle);

        var docked = new DockedElement(handlerDocked, panel);

        panel.SizeChanged += new EventHandler(Panel_Resize);
        Panel_Resize(docked, new EventArgs());

        _processCollection.Add(handlerDocked, proc);
    }
    private void Panel_Resize(object sender, EventArgs e)
    {
        var docked = (DockedElement)sender;
        //Change the docked windows size to match its parent's size. 
        MoveWindow(docked.Handle, 0, 0, docked.Container.Width, docked.Container.Height, true);
    }

    /// <summary>Finallize instances. </summary>
    public void FinallizeInstances()
    {

        foreach (var docked in _processCollection) {
            docked.Value.Close();
        }
        _processCollection.Clear();
    }

    private void Launcher_FormClosing(object sender, FormClosingEventArgs e)
    {
        FinallizeInstances();
    }

    protected override void Dispose(bool disposing)
    {
        FinallizeInstances();

        if (disposing && (components != null)) {
            components.Dispose();
        }
        base.Dispose(disposing);
    }
}

答案 1 :(得分:0)

为确保您的子进程在应用程序关闭后(正常或有力)正确擦除,您可以使用Job Objects

  

作业对象允许将进程组作为一个单元进行管理。工作   对象是可控制的,可安全的,可控制的可共享对象   与它们相关的进程的属性。执行的操作   在作业对象上影响与作业对象关联的所有进程。   示例包括强制执行工作集大小和过程等限制   优先级或终止与作业相关的所有进程。

StackOverflow上有一个类似的问题,在C#中有详细的实现:Working example of CreateJobObject/SetInformationJobObject pinvoke in .net?