簡體   English   中英

Windows服務屏幕截圖不起作用

[英]Windows service screen capture not working

我創建了Windows服務,需要捕獲桌面屏幕,但是結果圖像為黑色。 我知道Windows服務需要分配給winsat0 / default桌面。 我使用user32.dll函數與用戶桌面進行交互,但是它不起作用!

我在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;
}

獲取捕獲的功能是這樣的:

public static bool Trig1() // ScreenShot
{
    Desktop userDesk = new Desktop();
    if (!userDesk.BeginInteraction())
        return false;

    string path = @"C:\";
    if (!Directory.Exists(path))
        Directory.CreateDirectory(path);

    string fileName = string.Format("SCR-{0:yyyy-MM-dd_hh-mm-ss-tt}.png", DateTime.Now);
    string filePath = path + fileName;
    bmpScreenshot = CaptureScreen.GetDesktopImage();
    bmpScreenshot.Save(filePath, ImageFormat.Png);
    userDesk.EndInteraction();
    return true;
}

捕獲類是這樣的:

public class CaptureScreen
{
    #region Public Class Functions
    public static Bitmap GetDesktopImage()
    {
        //Variable to keep the handle of the btimap.
        IntPtr m_HBitmap = new IntPtr();

        //Variable to keep the refrence to the desktop bitmap.
        System.Drawing.Bitmap bmp = null;

        //In size variable we shall keep the size of the screen.
        SIZE size;

        //Here we get the handle to the desktop device context.
        IntPtr hDC = PlatformInvokeUSER32.GetDC(PlatformInvokeUSER32.GetDesktopWindow());

        //Here we make a compatible device context in memory for screen device context.
        IntPtr hMemDC = PlatformInvokeGDI32.CreateCompatibleDC(hDC);

        //We pass SM_CXSCREEN constant to GetSystemMetrics to get the X coordinates of screen.
        size.cx = PlatformInvokeUSER32.GetSystemMetrics(PlatformInvokeUSER32.SM_CXSCREEN);

        //We pass SM_CYSCREEN constant to GetSystemMetrics to get the Y coordinates of screen.
        size.cy = PlatformInvokeUSER32.GetSystemMetrics(PlatformInvokeUSER32.SM_CYSCREEN);

        //We create a compatible bitmap of screen size and using screen device context.
        m_HBitmap = PlatformInvokeGDI32.CreateCompatibleBitmap(hDC, size.cx, size.cy);

        //As m_HBitmap is IntPtr we can not check it against null. For this purspose IntPtr.Zero is used.
        if (m_HBitmap != IntPtr.Zero)
        {
            //Here we select the compatible bitmap in memeory device context and keeps the refrence to Old bitmap.
            IntPtr hOld = (IntPtr)PlatformInvokeGDI32.SelectObject(hMemDC, m_HBitmap);

            //We copy the Bitmap to the memory device context.
            PlatformInvokeGDI32.BitBlt(hMemDC, 0, 0, size.cx, size.cy, hDC, 0, 0, PlatformInvokeGDI32.SRCCOPY);

            //We select the old bitmap back to the memory device context.
            PlatformInvokeGDI32.SelectObject(hMemDC, hOld);

            //We delete the memory device context.
            PlatformInvokeGDI32.DeleteDC(hMemDC);

            //We release the screen device context.
            PlatformInvokeUSER32.ReleaseDC(PlatformInvokeUSER32.GetDesktopWindow(), hDC);

            //Image is created by Image bitmap handle and assigned to Bitmap variable.
            bmp = System.Drawing.Image.FromHbitmap(m_HBitmap);

            //Delete the compatible bitmap object. 
            PlatformInvokeGDI32.DeleteObject(m_HBitmap);

            return bmp;
        }

        //If m_HBitmap is null retunrn null.
        return null;
    }
    #endregion
}

但是圖像是黑色的。

您的進程與控制台上的交互式用戶所運行的會話不同。 您正在捕獲會話中的WinSta0桌面,並且由於那里沒有人顯示任何內容,因此它變黑了。 有關更多信息,請參見http://msdn.microsoft.com/zh-cn/library/windows/desktop/ms687096%28v=vs.85%29.aspx上的MS文檔。

從NT6(Vista / Server 2008及更高版本)開始,服務不再與用戶會話進行交互。 他們仍然可以創建窗口/消息框,但是它們將始終位於保留的會話0上(如果控制台上有活動的交互式用戶,則他們將獲得“服務正在嘗試顯示消息”彈出窗口,並可以選擇暫時切換並查看會話0)。

如果要捕獲用戶的桌面,則必須創建一個在其會話中運行的進程。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM