【问题标题】:Running only one instance of an application,(Quit new instance and Display old instance or give Focus)只运行一个应用程序的实例,(退出新实例并显示旧实例或给予焦点)
【发布时间】:2013-08-29 11:44:59
【问题描述】:

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

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

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

【问题讨论】:

标签: c# winforms


【解决方案1】:

你需要做的就是把它添加到你的主类中:

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

【讨论】:

  • 感谢您的回答,您的方法看起来很直接而且很好:但不幸的是,从到目前为止的测试来看,我无法实现我想要的。 ==> SetForegroundWindow(p.MainWindowHandle);//如果窗口处于正常状态,则将窗口置顶 Most ==> ShowWindow(p.MainWindowHandle, WindowShowStyle.ShowNormal); //如果窗口处于最小化或最大状态,则使其处于最顶层和正常状态 ==> 当程序在托盘中时,两者似乎都不起作用
【解决方案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

的引用

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

    • 我从 CodeProject 中提取了该代码,并将其几乎逐字插入到使用系统托盘的 Winforms 项目中,并且可以正常工作。
    • 很高兴知道该链接对某人有用。
    【解决方案4】:

    您可以使用 Threading Mutex 和 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);
    

    通过调用之前的方法

    【讨论】:

    • 使用互斥体是可以的,但是通过其 Text 属性识别另一个窗口是脏的!如果文本更改运行时怎么办?
    • 我在 msdn 上读回了 FindWindow 函数,如果需要,您可以使用 className 代替窗口标题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-10
    • 2013-02-18
    • 2012-08-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多