Windows 10 在Windows 10的多显示器设置中,每个显示器的墙纸不同

Windows 10 在Windows 10的多显示器设置中,每个显示器的墙纸不同,windows-10,vcl,multiple-monitors,wallpaper,Windows 10,Vcl,Multiple Monitors,Wallpaper,关于在Windows中以编程方式在多显示器设置上设置墙纸,有很多问题和答案,但我特别针对Windows 10(可能还有Windows 8),因为它的工作方式似乎与我找到的所有解释都不同 雷蒙德·陈(Raymond Chen)有一篇文章“如何在每个显示器上放置不同的墙纸?”(),也被《华尔街日报》引用。其核心概念是Windows将提供的位图的左上角放置在主监视器的左上角,并环绕以填充左侧和/或上方的任何桌面空间。我明白这一点,我用这些知识编写了一个小程序,它在Windows7中运行得很好 工作原理

关于在Windows中以编程方式在多显示器设置上设置墙纸,有很多问题和答案,但我特别针对Windows 10(可能还有Windows 8),因为它的工作方式似乎与我找到的所有解释都不同

雷蒙德·陈(Raymond Chen)有一篇文章“如何在每个显示器上放置不同的墙纸?”(),也被《华尔街日报》引用。其核心概念是Windows将提供的位图的左上角放置在主监视器的左上角,并环绕以填充左侧和/或上方的任何桌面空间。我明白这一点,我用这些知识编写了一个小程序,它在Windows7中运行得很好

工作原理:我创建了一个位图,在概念上覆盖了用户看到的整个桌面空间。我将每个监视器的内容绘制到适当位置的位图(程序是用VCL用C++编写的,但在其他编程环境中的原理仍然是一样的):

TRect getmonitorect\u壁纸库(int-MonitorNum)
{
表单::TMonitor*PrimaryMonitor=Screen->Monitors[0];
表单::TMonitor*Monitor=Screen->Monitors[MonitorNum];
//获取桌面坐标中的矩形
TRect Rect(监视器->左,监视器->顶,监视器->左+监视器->宽度,监视器->顶+监视器->高度);
//转换为墙纸坐标
Rect.Left+=PrimaryMonitor->Left-Screen->DesktopLeft;
Rect.Top+=PrimaryMonitor->Top-Screen->DesktopTop;
Rect.Right+=PrimaryMonitor->Left-Screen->DesktopLeft;
Rect.Bottom+=PrimaryMonitor->Top-Screen->DesktopTop;
返回矩形;
}
std::unique_ptr CreateWallpaperBitmap_wallpercoords()
{
std::unique_ptr Bmp(新图形::TBitmap);
Bmp->PixelFormat=PF24位;
Bmp->Width=屏幕->桌面宽度;
Bmp->高度=屏幕->桌面高度;
//绘制背景(并非我们真的需要它:它永远不会可见)
Bmp->Canvas->Brush->Style=bsSolid;
Bmp->画布->画笔->颜色=黑色;
Bmp->Canvas->FillRect(TRect(0,0,Bmp->Width,Bmp->Height));
对于(int MonitorNum=0;MonitorNumMonitorCount;++MonitorNum)
{
TDrawContext DC(Bmp->Canvas,GetMonitorRect_壁纸库(MonitorNum));
牵引监视器(DC);
}
返回Bmp;
}
(draw上下文使用坐标转换矩形,这样code int DrawMonitor函数就可以在(0、0、1920、1080)这样的矩形中绘制,而不必怀疑它在整个位图中的哪个位置绘制,并且使用clip矩形,这样DrawMonitor就不会意外地在其绘制的监视器之外绘制)

然后,我将该位图转换为一个图像,当放置在主显示器的左上角时,该图像将正确环绕(正如Raymond Chen在其文章中所描述的):

std::unique_ptr ConvertWallpaperToDesktopCoords(std::unique_ptr&Bmp_wallperCoords)
{
std::unique_ptr Bmp_DesktopCoords(新图形::TBitmap);
Bmp_桌面坐标->像素格式=Bmp_壁纸坐标->像素格式;
Bmp_桌面坐标->宽度=Bmp_墙纸坐标->宽度;
Bmp_桌面坐标->高度=Bmp_桌面坐标->高度;
//在四个不同的位置绘制Bmp_墙纸坐标到Bmp_桌面坐标,以说明所有
//Windows在桌面的左边缘和下边缘包裹壁纸的可能方式
//空间
Bmp_DesktopCoords->Canvas->Draw(屏幕->桌面左侧,屏幕->桌面,Bmp_wallportcoords.get());
Bmp_DesktopCoords->Canvas->Draw(屏幕->桌面左侧+屏幕->桌面宽度,屏幕->桌面,Bmp_wallportcoords.get());
Bmp_DesktopCoords->Canvas->Draw(屏幕->桌面左侧,屏幕->桌面+屏幕->桌面高度,Bmp_wallportcoords.get());
Bmp_DesktopCoords->Canvas->Draw(屏幕->桌面左+屏幕->桌面宽度,屏幕->桌面+屏幕->桌面高度,Bmp_wallportcoords.get());
返回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);
}
void安装壁纸(常量字符串和Fn)
{
//安装壁纸:
//有3对名称/数据对会影响桌面墙纸,均位于HKCU\Control Panel\desktop下:
//-墙纸(REG_SZ):墙纸的文件路径和名称
//-壁纸风格(REG_SZ):
//.0:居中
//.1:平铺
//.2:拉伸
//-瓷砖壁纸(REG_SZ):
//.0:不要平铺
//.1:瓷砖
//我们不使用墙纸值本身,而是使用SystemParametersInfo来设置墙纸。
//文件名必须是绝对的!
断言(Ioutils::TPath::IsPathRooted(Fn));
std::唯一目录(新目录);
Reg->RootKey=HKEY\u当前用户;
如果(Reg->OpenKey(L“控制面板\\桌面”,false))
{
Reg->WriteString(L“壁纸风格”,L“1”);
注册->书面资本(L“瓷砖墙纸”,L“1”);
Reg->CloseKey();
}
系统参数sinfow(SPI_SETDESKWALLPAPER,1,Fn.c_str(),SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
}

但是当我在Windows10中测试它时,它不再正常工作了:Windows10将壁纸完全放错了位置。鉴于过去有人问过关于多显示器墙纸的问题,我希望有人能在Windows 10上使用多显示器墙纸。

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


但是我找不到任何关于这方面的文档,所以我不知道这是否是Windows10的官方解释。小心使用。另外,我也不知道这种不同的行为是什么时候开始的:在Windows 10中,或者在Windows 8的早期版本中。

你的问题与编程没有任何关系,甚至都没有关系
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;
}
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);
}