如何从系统服务启动屏幕保护程序

时间:2011-04-20 09:11:02

标签: .net windows windows-services screensaver

我有几个变种来启动屏幕保护程序。我最喜欢的是

[DllImport("user32.dll", SetLastError = false)]
private static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

private void startScreensaver()
{
    UInt32 WM_SYSCOMMAND = 0x112;
    IntPtr SC_SCREENSAVE = new IntPtr(0xf140);
    IntPtr hWnd = GetDesktopWindow();
    SendMessage(hWnd, WM_SYSCOMMAND, SC_SCREENSAVE, new IntPtr(0));
}

我的问题是我想从系统服务启动屏幕保护程序。如果我是想要在会话被锁定后立即启动屏幕保护程序(仅用于证明概念),我可以尝试

protected override void OnSessionChange(SessionChangeDescription changeDescription)
{
    base.OnSessionChange(changeDescription);
    if (changeDescription.Reason == SessionChangeReason.SessionLock)
        startScreensaver();
}

这不起作用,我认为原因是服务是用

安装的

ServiceProcessInstaller.Account = ServiceAccount.LocalSystem;

无法访问用户的会话。我可以实现一个在用户会话中运行的小程序,该程序由服务触发以触发屏幕保护程序......但这不是很好的方法。

有什么建议吗?感谢。

编辑:显然这个问题与GetDesktopWindow();电话有关,但我还不知道如何解决这个问题

更新

根据Erics的建议,我现在迭代所有窗口站(使用OpenWindowStation),然后为所有这些迭代所有桌面(使用EnumDesktops)。然后,我使用OpenDesktop打开桌面并将句柄存储到桌面。我的标准Windows安装产生到以下windowStation列表:桌面:dskHandle

  • WinSta0:默认值:732
  • WinSta0:断开:760
  • WinSta0:Winlogon中:784
  • msswindowstation:mssrestricteddesk:0

我现在开始一个新的线程,其中我

[DllImport("user32.dll", SetLastError = true)]
static extern bool SetThreadDesktop(IntPtr hDesktop);

然后调用上面的startScreensaver()方法。 IntPtr hWnd = GetDesktopWindow()确实返回了合理的结果,但屏幕保护程序仍未启动。在

[DllImport("user32.dll")]
static extern IntPtr OpenDesktop(string lpszDesktop, uint dwFlags, bool fInherit, uint dwDesiredAccess);

我使用GENERIC_ALL = 0x10000000作为dwDesiredAccess。正如Farzin所说,我检查了

  

允许服务与桌面交互

我不是win32或pInvoke专业版,所以我现在完全迷失了。可以解释一下这些东西是如何协同工作的吗?某人有更好的建议吗?我想做的就是从系统服务中调用屏幕保护程序。

3 个答案:

答案 0 :(得分:2)

答案 1 :(得分:1)

转到您的服务,右键单击服务,然后在LogOn选项卡中将项目设置为true:

  

允许服务与桌面交互

如果您想在安装时执行此操作:

public WindowsServiceInstaller()
{
  // This call is required by the Designer.

  InitializeComponent();
  ServiceInstaller si = new ServiceInstaller();
  si.ServiceName = "WindowsService1"; 
  si.DisplayName = "WindowsService1";
  si.StartType = ServiceStartMode.Manual;
  this.Installers.Add(si);
  ServiceProcessInstaller spi = new ServiceProcessInstaller();
  spi.Account = System.ServiceProcess.ServiceAccount.LocalSystem; 
  spi.Password = null;
  spi.Username = null;
  this.Installers.Add(spi);

  // Here is where we set the bit on the value in the registry.

  // Grab the subkey to our service

  RegistryKey ckey = Registry.LocalMachine.OpenSubKey(
    @"SYSTEM\CurrentControlSet\Services\WindowsService1", true);
  // Good to always do error checking!

  if(ckey != null)
  {
    // Ok now lets make sure the "Type" value is there, 

    //and then do our bitwise operation on it.

    if(ckey.GetValue("Type") != null)
    {
      ckey.SetValue("Type", ((int)ckey.GetValue("Type") | 256));
    }
  }
}

参考:http://www.codeproject.com/KB/install/cswindowsservicedesktop.aspx

答案 2 :(得分:1)

安装时允许服务与桌面交互可能会有效(将SERVICE_INTERACTIVE_PROCESS传递给CreateService)。否则(可能存在访问问题 - 我没有尝试过)你需要从Window Station and Desktop Functions开始。

您需要做的是找到登录用户窗口站(EnumWindowStationsOpenWindowStation),桌面(EnumDesktopsOpenDesktop),创建一个主题和SetThreadDesktop,然后最后使用GetDesktopWindow