Example #1
0
        /// <summary>
        ///     Retrieve the DPI value for the supplied window handle
        /// </summary>
        /// <param name="hWnd">IntPtr</param>
        /// <returns>dpi value</returns>
        public static int GetDpi(IntPtr hWnd)
        {
            // Use the easiest method, but this only works for Windows 10
            if (WindowsVersion.IsWindows10OrLater)
            {
                return(GetDpiForWindow(hWnd));
            }

            // Use the second easiest method, but this only works for Windows 8.1 or later
            if (WindowsVersion.IsWindows81OrLater)
            {
                var  hMonitor = User32Api.MonitorFromWindow(hWnd, MonitorFrom.DefaultToNearest);
                uint dpiX;
                uint dpiY;
                if (GetDpiForMonitor(hMonitor, MonitorDpiType.EffectiveDpi, out dpiX, out dpiY))
                {
                    return((int)dpiX);
                }
            }

            // Fallback to the global DPI settings
            using (var hdc = SafeDeviceContextHandle.FromHWnd(hWnd))
            {
                return(Gdi32Api.GetDeviceCaps(hdc, DeviceCaps.LOGPIXELSX));
            }
        }
Example #2
0
        /// <summary>
        ///     Retrieve the DPI value for the supplied window handle
        /// </summary>
        /// <param name="hWnd">IntPtr</param>
        /// <returns>dpi value</returns>
        public static uint GetDpi(IntPtr hWnd)
        {
            if (!User32Api.IsWindow(hWnd))
            {
                return(DpiHandler.DefaultScreenDpi);
            }

            // Use the easiest method, but this only works for Windows 10
            if (WindowsVersion.IsWindows10OrLater)
            {
                return(GetDpiForWindow(hWnd));
            }

            // Use the second easiest method, but this only works for Windows 8.1 or later
            if (WindowsVersion.IsWindows81OrLater)
            {
                var hMonitor = User32Api.MonitorFromWindow(hWnd, MonitorFrom.DefaultToNearest);
                // ReSharper disable once UnusedVariable
                if (GetDpiForMonitor(hMonitor, MonitorDpiType.EffectiveDpi, out var dpiX, out var dpiY))
                {
                    return(dpiX);
                }
            }

            // Fallback to the global DPI settings
            using (var hdc = SafeWindowDcHandle.FromWindow(hWnd))
            {
                if (hdc == null)
                {
                    return(DpiHandler.DefaultScreenDpi);
                }
                return((uint)Gdi32Api.GetDeviceCaps(hdc, DeviceCaps.LOGPIXELSX));
            }
        }
Example #3
0
        public void TestCreateCompatibleDc()
        {
            using (var desktopDcHandle = SafeWindowDcHandle.FromDesktop())
            {
                Assert.False(desktopDcHandle.IsInvalid);

                // create a device context we can copy to
                using (var safeCompatibleDcHandle = Gdi32Api.CreateCompatibleDC(desktopDcHandle))
                {
                    Assert.False(safeCompatibleDcHandle.IsInvalid);
                }
            }
        }
Example #4
0
 /// <summary>
 ///     Get the region for a window
 /// </summary>
 /// <param name="interopWindow">InteropWindow</param>
 public static Region GetRegion(this IInteropWindow interopWindow)
 {
     using (var region = Gdi32Api.CreateRectRgn(0, 0, 0, 0))
     {
         if (region.IsInvalid)
         {
             return(null);
         }
         var result = User32Api.GetWindowRgn(interopWindow.Handle, region);
         if (result != RegionResults.Error && result != RegionResults.NullRegion)
         {
             return(Region.FromHrgn(region.DangerousGetHandle()));
         }
     }
     return(null);
 }
 /// <summary>
 ///     Get the color from the pixel on the screen at "x,y"
 /// </summary>
 /// <param name="screenCoordinates">Point with the coordinates</param>
 /// <returns>Color at the specified screenCoordinates</returns>
 private static Color GetPixelColor(Point screenCoordinates)
 {
     using (var screenDc = SafeWindowDcHandle.FromDesktop())
     {
         try
         {
             var pixel = Gdi32Api.GetPixel(screenDc, screenCoordinates.X, screenCoordinates.Y);
             var color = Color.FromArgb(255, (int)(pixel & 0xFF), (int)(pixel & 0xFF00) >> 8, (int)(pixel & 0xFF0000) >> 16);
             return(color);
         }
         catch (Exception)
         {
             return(Color.Empty);
         }
     }
 }
Example #6
0
        /// <summary>
        ///     This method will use User32 code to capture the specified captureBounds from the screen
        /// </summary>
        /// <param name="captureBounds">NativeRect with the bounds to capture</param>
        /// <returns>Bitmap which is captured from the screen at the location specified by the captureBounds</returns>
        public static Bitmap CaptureRectangle(NativeRect captureBounds)
        {
            Bitmap returnBitmap = null;

            if (captureBounds.Height <= 0 || captureBounds.Width <= 0)
            {
                Log.Warn().WriteLine("Nothing to capture, ignoring!");
                return(null);
            }
            Log.Debug().WriteLine("CaptureRectangle Called!");

            // .NET GDI+ Solution, according to some post this has a GDI+ leak...
            // See http://connect.microsoft.com/VisualStudio/feedback/details/344752/gdi-object-leak-when-calling-graphics-copyfromscreen
            // Bitmap capturedBitmap = new Bitmap(captureBounds.Width, captureBounds.Height);
            // using (Graphics graphics = Graphics.FromImage(capturedBitmap)) {
            //	graphics.CopyFromScreen(captureBounds.Location, NativePoint.Empty, captureBounds.Size, CopyPixelOperation.CaptureBlt);
            // }
            // capture.Image = capturedBitmap;
            // capture.Location = captureBounds.Location;

            using (var desktopDcHandle = SafeWindowDcHandle.FromDesktop())
            {
                if (desktopDcHandle.IsInvalid)
                {
                    // Get Exception before the error is lost
                    var exceptionToThrow = CreateCaptureException("desktopDCHandle", captureBounds);
                    // throw exception
                    throw exceptionToThrow;
                }

                // create a device context we can copy to
                using (var safeCompatibleDcHandle = Gdi32Api.CreateCompatibleDC(desktopDcHandle))
                {
                    // Check if the device context is there, if not throw an error with as much info as possible!
                    if (safeCompatibleDcHandle.IsInvalid)
                    {
                        // Get Exception before the error is lost
                        var exceptionToThrow = CreateCaptureException("CreateCompatibleDC", captureBounds);
                        // throw exception
                        throw exceptionToThrow;
                    }
                    // Create BITMAPINFOHEADER for CreateDIBSection
                    var bmi = BitmapInfoHeader.Create(captureBounds.Width, captureBounds.Height, 24);

                    // TODO: Enable when the function is available again
                    // Make sure the last error is set to 0
                    Win32.SetLastError(0);

                    // create a bitmap we can copy it to, using GetDeviceCaps to get the width/height
                    IntPtr bits0; // not used for our purposes. It returns a pointer to the raw bits that make up the bitmap.
                    // TODO: Change the usage to an enum?
                    using (var safeDibSectionHandle = Gdi32Api.CreateDIBSection(desktopDcHandle, ref bmi, 0, out bits0, IntPtr.Zero, 0))
                    {
                        if (safeDibSectionHandle.IsInvalid)
                        {
                            // Get Exception before the error is lost
                            var exceptionToThrow = CreateCaptureException("CreateDIBSection", captureBounds);
                            exceptionToThrow.Data.Add("hdcDest", safeCompatibleDcHandle.DangerousGetHandle().ToInt32());
                            exceptionToThrow.Data.Add("hdcSrc", desktopDcHandle.DangerousGetHandle().ToInt32());

                            // Throw so people can report the problem
                            throw exceptionToThrow;
                        }
                        // select the bitmap object and store the old handle
                        using (safeCompatibleDcHandle.SelectObject(safeDibSectionHandle))
                        {
                            // bitblt over (make copy)
                            // ReSharper disable once BitwiseOperatorOnEnumWithoutFlags
                            Gdi32Api.BitBlt(safeCompatibleDcHandle, 0, 0, captureBounds.Width, captureBounds.Height, desktopDcHandle, captureBounds.X, captureBounds.Y,
                                            RasterOperations.SourceCopy | RasterOperations.CaptureBlt);
                        }

                        // get a .NET image object for it
                        // A suggestion for the "A generic error occurred in GDI+." E_FAIL/0×80004005 error is to re-try...
                        var success = false;
                        ExternalException exception = null;
                        for (var i = 0; i < 3; i++)
                        {
                            try
                            {
                                // Collect all screens inside this capture
                                var screensInsideCapture = new List <Screen>();
                                foreach (var screen in Screen.AllScreens)
                                {
                                    if (screen.Bounds.IntersectsWith(captureBounds))
                                    {
                                        screensInsideCapture.Add(screen);
                                    }
                                }
                                // Check all all screens are of an equal size
                                bool offscreenContent;
                                using (var captureRegion = new Region(captureBounds))
                                {
                                    // Exclude every visible part
                                    foreach (var screen in screensInsideCapture)
                                    {
                                        captureRegion.Exclude(screen.Bounds);
                                    }
                                    // If the region is not empty, we have "offscreenContent"
                                    using (var screenGraphics = Graphics.FromHwnd(User32Api.GetDesktopWindow()))
                                    {
                                        offscreenContent = !captureRegion.IsEmpty(screenGraphics);
                                    }
                                }
                                // Check if we need to have a transparent background, needed for offscreen content
                                if (offscreenContent)
                                {
                                    using (var tmpBitmap = Image.FromHbitmap(safeDibSectionHandle.DangerousGetHandle()))
                                    {
                                        // Create a new bitmap which has a transparent background
                                        returnBitmap = BitmapFactory.CreateEmpty(tmpBitmap.Width, tmpBitmap.Height, PixelFormat.Format32bppArgb, Color.Transparent, tmpBitmap.HorizontalResolution,
                                                                                 tmpBitmap.VerticalResolution);
                                        // Content will be copied here
                                        using (var graphics = Graphics.FromImage(returnBitmap))
                                        {
                                            // For all screens copy the content to the new bitmap
                                            foreach (var screen in Screen.AllScreens)
                                            {
                                                // Make sure the bounds are offsetted to the capture bounds
                                                var screenBounds = screen.Bounds;
                                                screenBounds.Offset(-captureBounds.X, -captureBounds.Y);
                                                graphics.DrawImage(tmpBitmap, screenBounds, screenBounds.X, screenBounds.Y, screenBounds.Width, screenBounds.Height, GraphicsUnit.Pixel);
                                            }
                                        }
                                    }
                                }
                                else
                                {
                                    // All screens, which are inside the capture, are of equal size
                                    // assign image to Capture, the image will be disposed there..
                                    returnBitmap = Image.FromHbitmap(safeDibSectionHandle.DangerousGetHandle());
                                }
                                // We got through the capture without exception
                                success = true;
                                break;
                            }
                            catch (ExternalException ee)
                            {
                                Log.Warn().WriteLine(ee, "Problem getting bitmap at try " + i + " : ");
                                exception = ee;
                            }
                        }
                        if (!success)
                        {
                            Log.Error().WriteLine(null, "Still couldn't create Bitmap!");
                            if (exception != null)
                            {
                                throw exception;
                            }
                        }
                    }
                }
            }
            return(returnBitmap);
        }
 /// <summary>
 ///     Call DeleteObject
 /// </summary>
 /// <returns>true if this worked</returns>
 protected override bool ReleaseHandle()
 {
     return(Gdi32Api.DeleteObject(handle));
 }
Example #8
0
 /// <summary>
 ///     Directly call Gdi32.CreateRectRgn
 /// </summary>
 /// <param name="left"></param>
 /// <param name="top"></param>
 /// <param name="right"></param>
 /// <param name="bottom"></param>
 /// <returns>SafeRegionHandle</returns>
 public static SafeRegionHandle CreateRectRgn(int left, int top, int right, int bottom)
 {
     return(Gdi32Api.CreateRectRgn(left, top, right, bottom));
 }