仅运行应用程序的一个实例,(退出新实例并显示旧实例或授予焦点)

时间:2013-08-29 11:44:59

标签: c# winforms

我的应用有默认设置,可让您在启动计算机时在图标托盘上运行。 如果单击图标托盘中的图标,则应用程序将显示在桌面窗口中。 此外,如果用户尝试在旧应用程序运行时尝试启动我的应用程序的新实例,我只会显示另一个实例正在运行的消息,然后退出新实例。

现在我希望New实例不仅可以退出,还可以在桌面上激活/显示Old实例。 这是我现在的代码

if (System.Diagnostics.Process.GetProcessesByName(
           System.Diagnostics.Process.GetCurrentProcess().ProcessName).Length > 1)
{
    MessageBox.Show(kingCobra.Properties.Resources.Msg_Multiple_Starts, 
                    kingCobra.Properties.Resources.Multiple_Starts,
                    MessageBoxButtons.OK, MessageBoxIcon.Warning);
    System.Diagnostics.Process.GetCurrentProcess().Kill();
    return;
}

4 个答案:

答案 0 :(得分:2)

您需要做的是将其添加到您的主类:

[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);

然后你需要获得对已经运行的进程的引用,然后像这样调用SetForegroundWindow方法:

  SetForegroundWindow(SameProcess.MainWindowHandle);

您不需要像当前那样杀死当前进程,只需在关注其他进程的主窗口后返回,如上所示

这是一个完整的工作示例:

[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);


/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
    var currentProcess = Process.GetCurrentProcess();

    foreach (Process p in Process.GetProcessesByName(currentProcess.ProcessName))
    {
        if (p.Id != currentProcess.Id)
        {
            MessageBox.Show("Already running");
            SetForegroundWindow(p.MainWindowHandle);
            return;
        }
    }

    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new Form1());
}

答案 1 :(得分:2)

这是我见过完成这项工作的最佳方式。

public class SingleInstanceController : WindowsFormsApplicationBase
{
    public SingleInstanceController()
    {
        IsSingleInstance = true;
    }

    protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs)
    {
        Form1 form = MainForm as Form1;
        form.Text = "I will run only once!";
        form.Activate();

        base.OnStartupNextInstance(eventArgs);
    }

    protected override void OnCreateMainForm()
    {
        MainForm = new Form1();
    }
}

static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        string[] args = Environment.GetCommandLineArgs();
        SingleInstanceController controller = new SingleInstanceController();
        controller.Run(args);
    }
}

本文中的实际代码Single Instance Application

注意:这需要您添加 Microsoft.VisualBasic.dll

的引用

答案 2 :(得分:1)

我终于从Here获得了我想要的东西。我的主要问题是在关闭新的

时从Icon托盘中带来旧实例
 static class Program
{
    [STAThread]
    static void Main()
    {
        if (!SingleInstance.Start()) {
            SingleInstance.ShowFirstInstance();
            return;
        }

    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);

    try {
        MainForm mainForm = new MainForm();
        Application.Run(mainForm);
    } catch (Exception e) {
        MessageBox.Show(e.Message);
    }

    SingleInstance.Stop();
}
} 
//And secondly within your main form, the following code must be added:

protected override void WndProc(ref Message message)
{
    if (message.Msg == SingleInstance.WM_SHOWFIRSTINSTANCE) {
        Show

Window();
    }
    base.WndProc(ref message);
} 

public void ShowWindow()
{
    // Insert code here to make your form show itself.
    WinApi.ShowToFront(this.Handle);
}

答案 3 :(得分:0)

您可以使用Threading Mutex和user32.dll

试试这个

第1步: 声明以下constantes:

private const int SW_NORMAL = 1; // see WinUser.h for definitions
private const int SW_SHOWMAXIMIZED = 3;
private const int SW_RESTORE = 9;

[DllImport("User32", EntryPoint = "FindWindow")]
static extern IntPtr FindWindow(string className, string windowName);

[DllImport("User32", EntryPoint = "SendMessage")]
private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

[DllImport("User32", EntryPoint = "SetForegroundWindow")]
private static extern bool SetForegroundWindow(IntPtr hWnd);

[DllImport("User32", EntryPoint = "SetWindowPlacement")]
private static extern bool SetWindowPlacement(IntPtr hWnd, [In] ref WINDOWPLACEMENT lpwndpl);

[DllImport("User32", EntryPoint = "GetWindowPlacement")]
private static extern bool GetWindowPlacement(IntPtr hWnd, [In] ref WINDOWPLACEMENT lpwndpl);


private struct WINDOWPLACEMENT
{
    public int length;
    public int flags;
    public int showCmd;
}

第2步: 添加此方法:

public void application_run(Form form1)
{
bool createdNew;

            System.Threading.Mutex m = new System.Threading.Mutex(true, form1.Name, out createdNew);
            if (!createdNew)
            {
                MessageBox.Show("...", "...", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);//Alert message

                try
                {
                    // see if we can find the other app and Bring it to front
                    IntPtr hWnd = FindWindow(null, form1.Text);
                    if (hWnd != IntPtr.Zero)
                    {
                        LoaderDomain.WINDOWPLACEMENT placement = new LoaderDomain.WINDOWPLACEMENT();
                        placement.length = Marshal.SizeOf(placement);
                        GetWindowPlacement(hWnd, ref placement);
                        placement.showCmd = SW_SHOWMAXIMIZED;
                        SetWindowPlacement(hWnd, ref placement);
                        SetForegroundWindow(hWnd);
                    }
                }
                catch 
                {
                    //rien
                }

            }
            else
            {
                Application.Run(form1);
            }
            // keep the mutex reference alive until the normal termination of the program
            GC.KeepAlive(m);

}

第3步: 替换主

Application.run(forms);

通过调用之前的方法