我正在尝试使用安装的服务作为特定用户(在本例中为我)来更改壁纸。
以下是我的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);
}
我已经确认它正确地将图像下载到我的临时目录中,但它没有设置壁纸。它不会出错或将任何内容记录到事件日志中。
这是我在本地服务查看器中安装的服务:
运行它什么都不做。
修改
添加此代码以在我的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。如果我让服务除了下载壁纸之外什么都不做,如果下载新壁纸并且用户已经登录,可能还有另一个非服务应用程序来更改壁纸会不会更好?
答案 0 :(得分:1)
您知道Session 0 Isolation吗?这意味着您的服务在桌面上运行,用户无法登录,并且受限制的环境可能会影响您的程序行为。
您说代码“不会错误输出或将任何内容记录到事件日志中”,但是,根据您显示的内容,您需要改进错误检查以捕获更微妙的问题。例如,SystemParametersInfo()在失败时返回FALSE(后续调用GetLastError()可能非常有用!)但您的代码不会检查该结果。您不能单独依赖明确的例外。
答案 1 :(得分:1)
添加此课程:http://pastebin.com/ERsnqMEy
像这样使用:http://pastebin.com/RYvvT7bH
使用WMI从Windows系统服务模拟登录用户的工作奇迹。祝你好运。
答案 2 :(得分:0)
在“服务”中,转到“属性”,然后选中“使用本地帐户"和#34;允许使用桌面"。我不确定名字,因为我的Windows使用不同的语言,但你应该能够找到它。