1

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

现在我希望新实例不仅退出,而且使旧实例激活/显示在桌面上。这是我现在的代码

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

4 回答 4

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());
}
于 2013-08-29T11:54:48.933 回答
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的引用

于 2013-08-29T12:23:34.777 回答
1

我终于从这里得到了我想要的东西。我的主要问题是在关闭新实例的同时从图标托盘中取出旧实例

 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);
}
于 2013-09-11T02:25:18.930 回答
0

您可以使用线程互斥锁和 user32.dll

尝试这个

第 1 步:声明以下常量:

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

通过调用之前的方法

于 2013-08-29T12:02:03.997 回答