多显示器窗口分布规律探索(包括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

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

相关推荐
呉師傅21 小时前
国产麒麟系统卡启动项或图标如何解决
运维·网络·windows·计算机外设·电脑
触想工业平板电脑一体机1 天前
【触想智能】工业触控一体机在船舶海运设备上应用的特点和具体场景分析
android·网络·计算机外设·电脑·智能电视
企鹅侠客2 天前
定时坐标鼠标点击器
计算机外设·定时点击·鼠标点击
TESmart碲视2 天前
M4芯片MacBook支持多显示器吗?mac如何与KVM切换器使用。
macos·计算机外设·mst·kvm切换器·双屏kvm切换器
jmu-pfm4 天前
联想拯救者Y7000P遇到键盘失灵USB接口失效问题
计算机外设
斌蔚司李4 天前
外接显示器无法使用键盘/鼠标问题解决
计算机外设
电脑小管家4 天前
DirectX报错怎么办?快速修复游戏和软件崩溃问题
windows·驱动开发·microsoft·计算机外设·电脑
极客先躯4 天前
如何修复 ECharts 鼠标交互(如 hover、点击)位置错位的问题
计算机外设·echarts·交互
uuleaf5 天前
打字速度练习:零基础14天提升到80CPM键盘打字指南
计算机外设