当前位置: 首页 > news >正文

Win32 程序在启动时激活前一个启动程序的窗口

UWP 程序天生单实例。当然,新 API (10.0.17134)开始也提供了多实例功能。不过,传统 Win32 程序可就要自己来控制单实例了。

本文介绍简单的几个 Win32 方法调用,使 Win32 程序也支持单实例。


激活之前进程的窗口

我们可以通过进程名称找到此前已经启动过的进程实例,如果发现,就激活它的窗口。

[STAThread]
static void Main(string[] args)
{
    var current = Process.GetCurrentProcess();
    var process = Process.GetProcessesByName(current.ProcessName).FirstOrDefault(x => x.Id != current.Id);
    if (process != null)
    {
        var hwnd = process.MainWindowHandle;
        ShowWindow(hwnd, 9);
        return;
    }

    // 启动自己的主窗口,此部分代码省略。
}

[DllImport("user32.dll")]
private static extern int ShowWindow(IntPtr hwnd, uint nCmdShow);

你一定觉得那个 9 很奇怪,它是多个不同的 nCmdShow 的值:

  • 0 Hide
  • 1 Minimized
  • 2 Maximized
  • 9 Restore

另外,找到的窗口此时可能并不处于激活状态。例如在 Windows 10 中,此窗口可能在其他桌面上。那么我们需要添加额外的代码将其显示出来。

在前面的 ShowWindow 之后,再调用一下 SetForegroundWindow 即可将其激活到最前面来。如果在其他桌面,则会切换到对应的桌面。

[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
var hwnd = process.MainWindowHandle;
ShowWindow(hwnd, 9);
SetForegroundWindow(hwnd);

找到并激活窗口

以上方法适用于普通的主窗口。然而当窗口并不是进程的主窗口,或者 ShowInTaskBar 设为了 false 的时候就不生效了(此时窗口句柄会改变)。

于是,我们需要改用其他的方式来查找窗口。

[STAThread]
static void Main(string[] args)
{
    var hwnd = FindWindow(null, "那个窗口的标题栏文字");
    if (hwnd != IntPtr.Zero)
    {
        ShowWindow(hwnd, 9);
        return;
    }

    // 启动自己的主窗口,此部分代码省略。
}

[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

参考资料

  • Controlling Window State Of Other Applications using C#
  • c# - How to show/hide an application with Visible and ShowInTaskBar as false - Stack Overflow
  • ShowWindowAsync function (Windows)
  • How do I maximize/minimize applications programmatically in C#?

相关文章:

  • C#/.NET 读取或修改文件的创建时间和修改时间
  • 通过解读 WPF 触摸源码,分析 WPF 插拔设备触摸失效的问题(问题篇)
  • .NET 中各种混淆(Obfuscation)的含义、原理、实际效果和不同级别的差异(使用 SmartAssembly)
  • .NET 中 GetProcess 相关方法的性能
  • 常用输入法快速输入自定义格式的时间和日期(搜狗/QQ/手心/微软拼音)
  • 好的框架需要好的 API 设计 —— API 设计的六个原则
  • .NET/C# 使用反射注册事件
  • .NET/C# 判断某个类是否是泛型类型或泛型接口的子类型
  • .NET/C# 使用反射调用含 ref 或 out 参数的方法
  • WPF 多线程 UI:设计一个异步加载 UI 的容器
  • .NET 命令行参数包含应用程序路径吗?
  • 分析现有 WPF / Windows Forms 程序能否顺利迁移到 .NET Core 3.0(使用 .NET Core 3.0 Desktop API Analyzer )
  • C# 空合并操作符(??)不可重载?其实有黑科技可以间接重载!
  • UWP 轻量级样式定义(Lightweight Styling)
  • 预编译框架,开发高性能应用 - 课程 - 微软技术暨生态大会 2018
  • 2018天猫双11|这就是阿里云!不止有新技术,更有温暖的社会力量
  • CentOS7 安装JDK
  • express + mock 让前后台并行开发
  • HomeBrew常规使用教程
  • HTTP那些事
  • Js基础——数据类型之Null和Undefined
  • 力扣(LeetCode)965
  • 三分钟教你同步 Visual Studio Code 设置
  • 一个项目push到多个远程Git仓库
  • 云栖大讲堂Java基础入门(三)- 阿里巴巴Java开发手册介绍
  • ​ssh-keyscan命令--Linux命令应用大词典729个命令解读
  • ​ssh免密码登录设置及问题总结
  • # MySQL server 层和存储引擎层是怎么交互数据的?
  • # Python csv、xlsx、json、二进制(MP3) 文件读写基本使用
  • ## 临床数据 两两比较 加显著性boxplot加显著性
  • #基础#使用Jupyter进行Notebook的转换 .ipynb文件导出为.md文件
  • (6)设计一个TimeMap
  • (附源码)spring boot北京冬奥会志愿者报名系统 毕业设计 150947
  • (算法)Travel Information Center
  • (未解决)jmeter报错之“请在微信客户端打开链接”
  • (原創) 如何刪除Windows Live Writer留在本機的文章? (Web) (Windows Live Writer)
  • (转)Java socket中关闭IO流后,发生什么事?(以关闭输出流为例) .
  • (总结)Linux下的暴力密码在线破解工具Hydra详解
  • .net core开源商城系统源码,支持可视化布局小程序
  • .Net Remoting常用部署结构
  • .NET 跨平台图形库 SkiaSharp 基础应用
  • .NET 中的轻量级线程安全
  • .NET/C# 反射的的性能数据,以及高性能开发建议(反射获取 Attribute 和反射调用方法)
  • .NET运行机制
  • .NET中统一的存储过程调用方法(收藏)
  • [Kubernetes]9. K8s ingress讲解借助ingress配置http,https访问k8s集群应用
  • [MySQL]SQL优化之索引的使用规则
  • [noip2015 d1t2] 信息传递
  • [Oh My C++ Diary]Main函数参数argc,argv如何传入
  • [OIDC in Action] 3. 基于OIDC(OpenID Connect)的SSO(添加Github OAuth 2.0的支持)
  • [PHP]禅道项目管理软件ZenTaoPMS源码包 v16.4
  • [SDOI 2009]HH去散步
  • [SHELL]shell scripts笔记(1)
  • [SpringBoot系列]消息中间件解决方案
  • [UE4]动画蓝图的编辑全流程(Animation Blueprint)