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

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

相关推荐
dujunqiu1 小时前
S32K328上芯片内部RTC的使用和唤醒配置
mcu·计算机外设
嵌入式牛马在努力帮老板娶老婆1 天前
十三、STM32----LCD屏驱动
stm32·嵌入式硬件·计算机外设
MingYue_SSS1 天前
键盘上面有F3,四,R,F,V,按下没有反应,维修记录
嵌入式硬件·计算机外设·解决办法
KWTXX2 天前
单片机键盘接口程序设计(汇编语言)
单片机·计算机外设·nosql
全栈技术负责人3 天前
移动端富文本markdown中表格滚动与页面滚动的冲突处理:Touch 事件 + 鼠标滚轮精确控制方案
前端·javascript·计算机外设
铉铉这波能秀3 天前
解决Mac电脑连接蓝牙鼠标的延迟问题
macos·计算机外设·鼠标
xqlily3 天前
解决戴尔笔记本电脑键盘按键部分失灵
计算机外设·电脑
曹勖之5 天前
如果被控端显示器分辨率是2k,远程控制软件的画质设置是4k,主控端显示器的分辨率是2k,那主控端看到的被控端画面是几k
计算机外设
卡伦啊8 天前
rk键盘 用蓝牙链接 教程
计算机外设