【window/linux】应用窗口特性及功能开发(信创软件开发)

发布于:2025-08-07 ⋅ 阅读:(12) ⋅ 点赞:(0)

前言

        本篇主要是分享win10及国产桌面操作系统(统信UOS、麒麟kylin系统)的窗口的特性(窗口消息、窗口ID、窗口状态等),及一些功能开发技术点或者是思路(本文的风格是零散的方式分享技术点,不提供源码,仅提供一个编译好的获取到窗口消息的应用)。

背景简述

        信创项目,主要是让用户使用国产化的硬件终端(国产CPU,国产内存等),以及国产操作系统(统信UOS、麒麟kylin系统、欧拉系统等),因为甲方存在很多外设设备无法在Linux中使用(时间太久,厂商不提供Linux下的驱动,比如一台老的打印机,只能在window下使用),那么就需要一个过渡阶段(在Linux中操作window的业务应用),直到业务应用全部转移到国产操作系统为止。

       linux/window之间的窗口应用同步虚拟化方案,是过渡阶段比较主流的成熟方案,比如统信UOS提供的彩虹平台(收费),以及各个瘦客户端厂商自研的方案,都是此类方案为主。

窗口应用分享

window系统

窗口工具

spy++

安装有VC++ 6.0,可以在系统菜单中找到

安装有VS2022的话,可以在IDE的工具菜单中找到

前面数值是窗口句柄ID,后面的类名称,如下图所示:

        包含了很多窗口句柄,但特殊的“窗口”是获取不到的。这里分享一个坑点,系统托盘并不是一个独立窗口,而是一个button(区域),可以通过TrayNotifyWnd/Button获取到系统托盘的数量,但获取不到具体的系统托盘句柄及信息,因为这些button(区域)是系统托盘区域绘画上去的,无法直接获取。

坐标提取工具

window 屏幕坐标获取工具

需要鼠标模拟操作时,用得上这个工具

应用开发

涉及到底层的window API,本人使用VS2022以及QT的MSVC编译器版本进行的开发,常用接口如下:

findWindow()是根据名称获取窗口句柄;

GetParent()通过窗口句柄获取父窗口句柄;

GetWindowThreadProcessId()通过句柄获取进程ID;

GetWindowText()通过窗口句柄获取窗口标题;

GetWindowLongPtr()通过窗口句柄获取窗口样式(判断是否为可见的窗口);

GetClassName()通过窗口句柄窗口类名;

showWindow()通过句柄让窗口显示(最小化到任务栏、显示到桌面等);

SendMessage()向指定的窗口发送事件消息(比如关闭窗口WM_CLOSE);

PostMessage()向指定的窗口发送事件消息(比如关闭窗口WM_CLOSE);

窗口属性

应用窗口中还包含有:对话框、工具框(在任务栏上没有应用图标)等特征。

比如通用对话框的窗口类名中包含"#32770"

让任务栏透明化

本人调研过注册表或者第三方自定义主题工具让任务栏透明/隐藏,效果不如以下代码

void TaskBarWnd::SetTaskbarTransparency(int alpha) {
    HWND hTaskbar = FindWindow(L"Shell_TrayWnd", NULL);
    if (hTaskbar) {
        // 启用窗口透明
        SetWindowLong(hTaskbar, GWL_EXSTYLE,
                      GetWindowLong(hTaskbar, GWL_EXSTYLE) | WS_EX_LAYERED);

        // 设置透明度 (0-255)
        //alpha>0时,值越小,越透明,鼠标可以正常点击任务栏
        //alpha为0时,任务栏消失,鼠标无法点击到任务栏
        SetLayeredWindowAttributes(hTaskbar, 0, alpha, LWA_ALPHA);

        // 禁用DWM过渡动画
        BOOL disableTransitions = TRUE;
        DwmSetWindowAttribute(hTaskbar,
                              DWMWA_TRANSITIONS_FORCEDISABLED,
                              &disableTransitions,
                              sizeof(disableTransitions));
    }
}
监测桌面指定的“图片”

如果需要监测第三方应用是否出现指定的“图片”特征,比如一个唯一性按钮,需要进行点击操作,可以参考我另外的文章python pyautogui 捕捉桌面按钮,并进行点击操作_pyautogui 如何找按钮-CSDN博客

QT常用库主要是以下几个

LIBS += -lPsapi -lcomctl32 -ldwmapi -luser32 -lgdi32

Linux系统

窗口工具

xwininfo

查看窗口信息

xwininfo -id 0x0a400011

xwininfo: Window id: 0xa400011 "mytool : 1"

  Absolute upper-left X:  163  //窗口左上角相对于屏幕左上角的绝对坐标(单位:像素)‌
  Absolute upper-left Y:  29   //窗口左上角相对于屏幕左上角的绝对坐标(单位:像素)‌
  Relative upper-left X:  0    //窗口内容区域相对于窗口边框的偏移量
  Relative upper-left Y:  0    //窗口内容区域相对于窗口边框的偏移量
  Width: 1681                  //窗口内容区域的宽度
  Height: 919                  //窗口内容区域的高度
  Depth: 24
  Visual: 0x21
  Visual Class: TrueColor
  Border width: 0
  Class: InputOutput            //窗口类型为可交互的输入输出窗口‌
  Colormap: 0x20 (installed)
  Bit Gravity State: NorthWestGravity
  Window Gravity State: NorthWestGravity
  Backing Store State: NotUseful
  Save Under State: no
  Map State: IsViewable        //窗口当前可见且未被最小化‌---无效值
  Override Redirect State: no
  Corners:  +163+29  -76+29  -76-132  +163-132 //窗口四个角相对于屏幕的坐标(格式为+X+Y或-X-Y)‌
  -geometry 1681x919-76+29

        以上主要有用的值是XYWidth 和 Height,原本Map State是表示显示/隐藏的,结果测试这个值一直没有变化。

        以上命令行涉及了窗口ID,以下讲解两种窗口ID获取方式:

1、QT获取窗口ID的方法

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)   
     WId windowId = this->winId();
    //转换成字符串
    QString hwndid = QString("0x%1").arg(windowId, 8, 16, QLatin1Char('0'));
}

2、命令行获取方法:wmctl -x -l  (下面详细介绍这个系统命令)

wmctl

第一列(例如:0x0c000006,标识为CLASSID)是当前的窗口句柄,第三列(peony-qt-desktop.桌面,标识为CLASS)是窗口类,第四列(xxxx 桌面,标识为win_name)是应用窗口的名称。

应用场景:把指定窗口激活显示到桌面

wmctrl -i -r <CLASSID> -b remove,hidden && wmctrl -i -a <CLASSID>
xprop

查看窗口状态,实时窗口状态,可以用以下命令行

xprop  -id 0x05a000fc -spy

返回的值及说明如下:

_NET_WM_STATE_MAXIMIZED_HORZ:表示窗口处于水平方向最大化状态(宽度填满屏幕)‌
_NET_WM_STATE_HIDDEN:表示窗口当前处于最小化/隐藏状态(即缩小到任务栏)‌
_NET_WM_STATE_ABOVE:窗口层级属性,表示该窗口被设置为始终显示在其他窗口之上‌
_NET_WM_STATE_STAYS_ON_TOP:窗口置顶属性,即使最小化后恢复仍保持最顶层显示‌
_NET_WM_STATE_MAXIMIZED_VERT:表示窗口处于垂直方向最大化状态(高度填满屏幕)‌
_NET_WM_STATE_FOCUSED:表示窗口当前获得键盘焦点的属性标志

应用开发

Linux对窗口的操作主要是x11(X Window System Version 11),QT项目引入时,需要在.pro文件中加入以下内容

QT += x11extras
LIBS += -lx11 -lxcb

        虽然有开发库,但国产的桌面操作系统(统信UOS、麒麟kylin),界面交互都是高度定制的,x11lib不是很适合作为开发库。

        比如我需要让任务栏上的应用窗口隐藏起来,尝试了很多种方式,全部无效。但是我卸载系统自带的任务栏,安装上开源的第三方任务栏,遵循x11标准的是可以隐藏的。

        比如我需要屏蔽win+D快捷键,x11库是支持捕获键盘的,但是唯独快捷键无法捕获。这些都是国产系统高度定制导致,所以后台命令行反而更适合项目开发选型。

监测窗口是否在桌面显示

写一个定时器,通过xprop命令监测指定窗口是否包含属性:_NET_WM_STATE_HIDDEN

xprop  -id 0x05a000fc|grep "_NET_WM_STATE_HIDDEN"
让窗口在桌面置顶显示

通过wmctrl进行窗口操作

wmctrl -i -r <CLASSID> -b remove,hidden && wmctrl -i -a <CLASSID>

         实际用户场景中,用户会在桌面使用crtl+D,或者点击任务栏最右边的边界处,会导致桌面显示的窗口都被强制最小化,如果开发的是工具型应用(不在任务栏中显示窗口图标),用户是无法再找到窗口的,此时结合以上两个特性,可以让应用一直显示在桌面。


网站公告

今日签到

点亮在社区的每一天
去签到