/// <summary> /// Capture the supplied Window /// </summary> /// <param name="windowToCapture">Window to capture</param> /// <param name="captureForWindow">The capture to store the details</param> /// <param name="windowCaptureMode">What WindowCaptureMode to use</param> /// <returns></returns> public static ICapture CaptureWindow(WindowDetails windowToCapture, ICapture captureForWindow, WindowCaptureMode windowCaptureMode) { if (captureForWindow == null) { captureForWindow = new Capture(); } Rectangle windowRectangle = windowToCapture.WindowRectangle; // When Vista & DWM (Aero) enabled bool dwmEnabled = DWM.IsDwmEnabled(); // get process name to be able to exclude certain processes from certain capture modes using (Process process = windowToCapture.Process) { bool isAutoMode = windowCaptureMode == WindowCaptureMode.Auto; // For WindowCaptureMode.Auto we check: // 1) Is window IE, use IE Capture // 2) Is Windows >= Vista & DWM enabled: use DWM // 3) Otherwise use GDI (Screen might be also okay but might lose content) if (isAutoMode) { if (CoreConfig.IECapture && IeCaptureHelper.IsIeWindow(windowToCapture)) { try { ICapture ieCapture = IeCaptureHelper.CaptureIe(captureForWindow, windowToCapture); if (ieCapture != null) { return(ieCapture); } } catch (Exception ex) { Log.WarnFormat("Problem capturing IE, skipping to normal capture. Exception message was: {0}", ex.Message); } } // Take default screen windowCaptureMode = WindowCaptureMode.Screen; // Change to GDI, if allowed if (!windowToCapture.IsMetroApp && WindowCapture.IsGdiAllowed(process)) { if (!dwmEnabled && IsWpf(process)) { // do not use GDI, as DWM is not enabled and the application uses PresentationFramework.dll -> isWPF Log.InfoFormat("Not using GDI for windows of process {0}, as the process uses WPF", process.ProcessName); } else { windowCaptureMode = WindowCaptureMode.GDI; } } // Change to DWM, if enabled and allowed if (dwmEnabled) { if (windowToCapture.IsMetroApp || WindowCapture.IsDwmAllowed(process)) { windowCaptureMode = WindowCaptureMode.Aero; } } } else if (windowCaptureMode == WindowCaptureMode.Aero || windowCaptureMode == WindowCaptureMode.AeroTransparent) { if (!dwmEnabled || (!windowToCapture.IsMetroApp && !WindowCapture.IsDwmAllowed(process))) { // Take default screen windowCaptureMode = WindowCaptureMode.Screen; // Change to GDI, if allowed if (WindowCapture.IsGdiAllowed(process)) { windowCaptureMode = WindowCaptureMode.GDI; } } } else if (windowCaptureMode == WindowCaptureMode.GDI && !WindowCapture.IsGdiAllowed(process)) { // GDI not allowed, take screen windowCaptureMode = WindowCaptureMode.Screen; } Log.InfoFormat("Capturing window with mode {0}", windowCaptureMode); bool captureTaken = false; windowRectangle.Intersect(captureForWindow.ScreenBounds); // Try to capture while (!captureTaken) { ICapture tmpCapture = null; switch (windowCaptureMode) { case WindowCaptureMode.GDI: if (WindowCapture.IsGdiAllowed(process)) { if (windowToCapture.Iconic) { // Restore the window making sure it's visible! windowToCapture.Restore(); } else { windowToCapture.ToForeground(false); } tmpCapture = windowToCapture.CaptureGdiWindow(captureForWindow); if (tmpCapture != null) { // check if GDI capture any good, by comparing it with the screen content int blackCountGdi = ImageHelper.CountColor(tmpCapture.Image, Color.Black, false); int gdiPixels = tmpCapture.Image.Width * tmpCapture.Image.Height; int blackPercentageGdi = blackCountGdi * 100 / gdiPixels; if (blackPercentageGdi >= 1) { int screenPixels = windowRectangle.Width * windowRectangle.Height; using (ICapture screenCapture = new Capture()) { screenCapture.CaptureDetails = captureForWindow.CaptureDetails; if (WindowCapture.CaptureRectangleFromDesktopScreen(screenCapture, windowRectangle) != null) { int blackCountScreen = ImageHelper.CountColor(screenCapture.Image, Color.Black, false); int blackPercentageScreen = blackCountScreen * 100 / screenPixels; if (screenPixels == gdiPixels) { // "easy compare", both have the same size // If GDI has more black, use the screen capture. if (blackPercentageGdi > blackPercentageScreen) { Log.Debug("Using screen capture, as GDI had additional black."); // changeing the image will automatically dispose the previous tmpCapture.Image = screenCapture.Image; // Make sure it's not disposed, else the picture is gone! screenCapture.NullImage(); } } else if (screenPixels < gdiPixels) { // Screen capture is cropped, window is outside of screen if (blackPercentageGdi > 50 && blackPercentageGdi > blackPercentageScreen) { Log.Debug("Using screen capture, as GDI had additional black."); // changeing the image will automatically dispose the previous tmpCapture.Image = screenCapture.Image; // Make sure it's not disposed, else the picture is gone! screenCapture.NullImage(); } } else { // Use the GDI capture by doing nothing Log.Debug("This should not happen, how can there be more screen as GDI pixels?"); } } } } } } if (tmpCapture != null) { captureForWindow = tmpCapture; captureTaken = true; } else { // A problem, try Screen windowCaptureMode = WindowCaptureMode.Screen; } break; case WindowCaptureMode.Aero: case WindowCaptureMode.AeroTransparent: if (windowToCapture.IsMetroApp || WindowCapture.IsDwmAllowed(process)) { tmpCapture = windowToCapture.CaptureDwmWindow(captureForWindow, windowCaptureMode, isAutoMode); } if (tmpCapture != null) { captureForWindow = tmpCapture; captureTaken = true; } else { // A problem, try GDI windowCaptureMode = WindowCaptureMode.GDI; } break; default: // Screen capture if (windowToCapture.Iconic) { // Restore the window making sure it's visible! windowToCapture.Restore(); } else { windowToCapture.ToForeground(); } try { captureForWindow = WindowCapture.CaptureRectangleFromDesktopScreen(captureForWindow, windowRectangle); captureTaken = true; } catch (Exception e) { Log.Error("Problem capturing", e); return(null); } break; } } } if (captureForWindow != null) { captureForWindow.CaptureDetails.Title = windowToCapture.Text; } return(captureForWindow); }