激活运行中的程序实例的窗口

1.问题

禁止程序多实例运行时,防止多实例简单,这里不做介绍。这里着重关注怎样激活运行中的实例的窗口,常规方法都不那么完美,如当目标窗口被其它窗口遮蔽时,想把它置顶,如下方法都没用

  • this.Show();
  • this.Activate();
  • this.BringToFront();
  • ShowWindow(hWnd, SW_RESTORE);
  • SetForegroundWindow(hWnd);

2.两个半吊子方法鉴赏

下面两个方法,能实现激活&置顶,但是有瑕疵,大家不要踩坑。它们具体是

2.1.用this.TopMost=true

实现了对窗口的激活&置顶,但改变了窗口的特性——窗口永久置顶,且总是置于其它窗口之上,这个效果很多余,很可能我们并不希望如此

2.2.先最小化再恢复显示

if (this.Visible)
{
    this.WindowState = FormWindowState.Minimized;
}
this.Show();
this.WindowState = lastWindowState; //Form最后WindowState,但不包括最小化

实现了对窗口的激活&置顶,且是临时置顶。但是,当窗口本身就在顶层可见时,跑上面的代码窗口会肉眼可见夸张的闪烁。

3.推荐方法

摸索出如下方法,不一定是最好的,但保证体验丝滑

用自定义的windows消息通知已存在的实例:请恢复你的窗口显示&临时将窗口置顶

Program.css

实现:

  • 禁止本程序的多实例运行
  • 如果已有实例在运行,则用windows消息通知对方恢复显示
static class Program
{
    [DllImport("user32.dll", SetLastError = true)]
    public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern bool PostMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);

    static void Main()
    {
        // 尝试创建Mutex  
        bool createdNew;
        using (Mutex mutex = new Mutex(false, "APP_MUTEX_ID__MYAPP", out createdNew)) // 常量为自定义值,作为本程序的唯一Id
        {
            if (!createdNew) //创建失败说明已存在。则激活已存在的窗口  
            {
                // 根据Form的Caption查找窗口句柄  
                IntPtr hWnd = FindWindow(null, "我的app的Title");
                if (hWnd != IntPtr.Zero)
                {
                    // 发送自定义消息,要求激活本APP的窗口
                    PostMessage(hWnd, CustomMessages.WM_CUSTOM_MESSAGE_ACTIVEWINDOWS, IntPtr.Zero, IntPtr.Zero);
                }
                else
                {
                    MessageBox.Show("检测到有一个实例正在运行!", "提示");
                }

                // 退出当前实例  
                return;
            }

            // 打开frmMain
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new frmMain());
        }
    }
}

frmMain.css

实现:

监听windows消息,在需要时临时置顶本Form

public partial class frmMain : Form
{
    private FormWindowState lastWindowState;  // Form最后WindowState,但不包括最小化

    public frmMain()
    {
        InitializeComponent();
        this.Text = "我的app的Title";
    }

    private void frmMain_Resize(object sender, EventArgs e)
    {
        if (this.WindowState != FormWindowState.Minimized)
        {
            lastWindowState = this.WindowState;
        }
    }

    // 重写WndProc方法  
    protected override void WndProc(ref Message m)
    {
        switch (m.Msg)
        {
            case CustomMessages.WM_CUSTOM_MESSAGE_ACTIVEWINDOWS: // 自定义消息-激活窗口,实现被外部程序激活本Form
                ShowMe();
                break; 

            default:
                base.WndProc(ref m);
                break;
        }
    }

    private void ShowMe()
    {
        if (this.Visible == false || this.WindowState == FormWindowState.Minimized)
        {
            this.Show();
            this.WindowState = lastWindowState;
        }
        this.TopMost = true;     // 全局置顶
        this.TopMost = false;    // 取消全局置顶,但上句已完成此次置顶
            
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ThorpeTao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值