首页 > 解决方案 > Windows 10 中的多显示器设置中的每台显示器的不同壁纸

问题描述

有许多关于在 Windows 中以编程方式在多显示器设置上设置壁纸的问题和答案,但我专门针对 Windows 10(可能还有 Windows 8)询问,因为它的工作方式似乎与我发现的所有解释不同。

Raymond Chen 有一篇文章《如何在每台显示器上放置不同的壁纸?》( https://devblogs.microsoft.com/oldnewthing/?p=25003 ),也在Windows 壁纸上的监视器位置中引用。核心概念是 Windows 将提供的位图的左上角放在主显示器的左上角,并环绕以填充左侧和/或上方的任何桌面空间。我明白,我使用这些知识编写了一个小程序,它在 Windows 7 中运行良好。

它是如何工作的:我创建了一个位图,它在概念上涵盖了用户所看到的整个桌面空间。我将每个监视器的内容绘制到该位图的适当位置(程序是使用 VCL 用 C++ 编写的,但在其他编程环境中原理保持不变):

TRect GetMonitorRect_WallpaperCoords(int MonitorNum)
{
  Forms::TMonitor *PrimaryMonitor = Screen->Monitors[0];
  Forms::TMonitor *Monitor = Screen->Monitors[MonitorNum];
  // Get the rectangle in desktop coordinates
  TRect Rect(Monitor->Left, Monitor->Top, Monitor->Left + Monitor->Width, Monitor->Top + Monitor->Height);
  // Convert to wallpaper coordinates
  Rect.Left += PrimaryMonitor->Left - Screen->DesktopLeft;
  Rect.Top += PrimaryMonitor->Top - Screen->DesktopTop;
  Rect.Right += PrimaryMonitor->Left - Screen->DesktopLeft;
  Rect.Bottom += PrimaryMonitor->Top - Screen->DesktopTop;
  return Rect;
}

std::unique_ptr<Graphics::TBitmap> CreateWallpaperBitmap_WallpaperCoords()
{
  std::unique_ptr<Graphics::TBitmap> Bmp(new Graphics::TBitmap);
  Bmp->PixelFormat = pf24bit;
  Bmp->Width = Screen->DesktopWidth;
  Bmp->Height = Screen->DesktopHeight;

  // Draw background (not that we really need it: it will never be visible)
  Bmp->Canvas->Brush->Style = bsSolid;
  Bmp->Canvas->Brush->Color = clBlack;
  Bmp->Canvas->FillRect(TRect(0, 0, Bmp->Width, Bmp->Height));

  for (int MonitorNum = 0; MonitorNum < Screen->MonitorCount; ++MonitorNum)
    {
    TDrawContext DC(Bmp->Canvas, GetMonitorRect_WallpaperCoords(MonitorNum));
    DrawMonitor(DC);
    }

  return Bmp;
}

(绘制上下文使用坐标转换 rect 以便代码 int DrawMonitor 函数可以在像 (0, 0, 1920, 1080) 这样的矩形中绘制,而不必怀疑它在完整位图中绘制的位置,并且使用剪辑 rect 所以DrawMonitor 不会意外地在它正在绘制的监视器之外绘制)。

然后我将该位图转换为在放置在主显示器左上角时可以正确环绕的图像(正如 Raymond Chen 在他的文章中所描述的那样):

std::unique_ptr<Graphics::TBitmap> ConvertWallpaperToDesktopCoords(std::unique_ptr<Graphics::TBitmap> &Bmp_WallpaperCoords)
{
  std::unique_ptr<Graphics::TBitmap> Bmp_DesktopCoords(new Graphics::TBitmap);
  Bmp_DesktopCoords->PixelFormat = Bmp_WallpaperCoords->PixelFormat;
  Bmp_DesktopCoords->Width = Bmp_WallpaperCoords->Width;
  Bmp_DesktopCoords->Height = Bmp_WallpaperCoords->Height;

  // Draw Bmp_WallpaperCoords to Bmp_DesktopCoords at four different places to account for all
  // possible ways Windows wraps the wallpaper around the left and bottom edges of the desktop
  // space
  Bmp_DesktopCoords->Canvas->Draw(Screen->DesktopLeft, Screen->DesktopTop, Bmp_WallpaperCoords.get());
  Bmp_DesktopCoords->Canvas->Draw(Screen->DesktopLeft + Screen->DesktopWidth, Screen->DesktopTop, Bmp_WallpaperCoords.get());
  Bmp_DesktopCoords->Canvas->Draw(Screen->DesktopLeft, Screen->DesktopTop + Screen->DesktopHeight, Bmp_WallpaperCoords.get());
  Bmp_DesktopCoords->Canvas->Draw(Screen->DesktopLeft + Screen->DesktopWidth, Screen->DesktopTop + Screen->DesktopHeight, Bmp_WallpaperCoords.get());

  return Bmp_DesktopCoords;
}

然后我通过在注册表中写入适当的值并使用 SPI_SETDESKWALLPAPER 调用 SystemParametersInfo 来将该位图安装为墙纸:

void InstallWallpaper(const String &Fn)
{
  // Install wallpaper:
  // There are 3 name/data pairs that have an effect on the desktop wallpaper, all under HKCU\Control Panel\Desktop:
  //  - Wallpaper (REG_SZ): file path and name of wallpaper
  //  - WallpaperStyle (REG_SZ):
  //    . 0: Centered
  //    . 1: Tiled
  //    . 2: Stretched
  //  - TileWallpaper (REG_SZ):
  //    . 0: Don't tile
  //    . 1: Tile
  //  We don't use the Wallpaper value itself; instead we use SystemParametersInfo to set the wallpaper.

  // The file name needs to be absolute!
  assert(Ioutils::TPath::IsPathRooted(Fn));

  std::unique_ptr<TRegistry> Reg(new TRegistry);
  Reg->RootKey = HKEY_CURRENT_USER;
  if (Reg->OpenKey(L"Control Panel\\Desktop", false))
    {
    Reg->WriteString(L"WallpaperStyle", L"1");
    Reg->WriteString(L"TileWallpaper", L"1");
    Reg->CloseKey();
    }
  SystemParametersInfoW(SPI_SETDESKWALLPAPER, 1, Fn.c_str(), SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
}

但是当我在 Windows 10 中对其进行测试时,它不再正常工作:Windows 10 将壁纸完全放错了位置。看到其他人过去曾问过有关多显示器壁纸的问题,我希望有人在 Windows 10 上有经验。

标签: windows-10vclmultiple-monitorswallpaper

解决方案


据我所知,Windows 10 将提供的位图的左上角放置在桌面空间的左上角(我的意思是所有显示器的边界矩形),而不是左上角主监视器。在代码中,这意味着:我省略了 ConvertWallpaperToDesktopCoords 步骤,然后就我所见,它工作正常。

但是我找不到这方面的任何文档,所以我不知道这是否正式解释了 Windows 10 是如何做到的。小心使用。我也不知道这种不同的行为是什么时候开始的:在 Windows 10 中,或者在 Windows 8 中更早的版本。


推荐阅读