예제 #1
0
        /// <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);
        }