多显示器窗口分布规律探索(包括WorkerW的区域)

新知引入

在许多壁纸应用程序中,它们大多都支持多显示器的分布,而对于Windows的多显示器而言,它的窗口不可能是多边形

整个大窗口的布局其实是这2块显示屏的外边缘组成的大矩形,即

而在.net里面,有一个专门的类去管理显示器的虚拟区域

vbnet 复制代码
Dim s As Screen() = Screen.AllScreens

这一个方法可以给s附上所有显示器的数据,包括系统分配的设备名称、各个显示器的虚拟位置,其中,非常值得注意的一点是,虚拟桌面的坐标原点为主显示器(显示器1)的坐标原点(左上角)

因此,上图的红色大矩形数据为

转换为Rectangle为:-2048 -442 3968 1536

然后,事情就变得非常好办了,由于在显示器内,窗口的坐标是按照显示器的坐标原点来计算的,但是,WorkerW作为桌面背景层,它的区域就是上图的红色大矩形,并且中的并且,如果你想要设置一个窗口嵌入WorkerW,那么你就需要将不同显示器的坐标转换到WorkerW作为Parent的坐标。

说的有点绕了,简言之就是那个大矩形就是WorkerW的主窗体,然后你要嵌入窗口并且想要让壁纸准确出现在不同显示器上就要换算对应显示器区域在WorkerW上的哪一个位置

我们来使用代码来解释

vbnet 复制代码
 BackPalyer.Show()
 Threading.Thread.Sleep(100)
 Dim s As Screen() = Screen.AllScreens

 Dim Wrect As RECT
 GetWindowRect(&H60950, Wrect)
 Dim ToWorkerWRect As New List(Of Rectangle)

 For Each i In s
     Dim p As New Point(i.Bounds.X - Wrect.Left, i.Bounds.Y - Wrect.Top)
     ToWorkerWRect.Add(New Rectangle(p.X, p.Y, i.Bounds.Width, i.Bounds.Height))
 Next
 SetParent(BackPalyer.Handle, &H60950)
 BackPalyer.DesktopBounds = ToWorkerWRect(0)

解读一下:

延时100ms可以不写,s()是当前所有显示器的集合,Wrect是WorkerW的窗口rect,&H60950是WorkerW的句柄(注意,此处为了方便理解,实则每一次重启explorer都会变!先不要着急复制代码,下面会给出方法!)

在循环过程中,p的作用是换算的显示器在WorkerW上的位置,循环添加到列表

最后使用SetParent设置桌面背景,然后按照显示器bound设置壁纸窗口的DesktopBounds

如何获取壁纸层的句柄?

参考文章:桌面壁纸层嵌入窗口(wallpaper engine核心)原理讲解

或者改一下代码

vbnet 复制代码
Public Sub GetWorkerWHandle(ByVal videoPtr As IntPtr) As IntPtr
    Dim windows_version As Double = Environment.OSVersion.Version.Major
    progmanPtr = FindWindow("Progman", Nothing)
 
    If progmanPtr = IntPtr.Zero Then
        MessageBox.Show("当前系统可能不支持运行本程序或者卡死")
        Return
    Else
        SendMessageTimeout(progmanPtr, &H52C, IntPtr.Zero, IntPtr.Zero, 0, &H3E8, sendMessageBack)
        EnumWindows(Function(hwnd, param)
 
                        If Win32.FindWindowEx(hwnd, IntPtr.Zero, "SHELLDLL_DefView", Nothing) <> IntPtr.Zero Then
                            workWPtr = Win32.FindWindowEx(IntPtr.Zero, hwnd, "WorkerW", Nothing)
 
                            If windows_version < 6.2 Then
                                Win32.ShowWindow(workWPtr, 0)
                            End If
                        End If
 
                        Return True
                    End Function, 0)
 
        If windows_version < 6.2 Then
            return progmanPtr
        Else
            return workWPtr
        End If
 
        
    End If
End Sub

经过测试,至此窗口可以被正确的嵌入桌面背景层了

相关推荐
双翌视觉2 天前
高精度视觉对位实现键盘线路薄膜定位纠偏
数码相机·计算机外设
今夕资源网2 天前
windows11无法启用投屏功能 无线显示器无法添加可选功能 解决办法 Miracast修复脚本
windows·计算机外设·miracast·系统修复·无线显示器·投屏功能·投屏功能无法添加
人工智能导论实践课3 天前
从零到一:用 ROS Noetic 搭建可键盘控制的 Gazebo 小车模型
计算机外设
站长工具箱3 天前
鼠标在线测试工具:全维度检测鼠标性能,本地处理更安全
测试工具·计算机外设
开开心心就好3 天前
免费轻量级PDF阅读器,打开速度快
windows·计算机视觉·visualstudio·pdf·计算机外设·excel·myeclipse
春日见4 天前
Matlab快速入门 基础语法教学
java·开发语言·驱动开发·matlab·docker·计算机外设
Saniffer_SH4 天前
【高清视频】AI服务器调试利器:PCIe功耗分析设备 Quarch PAM 深度解析
网络·人工智能·驱动开发·嵌入式硬件·测试工具·计算机外设·压力测试
Never_Satisfied4 天前
在JavaScript / HTML中,监听鼠标滚动事件
javascript·html·计算机外设
触想工业平板电脑一体机5 天前
【触想智能】工业触摸屏显示器的主要特点以及其应用领域分析
计算机外设
TESmart碲视6 天前
Mac+PC双系统如何共享双屏?KVM切换器选购的5个关键指标|TESmart用户真实体验复盘
macos·计算机外设·kvm切换器·tesmart·双屏kvm切换器·碲视