为什么Windows服务中的打印屏幕返回黑色图像?

protected override void OnStart(string[] args) { base.OnStart(args); CaptureScreen(); } protected override void OnStop() { base.OnStop(); } private void CaptureScreen() { Bitmap printscreen = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height); Graphics graphics = Graphics.FromImage(printscreen as Image); graphics.CopyFromScreen(0, 0, 0, 0, printscreen.Size); printscreen.Save(@"L:\" + Counter++ + ".jpg", ImageFormat.Jpeg); } 
  • 我检查过与桌面交互
  • 尝试了localService帐户和用户

这是添加到Vista的会话0隔离function的一部分。 服务现在使用自己的工作站和桌面运行自己的会话。 就像登录提示和屏幕保护程序运行的会话一样。您正在截取该会话桌面的截图,其中没有任何内容。 无法再访问用户桌面。 它是一种安全function,可以防止破碎攻击。 不可否认,我不明白为什么没有删除“与桌面交互”复选框。

您需要将程序更改为“Windows应用程序”,而不是服务。 在Startup文件夹中放置一个快捷方式或使用Run注册表项。 哪个没关系,没有用户登录时没什么值得抓拍的。

您需要将服务设置为用户Windows工作站。 这不是我的代码,我不记得从哪里得到它。 添加这两个类,然后您可以创建一个Desktop对象

Desktop userDesk = new Desktop();

然后,当您需要服务与用户会话进行交互时,您将编写

userDesk.BeginInteraction();

最后回到你打电话给你的服务会议

userDesk.EndInteraction();

 internal class Desktop { private IntPtr m_hCurWinsta = IntPtr.Zero; private IntPtr m_hCurDesktop = IntPtr.Zero; private IntPtr m_hWinsta = IntPtr.Zero; private IntPtr m_hDesk = IntPtr.Zero; ///  /// associate the current thread to the default desktop ///  ///  internal bool BeginInteraction() { EndInteraction(); m_hCurWinsta = User32DLL.GetProcessWindowStation(); if (m_hCurWinsta == IntPtr.Zero) return false; m_hCurDesktop = User32DLL.GetDesktopWindow(); if (m_hCurDesktop == IntPtr.Zero) return false; m_hWinsta = User32DLL.OpenWindowStation("winsta0", false, WindowStationAccessRight.WINSTA_ACCESSCLIPBOARD | WindowStationAccessRight.WINSTA_ACCESSGLOBALATOMS | WindowStationAccessRight.WINSTA_CREATEDESKTOP | WindowStationAccessRight.WINSTA_ENUMDESKTOPS | WindowStationAccessRight.WINSTA_ENUMERATE | WindowStationAccessRight.WINSTA_EXITWINDOWS | WindowStationAccessRight.WINSTA_READATTRIBUTES | WindowStationAccessRight.WINSTA_READSCREEN | WindowStationAccessRight.WINSTA_WRITEATTRIBUTES ); if (m_hWinsta == IntPtr.Zero) return false; User32DLL.SetProcessWindowStation(m_hWinsta); m_hDesk = User32DLL.OpenDesktop("default", OpenDesktopFlag.DF_NONE, false, DesktopAccessRight.DESKTOP_CREATEMENU | DesktopAccessRight.DESKTOP_CREATEWINDOW | DesktopAccessRight.DESKTOP_ENUMERATE | DesktopAccessRight.DESKTOP_HOOKCONTROL | DesktopAccessRight.DESKTOP_JOURNALPLAYBACK | DesktopAccessRight.DESKTOP_JOURNALRECORD | DesktopAccessRight.DESKTOP_READOBJECTS | DesktopAccessRight.DESKTOP_SWITCHDESKTOP | DesktopAccessRight.DESKTOP_WRITEOBJECTS ); if (m_hDesk == IntPtr.Zero) return false; User32DLL.SetThreadDesktop(m_hDesk); return true; } ///  /// restore ///  internal void EndInteraction() { if (m_hCurWinsta != IntPtr.Zero) User32DLL.SetProcessWindowStation(m_hCurWinsta); if (m_hCurDesktop != IntPtr.Zero) User32DLL.SetThreadDesktop(m_hCurDesktop); if (m_hWinsta != IntPtr.Zero) User32DLL.CloseWindowStation(m_hWinsta); if (m_hDesk != IntPtr.Zero) User32DLL.CloseDesktop(m_hDesk); } } public static class User32DLL { ///  /// The GetDesktopWindow function returns a handle to the desktop window. /// The desktop window covers the entire screen. /// The desktop window is the area on top of which other windows are painted. ///  /// The return value is a handle to the desktop window.  [DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)] public static extern IntPtr GetDesktopWindow(); ///  /// Retrieves a handle to the current window station for the calling process. ///  /// If the function succeeds, /// the return value is a handle to the window station. /// If the function fails, the return value is NULL. [DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)] public static extern IntPtr GetProcessWindowStation(); ///  /// Retrieves a handle to the desktop assigned to the specified thread. ///  /// [in] Handle to the thread /// for which to return the desktop handle. /// If the function succeeds, the return value is a handle to the /// desktop associated with the specified thread. /// If the function fails, the return value is NULL. [DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)] public static extern IntPtr GetThreadDesktop(uint dwThread); ///  /// Opens the specified window station. ///  /// Pointer to a null-terminated /// string specifying the name of the window station /// to be opened. Window station names are case-insensitive. /// This window station must belong to the current session. ///  /// [in] If this value /// is TRUE, processes created by this process /// will inherit the handle. Otherwise, /// the processes do not inherit this handle. ///  /// [in] Access to the window station /// If the function succeeds, the return value /// is the handle to the specified window station. /// If the function fails, the return value is NULL. [DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)] public static extern IntPtr OpenWindowStation(string lpszWinSta , bool fInherit , WindowStationAccessRight dwDesiredAccess ); ///  /// Assigns the specified window station to the calling process. /// This enables the process to access objects in the window /// station such as desktops, the clipboard, and global atoms. /// All subsequent operations on the window station /// use the access rights granted to hWinSta. ///  /// [in] Handle to the window /// station to be assigned to the calling process /// If the function succeeds, the return value is nonzero. /// If the function fails, the return value is zero.  [DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)] public static extern IntPtr SetProcessWindowStation(IntPtr hWinSta); ///  /// Closes an open window station handle. ///  /// [in] Handle /// to the window station to be closed. /// If the function succeeds, the return value is nonzero. /// If the function fails, the return value is zero.  [DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)] public static extern IntPtr CloseWindowStation(IntPtr hWinSta); ///  /// Opens the specified desktop object. ///  /// [in] Pointer to null-terminated string /// specifying the name of the desktop to be opened. /// Desktop names are case-insensitive. /// This desktop must belong to the current window station. /// [in] This parameter can /// be zero or DF_ALLOWOTHERACCOUNTHOOK=0x0001 /// [in] If this value is TRUE, processes created by /// this process will inherit the handle. /// Otherwise, the processes do not inherit this handle.  /// [in] Access /// to the desktop. For a list of access rights /// If the function succeeds, the return value is a handle to the opened desktop. /// When you are finished using the handle, call the CloseDesktop function to close it. /// If the function fails, the return value is NULL. ///  [DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)] public static extern IntPtr OpenDesktop(string lpszDesktop , OpenDesktopFlag dwFlags , bool fInherit , DesktopAccessRight dwDesiredAccess ); ///  /// Closes an open handle to a desktop object. ///  /// [in] Handle to the desktop to be closed. /// If the function succeeds, the return value is nonzero. /// If the function fails, the return value is zero.  [DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)] public static extern IntPtr CloseDesktop(IntPtr hDesktop); ///  /// Assigns the specified desktop to the calling thread. /// All subsequent operations on the desktop use the access rights granted to the desktop. ///  /// [in] Handle to the desktop /// to be assigned to the calling thread. /// If the function succeeds, the return value is nonzero. /// If the function fails, the return value is zero.  [DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)] public static extern bool SetThreadDesktop(IntPtr hDesktop); } ///  /// REF MSDN:Window Station Security and Access Rights /// ms-help://MS.MSDN.vAug06.en/dllproc/base/window_station_security_and_access_rights.htm ///  [FlagsAttribute] public enum WindowStationAccessRight : uint { /// All possible access rights for the window station. WINSTA_ALL_ACCESS = 0x37F, /// Required to use the clipboard. WINSTA_ACCESSCLIPBOARD = 0x0004, /// Required to manipulate global atoms. WINSTA_ACCESSGLOBALATOMS = 0x0020, /// Required to create new desktop /// objects on the window station. WINSTA_CREATEDESKTOP = 0x0008, /// Required to enumerate existing desktop objects. WINSTA_ENUMDESKTOPS = 0x0001, /// Required for the window station to be enumerated. WINSTA_ENUMERATE = 0x0100, /// Required to successfully call the ExitWindows or ExitWindowsEx function. /// Window stations can be shared by users and this access type can prevent other users /// of a window station from logging off the window station owner. WINSTA_EXITWINDOWS = 0x0040, /// Required to read the attributes of a window station object. /// This attribute includes color settings /// and other global window station properties. WINSTA_READATTRIBUTES = 0x0002, /// Required to access screen contents. WINSTA_READSCREEN = 0x0200, /// Required to modify the attributes of /// a window station object. /// The attributes include color settings /// and other global window station properties. WINSTA_WRITEATTRIBUTES = 0x0010, } ///  /// OpenDesktop 2nd param ///  public enum OpenDesktopFlag : uint { ///  /// Default value ///  DF_NONE = 0x0000, ///  /// Allows processes running in other accounts on the desktop /// to set hooks in this process. ///  DF_ALLOWOTHERACCOUNTHOOK = 0x0001, } ///  /// REF MSDN:Desktop Security and Access Rights /// ms-help://MS.MSDN.vAug06.en/dllproc/base/desktop_security_and_access_rights.htm ///  [FlagsAttribute] public enum DesktopAccessRight : uint { /// Required to create a menu on the desktop.  DESKTOP_CREATEMENU = 0x0004, /// Required to create a window on the desktop.  DESKTOP_CREATEWINDOW = 0x0002, /// Required for the desktop to be enumerated.  DESKTOP_ENUMERATE = 0x0040, /// Required to establish any of the window hooks.  DESKTOP_HOOKCONTROL = 0x0008, /// Required to perform journal playback on a desktop.  DESKTOP_JOURNALPLAYBACK = 0x0020, /// Required to perform journal recording on a desktop.  DESKTOP_JOURNALRECORD = 0x0010, /// Required to read objects on the desktop.  DESKTOP_READOBJECTS = 0x0001, /// Required to activate the desktop /// using the SwitchDesktop function.  DESKTOP_SWITCHDESKTOP = 0x0100, /// Required to write objects on the desktop.  DESKTOP_WRITEOBJECTS = 0x0080, } 

该服务是“无头”,没有UI,没有100%肯定(CopyFromScreen的文档相当模糊)我期望在无头运行时失败。 在多个用户同时登录的情况下,服务如何知道要复制哪个屏幕?

也看到这个问题

在XP / 2003的情况下,Interact with Desktop应该有所帮助。 对于Windows 7 / Windows 2008,Interact with Desktop的工作方式不同。

对您而言,最佳解决方案是分析来自服务的登录会话,对于新会话,在用户会话中启动“桌面”进程并与该进程通信以获取屏幕。