/// <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)); } }
/// <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)); } }
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); } } }
/// <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); } } }
/// <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)); }
/// <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)); }