用服务改变壁纸

时间:2014-07-26 19:27:33

标签: c# windows-services

我正在尝试使用安装的服务作为特定用户(在本例中为我)来更改壁纸。

以下是我的Wallpaper类,其中包含SetWallpaper函数:

public sealed class Wallpaper
{
   [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError=true)]
   private static extern Int32 SystemParametersInfo(
      UInt32 action, UInt32 uParam, String vParam, UInt32 winIni);

   private static readonly UInt32 SPI_SETDESKWALLPAPER = 0x14;
   private static readonly UInt32 SPIF_UPDATEINIFILE = 0x01;
   private static readonly UInt32 SPIF_SENDWININICHANGE = 0x02;

   public static void SetWallpaper(String path)
   {
      System.IO.Stream s = new System.Net.WebClient().OpenRead(path.ToString());
      System.Drawing.Image img = System.Drawing.Image.FromStream(s);
      string tempPath = Path.Combine(Path.GetTempPath(), "wallpaper.bmp");
      ImgurWallpaperSetter.ImgurWallpaperSetter.log(tempPath);
      img.Save(tempPath, System.Drawing.Imaging.ImageFormat.Bmp);
      SystemParametersInfo(SPI_SETDESKWALLPAPER, 1, tempPath,
      SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);
      int error = Marshal.GetLastWin32Error();
      ImgurWallpaperSetter.ImgurWallpaperSetter.log("Last error: " + error);
   }
}

当我从单元测试中运行SetWallpaper时它非常有效,但是当我安装服务并启动它时它根本不起作用。

以下是服务开始代码:

protected override void OnStart(string[] args) {    
   //WallpaperScheduler.ScheduleWallpaperFetch(DateTime.Now.Hour, DateTime.Now.Minute+1);
   //Debugger.Launch();
   Uri imageUrl = WallpaperRetriever.mostPopularImgurWallpaper();
   log(imageUrl.AbsoluteUri);
   Wallpaper.SetWallpaper(imageUrl.AbsoluteUri);
}

我已经确认它正确地将图像下载到我的临时目录中,但它没有设置壁纸。它不会出错或将任何内容记录到事件日志中。

这是我在本地服务查看器中安装的服务:

Service installed as the user (me)

运行它什么都不做。

A similar thread I've read

修改 添加此代码以在我的serviceInstaller_Committed事件上运行,该事件应允许服务与桌面交互,但我发现服务运行与实际切换壁纸之间存在巨大延迟:

ConnectionOptions coOptions = new ConnectionOptions();
coOptions.Impersonation = ImpersonationLevel.Impersonate;

ManagementScope mgmtScope = new ManagementScope(@"root\CIMV2", coOptions);
mgmtScope.Connect();

ManagementObject wmiService;
wmiService = new ManagementObject(
   "Win32_Service.Name='" + serviceInstaller1.ServiceName + "'"
);

ManagementBaseObject InParam = wmiService.GetMethodParameters("Change");
InParam["DesktopInteract"] = true;
ManagementBaseObject OutParam = wmiService.InvokeMethod("Change", InParam, null);

EDIT2: 我已更新我的服务以登录系统事件GetLastError()。现在我看到该服务正在抛出错误1459(“此操作需要一个交互式窗口站。”)。然而,这并不能解释为什么我的壁纸最终会切换(我想通常是从睡眠中醒来后)。上面也更新了Wallpaper课程。

EDIT3 我已经确认睡了之后,新的壁纸已经设定好了。谁能解释为什么会这样?可能是我需要重新启动才能设置交互式桌面功能吗?

Edit4 我正在做的是感觉非常hacky。如果我让服务除了下载壁纸之外什么都不做,如果下载新壁纸并且用户已经登录,可能还有另一个非服务应用程序来更改壁纸会不会更好?

3 个答案:

答案 0 :(得分:1)

您知道Session 0 Isolation吗?这意味着您的服务在桌面上运行,用户无法登录,并且受限制的环境可能会影响您的程序行为。

您说代码“不会错误输出或将任何内容记录到事件日志中”,但是,根据您显示的内容,您需要改进错误检查以捕获更微妙的问题。例如,SystemParametersInfo()在失败时返回FALSE(后续调用GetLastError()可能非常有用!)但您的代码不会检查该结果。您不能单独依赖明确的例外。

答案 1 :(得分:1)

添加此课程:http://pastebin.com/ERsnqMEy

像这样使用:http://pastebin.com/RYvvT7bH

使用WMI从Windows系统服务模拟登录用户的工作奇迹。祝你好运。

答案 2 :(得分:0)

在“服务”中,转到“属性”,然后选中“使用本地帐户"和#34;允许使用桌面"。我不确定名字,因为我的Windows使用不同的语言,但你应该能够找到它。