/// <summary> /// Attempts to create a capture handle if it does not already exist. Returns false if the capture handle could not be created. /// </summary> private bool CreateCaptureHandleIfNecessary() { if (deviceContext == null) { deviceContext = AutoDisposeHandle.Create(NativeMethods.GetDC(IntPtr.Zero), h => NativeMethods.ReleaseDC(IntPtr.Zero, h)); } return(deviceContext != null); }
private void ClearCaptureHandle() { if (deviceContext != null) { deviceContext.Dispose(); } deviceContext = null; }
/// <summary> /// If the current thread's desktop is not the desktop that receives input, then change it. Returns true if the desktop was changed. /// </summary> public static bool AssociateCurrentThreadWithDefaultDesktop() { using (AutoDisposeHandle inputDesktop = GetInputDesktop()) { string inputDesktopName = GetDesktopName(inputDesktop); string currentThreadDesktopName = GetDesktopName(GetThreadDesktop()); if (currentThreadDesktopName != inputDesktopName) { if (NativeMethods.SetThreadDesktop(inputDesktop)) { return(true); } Win32Helper.ThrowLastWin32Error("Unable to set thread desktop"); } } return(false); }
/// <summary> /// Attempts to capture a screenshot of the current desktop. /// </summary> /// <returns></returns> private Screenshot CaptureScreenshot(int x, int y, int width, int height) { BasicEventTimer bet = new BasicEventTimer("0.000"); bet.Start("Setup"); if (!CreateCaptureHandleIfNecessary()) { return(null); } NativeMethods.BITMAPINFO bmpInfo = new NativeMethods.BITMAPINFO(); using (AutoDisposeHandle bmp = AutoDisposeHandle.Create(NativeMethods.CreateCompatibleBitmap(deviceContext, 1, 1), h => NativeMethods.DeleteObject(h))) { bmpInfo.bmiHeader.biSize = Marshal.SizeOf(typeof(NativeMethods.BITMAPINFOHEADER)); if (0 == NativeMethods.GetDIBits(deviceContext, bmp, 0, 1, null, ref bmpInfo, NativeMethods.DIB_Color_Mode.DIB_RGB_COLORS)) { Win32Helper.ThrowLastWin32Error(); } bmpInfo.bmiHeader.biSize = Marshal.SizeOf(typeof(NativeMethods.BITMAPINFO)); if (0 == NativeMethods.GetDIBits(deviceContext, bmp, 0, 1, null, ref bmpInfo, NativeMethods.DIB_Color_Mode.DIB_RGB_COLORS)) { Win32Helper.ThrowLastWin32Error(); } } bmpInfo.bmiHeader.biWidth = width; bmpInfo.bmiHeader.biHeight = -height; bmpInfo.bmiHeader.biSizeImage = 0; // Create memory device context. When done, delete it. using (AutoDisposeHandle dc = AutoDisposeHandle.Create(NativeMethods.CreateCompatibleDC(IntPtr.Zero), h => NativeMethods.DeleteDC(h))) { if (dc == null) { Win32Helper.ThrowLastWin32Error("Failed to create memory device context"); } // Create "DIB Section" (a Bitmap, more or less). When done, delete it. IntPtr ppvBits = new IntPtr(); using (AutoDisposeHandle newDib = AutoDisposeHandle.Create(NativeMethods.CreateDIBSection(dc, ref bmpInfo, 0U, out ppvBits, IntPtr.Zero, 0U), h => NativeMethods.DeleteObject(h))) //using (AutoDisposeHandle newDib = AutoDisposeHandle.Create(NativeMethods.CreateCompatibleBitmap(deviceContext, width, height), h => NativeMethods.DeleteObject(h))) { if (newDib == null) { Win32Helper.ThrowLastWin32Error("Failed to create DIB Section"); } // Assign new DIB Section to our memory device context. When done, put back the old DIB Section. using (AutoDisposeHandle oldDib = AutoDisposeHandle.Create(NativeMethods.SelectObject(dc, newDib), h => NativeMethods.SelectObject(dc, h))) { if (oldDib == null) { Win32Helper.ThrowLastWin32Error("Failed to assign new DIB Section to memory device context"); } bet.Start("BitBlt"); // Copy data from the screen to our memory device context if (!NativeMethods.BitBlt(dc, 0, 0, width, height, deviceContext, x, y, CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt)) { Logger.Debug("BitBlt failed with error code: " + Win32Helper.GetLastWin32Error()); ClearCaptureHandle(); DesktopManager.ShouldReassociate = true; } else { bet.Start("new Screenshot/Copy bits"); Screenshot screenshot = new Screenshot(width, height, bmpInfo.bmiHeader.biBitCount); Marshal.Copy(ppvBits, screenshot.Buffer, 0, screenshot.Buffer.Length); bet.Stop(); //Logger.Info(bet.ToString(Environment.NewLine)); return(screenshot); } } } } return(null); }
/// <summary> /// Gets a handle to the desktop that receives user input. /// </summary> /// <returns></returns> private static AutoDisposeHandle GetInputDesktop() { return(AutoDisposeHandle.Create(NativeMethods.OpenInputDesktop(0, false, (uint)NativeMethods.ACCESS_MASK.DESKTOP_ALL_ACCESS), h => NativeMethods.CloseDesktop(h))); }
/// <summary> /// Retrieves a handle to the desktop assigned to the current thread. This handle does not need to be closed. /// </summary> /// <returns></returns> private static AutoDisposeHandle GetThreadDesktop() { // The value returned by GetThreadDesktop does not need to be closed, so we pass null for the onRelease method. return(AutoDisposeHandle.Create(NativeMethods.GetThreadDesktop(NativeMethods.GetCurrentThreadId()), null)); }