2014-05-09 72 views
0

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

我的桌面類的代碼是這樣的:

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 
} 

但圖像是黑色的。

+1

您認爲*也許*這是因爲您的'BeginInteraction'中的第一行代碼是'EndInteraction'? –

+0

Ken White:不,我刪除第一行,但結果是黑色但是.. :( –

+0

第一行有一段時間,我忘記了'BeginInteraction'之後的'EndInteraction',所以當開始調用'BeginInteraction'時它首先關閉最後一個互動.. –

回答

3

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

從NT6(Vista/Server 2008及更新版本)開始,服務不再允許與用戶會話交互。他們仍然可以創建窗口/消息框,但是它們將始終保留在保留的會話0上(如果控制檯上有活動的交互式用戶,他們將獲得「A服務試圖顯示消息」彈出窗口並且可以選擇暫時切換到並查看會話0)。

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

+0

這是一個壞消息.. :(你是對的,我試圖顯示一個對話框,此消息出現:「服務試圖顯示一條消息」,所以我無法通過Win-服務在Windows 7中,直到我切換到用戶桌面會話,是不是? –

+0

以及如何在用戶會話中運行雙贏服務(不是雙贏格式)?是否有可能? –