private static void SmartResizeWindow(ref ScreenshotTask data, out WindowsRect oldWindowSize) { oldWindowSize = new WindowsRect(0); if ((WindowsApi.GetWindowLong(data.WindowHandle, GWL_STYLE) & WS_SIZEBOX) != WS_SIZEBOX) { return; } var r = new WindowsRect(); WindowsApi.GetWindowRect(data.WindowHandle, ref r); oldWindowSize = r; Bitmap f = CaptureCompositeScreenshot(ref data); if (f != null) { WindowsApi.SetWindowPos(data.WindowHandle, (IntPtr)0, r.Left, r.Top, data.ResizeX - (f.Width - (r.Right - r.Left)), data.ResizeY - (f.Height - (r.Bottom - r.Top)), SWP_SHOWWINDOW); f.Dispose(); } else { WindowsApi.SetWindowPos(data.WindowHandle, (IntPtr)0, r.Left, r.Top, data.ResizeX, data.ResizeY, SWP_SHOWWINDOW); } }
// Safe method of calling dwmapi.dll, for versions of Windows lower than Vista internal static int DwmGetWindowAttribute(IntPtr hWnd, DwmWindowAttribute dwAttribute, ref WindowsRect pvAttribute, int cbAttribute) { IntPtr dwmDll = LoadLibrary("dwmapi.dll"); if (dwmDll == IntPtr.Zero) { return(Marshal.GetLastWin32Error()); } IntPtr dwmFunction = GetProcAddress(dwmDll, "DwmGetWindowAttribute"); if (dwmFunction == IntPtr.Zero) { return(Marshal.GetLastWin32Error()); } var call = (DwmGetWindowAttributeDelegate) Marshal.GetDelegateForFunctionPointer(dwmFunction, typeof( DwmGetWindowAttributeDelegate )); int result = call(hWnd, dwAttribute, ref pvAttribute, cbAttribute); FreeLibrary(dwmDll); return(result); }
internal static extern bool GetWindowRect(IntPtr hWnd, ref WindowsRect rect);
internal static void CaptureWindow(ref ScreenshotTask data) { IntPtr start = WindowsApi.FindWindow("Button", "Start"); IntPtr taskbar = WindowsApi.FindWindow("Shell_TrayWnd", null); if (data.ClipboardNotDisk || Directory.Exists(data.DiskSaveDirectory)) { try { // Hide the taskbar, just incase it gets in the way if (data.WindowHandle != start && data.WindowHandle != taskbar) { WindowsApi.ShowWindow(start, 0); WindowsApi.ShowWindow(taskbar, 0); Application.DoEvents(); } if (WindowsApi.IsIconic(data.WindowHandle)) { WindowsApi.ShowWindow(data.WindowHandle, 1); Thread.Sleep(300); // Wait for window to be restored } else { WindowsApi.ShowWindow(data.WindowHandle, 5); Thread.Sleep(100); } WindowsApi.SetForegroundWindow(data.WindowHandle); var r = new WindowsRect(0); if (data.DoResize) { SmartResizeWindow(ref data, out r); Thread.Sleep(100); } int length = WindowsApi.GetWindowTextLength(data.WindowHandle); var sb = new StringBuilder(length + 1); WindowsApi.GetWindowText(data.WindowHandle, sb, sb.Capacity); string name = sb.ToString(); foreach (char inv in Path.GetInvalidFileNameChars()) name = name.Replace(inv.ToString(), string.Empty); Bitmap s = CaptureCompositeScreenshot(ref data); // Show the taskbar again if (data.WindowHandle != start && data.WindowHandle != taskbar) { WindowsApi.ShowWindow(start, 1); WindowsApi.ShowWindow(taskbar, 1); } if (s == null) { MessageBox.Show( "The screenshot taken was blank, it will not be saved.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); } else { if (data.ClipboardNotDisk && data.Background != ScreenshotTask.BackgroundType.Transparent) // Screenshot is already opaque, don't need to modify it Clipboard.SetImage(s); else if (data.ClipboardNotDisk) { var whiteS = new Bitmap(s.Width, s.Height, PixelFormat.Format24bppRgb); using ( Graphics graphics = Graphics.FromImage(whiteS)) { graphics.Clear(Color.White); graphics.DrawImage(s, 0, 0, s.Width, s.Height); } using (var stream = new MemoryStream()) { // Save screenshot in clipboard as PNG which some applications support (eg. Microsoft Office) s.Save(stream, ImageFormat.Png); var pngClipboardData = new DataObject("PNG", stream); // Add fallback for applications that don't support PNG from clipboard (eg. Photoshop or Paint) pngClipboardData.SetData(DataFormats.Bitmap, whiteS); Clipboard.Clear(); Clipboard.SetDataObject(pngClipboardData, true); } whiteS.Dispose(); } else { name = name.Trim(); if (name == string.Empty) name = "AeroShot"; string path = Path.Combine(data.DiskSaveDirectory, name + ".png"); if (File.Exists(path)) { for (int i = 1; i < 9999; i++) { path = Path.Combine(data.DiskSaveDirectory, name + " " + i + ".png"); if (!File.Exists(path)) break; } } s.Save(path, ImageFormat.Png); } s.Dispose(); } if (data.DoResize) { if ( (WindowsApi.GetWindowLong(data.WindowHandle, GWL_STYLE) & WS_SIZEBOX) == WS_SIZEBOX) { WindowsApi.SetWindowPos(data.WindowHandle, (IntPtr) 0, r.Left, r.Top, r.Right - r.Left, r.Bottom - r.Top, SWP_SHOWWINDOW); } } } catch (Exception) { if (data.WindowHandle != start && data.WindowHandle != taskbar) { WindowsApi.ShowWindow(start, 1); WindowsApi.ShowWindow(taskbar, 1); } MessageBox.Show( "An error occurred while trying to take a screenshot.\r\n\r\nPlease make sure you have selected a valid window.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } else { MessageBox.Show("Invalid directory chosen.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } }
private static unsafe Bitmap CaptureCompositeScreenshot( ref ScreenshotTask data) { Color tmpColour = data.BackgroundColour; if (data.Background == ScreenshotTask.BackgroundType.Transparent || data.Background == ScreenshotTask.BackgroundType.Checkerboard) tmpColour = Color.White; var backdrop = new Form { BackColor = tmpColour, FormBorderStyle = FormBorderStyle.None, ShowInTaskbar = false, Opacity = 0 }; // Generate a rectangle with the size of all monitors combined Rectangle totalSize = Rectangle.Empty; foreach (Screen s in Screen.AllScreens) totalSize = Rectangle.Union(totalSize, s.Bounds); var rct = new WindowsRect(); if ( WindowsApi.DwmGetWindowAttribute(data.WindowHandle, DwmWindowAttribute .ExtendedFrameBounds, ref rct, sizeof (WindowsRect)) != 0) // DwmGetWindowAttribute() failed, usually means Aero is disabled so we fall back to GetWindowRect() WindowsApi.GetWindowRect(data.WindowHandle, ref rct); else { // DwmGetWindowAttribute() succeeded // Add a 100px margin for window shadows. Excess transparency is trimmed out later rct.Left -= 100; rct.Right += 100; rct.Top -= 100; rct.Bottom += 100; } // These next 4 checks handle if the window is outside of the visible screen if (rct.Left < totalSize.Left) rct.Left = totalSize.Left; if (rct.Right > totalSize.Right) rct.Right = totalSize.Right; if (rct.Top < totalSize.Top) rct.Top = totalSize.Top; if (rct.Bottom > totalSize.Bottom) rct.Bottom = totalSize.Bottom; WindowsApi.ShowWindow(backdrop.Handle, 4); WindowsApi.SetWindowPos(backdrop.Handle, data.WindowHandle, rct.Left, rct.Top, rct.Right - rct.Left, rct.Bottom - rct.Top, SWP_NOACTIVATE); backdrop.Opacity = 1; Application.DoEvents(); // Capture screenshot with white background Bitmap whiteShot = CaptureScreenRegion(new Rectangle(rct.Left, rct.Top, rct.Right - rct.Left, rct.Bottom - rct.Top)); if (data.Background == ScreenshotTask.BackgroundType.SolidColour) { backdrop.Dispose(); if (data.CaptureMouse) DrawCursorToBitmap(whiteShot, new Point(rct.Left, rct.Top)); Bitmap final = CropEmptyEdges(whiteShot, tmpColour); whiteShot.Dispose(); return final; } backdrop.BackColor = Color.Black; Application.DoEvents(); // Capture screenshot with black background Bitmap blackShot = CaptureScreenRegion(new Rectangle(rct.Left, rct.Top, rct.Right - rct.Left, rct.Bottom - rct.Top)); backdrop.Dispose(); Bitmap transparentImage = DifferentiateAlpha(whiteShot, blackShot); if (data.CaptureMouse) DrawCursorToBitmap(transparentImage, new Point(rct.Left, rct.Top)); transparentImage = CropEmptyEdges(transparentImage, Color.FromArgb(0, 0, 0, 0)); whiteShot.Dispose(); blackShot.Dispose(); if (data.Background == ScreenshotTask.BackgroundType.Checkerboard) { var final = new Bitmap(transparentImage.Width, transparentImage.Height, PixelFormat.Format24bppRgb); Graphics finalGraphics = Graphics.FromImage(final); var brush = new TextureBrush(GenerateChecker(data.CheckerboardSize)); finalGraphics.FillRectangle(brush, finalGraphics.ClipBounds); finalGraphics.DrawImageUnscaled(transparentImage, 0, 0); finalGraphics.Dispose(); transparentImage.Dispose(); return final; } // Returns a bitmap with transparency, calculated by differentiating the white and black screenshots return transparentImage; }
private static void SmartResizeWindow(ref ScreenshotTask data, out WindowsRect oldWindowSize) { oldWindowSize = new WindowsRect(0); if ((WindowsApi.GetWindowLong(data.WindowHandle, GWL_STYLE) & WS_SIZEBOX) != WS_SIZEBOX) return; var r = new WindowsRect(); WindowsApi.GetWindowRect(data.WindowHandle, ref r); oldWindowSize = r; Bitmap f = CaptureCompositeScreenshot(ref data); if (f != null) { WindowsApi.SetWindowPos(data.WindowHandle, (IntPtr) 0, r.Left, r.Top, data.ResizeX - (f.Width - (r.Right - r.Left)), data.ResizeY - (f.Height - (r.Bottom - r.Top)), SWP_SHOWWINDOW); f.Dispose(); } else { WindowsApi.SetWindowPos(data.WindowHandle, (IntPtr) 0, r.Left, r.Top, data.ResizeX, data.ResizeY, SWP_SHOWWINDOW); } }
internal static extern int DwmGetWindowAttribute(IntPtr hWnd, DwmWindowAttribute dwAttribute, ref WindowsRect pvAttribute, int cbAttribute);
// Safe method of calling dwmapi.dll, for versions of Windows lower than Vista internal static int DwmGetWindowAttribute(IntPtr hWnd, DwmWindowAttribute dwAttribute, ref WindowsRect pvAttribute, int cbAttribute) { IntPtr dwmDll = LoadLibrary("dwmapi.dll"); if (dwmDll == IntPtr.Zero) return Marshal.GetLastWin32Error(); IntPtr dwmFunction = GetProcAddress(dwmDll, "DwmGetWindowAttribute"); if (dwmFunction == IntPtr.Zero) return Marshal.GetLastWin32Error(); var call = (DwmGetWindowAttributeDelegate)Marshal.GetDelegateForFunctionPointer(dwmFunction, typeof(DwmGetWindowAttributeDelegate)); int result = call(hWnd, dwAttribute, ref pvAttribute, cbAttribute); FreeLibrary(dwmDll); return result; }
internal static void CaptureWindow(ref ScreenshotTask data) { IntPtr start = WindowsApi.FindWindow("Button", "Start"); IntPtr taskbar = WindowsApi.FindWindow("Shell_TrayWnd", null); if (data.ClipboardNotDisk || Directory.Exists(data.DiskSaveDirectory)) { try { // Hide the taskbar, just incase it gets in the way if (data.WindowHandle != start && data.WindowHandle != taskbar) { WindowsApi.ShowWindow(start, 0); WindowsApi.ShowWindow(taskbar, 0); Application.DoEvents(); } bool ClearTypeToggled = false; if (data.DisableClearType && ClearTypeEnabled()) { WindowsApi.SystemParametersInfo(SPI_SETFONTSMOOTHINGTYPE, 0, FE_FONTSMOOTHINGSTANDARD, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE); WindowsApi.RedrawWindow(data.WindowHandle, IntPtr.Zero, IntPtr.Zero, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); ClearTypeToggled = true; } WindowsApi.SetForegroundWindow(data.WindowHandle); bool AeroColorToggled = false; WindowsApi.DWM_COLORIZATION_PARAMS originalParameters; WindowsApi.DwmGetColorizationParameters(out originalParameters); if (data.CustomGlass && AeroEnabled()) { // Original colorization parameters originalParameters.clrGlassReflectionIntensity = 50; // Custom colorization parameters WindowsApi.DWM_COLORIZATION_PARAMS parameters; WindowsApi.DwmGetColorizationParameters(out parameters); parameters.clrAfterGlowBalance = 2; parameters.clrBlurBalance = 29; parameters.clrColor = ColorToBgra(data.AeroColor); parameters.nIntensity = 69; // Call the DwmSetColorizationParameters to make the change take effect. WindowsApi.DwmSetColorizationParameters(ref parameters, false); AeroColorToggled = true; } bool ShadowToggled = false; if (data.DisableShadow && ShadowEnabled()) { WindowsApi.SystemParametersInfo(SPI_SETDROPSHADOW, 0, false, 0); ShadowToggled = true; } var r = new WindowsRect(0); if (data.DoResize) { SmartResizeWindow(ref data, out r); Thread.Sleep(100); } int length = WindowsApi.GetWindowTextLength(data.WindowHandle); var sb = new StringBuilder(length + 1); WindowsApi.GetWindowText(data.WindowHandle, sb, sb.Capacity); string name = sb.ToString(); foreach (char inv in Path.GetInvalidFileNameChars()) name = name.Replace(inv.ToString(), string.Empty); Bitmap s = CaptureCompositeScreenshot(ref data); if (AeroColorToggled) { WindowsApi.DwmSetColorizationParameters(ref originalParameters, false); } if (ClearTypeToggled) { WindowsApi.SystemParametersInfo(SPI_SETFONTSMOOTHINGTYPE, 0, FE_FONTSMOOTHINGCLEARTYPE, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE); WindowsApi.RedrawWindow(data.WindowHandle, IntPtr.Zero, IntPtr.Zero, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); } if (ShadowToggled) { WindowsApi.SystemParametersInfo(SPI_SETDROPSHADOW, 0, true, 0); } // Show the taskbar again if (data.WindowHandle != start && data.WindowHandle != taskbar) { WindowsApi.ShowWindow(start, 1); WindowsApi.ShowWindow(taskbar, 1); } if (s == null) { MessageBox.Show("The screenshot taken was blank, it will not be saved.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); } else { if (data.ClipboardNotDisk && data.Background != ScreenshotTask.BackgroundType.Transparent) // Screenshot is already opaque, don't need to modify it Clipboard.SetImage(s); else if (data.ClipboardNotDisk) { var whiteS = new Bitmap(s.Width, s.Height, PixelFormat.Format24bppRgb); using (Graphics graphics = Graphics.FromImage(whiteS)) { graphics.Clear(Color.White); graphics.DrawImage(s, 0, 0, s.Width, s.Height); } using (var stream = new MemoryStream()) { // Save screenshot in clipboard as PNG which some applications support (eg. Microsoft Office) s.Save(stream, ImageFormat.Png); var pngClipboardData = new DataObject("PNG", stream); // Add fallback for applications that don't support PNG from clipboard (eg. Photoshop or Paint) pngClipboardData.SetData(DataFormats.Bitmap, whiteS); Clipboard.Clear(); Clipboard.SetDataObject(pngClipboardData, true); } whiteS.Dispose(); } else { name = name.Trim(); if (name == string.Empty) name = "AeroShot"; string path = Path.Combine(data.DiskSaveDirectory, name + ".png"); if (File.Exists(path)) { for (int i = 1; i < 9999; i++) { path = Path.Combine(data.DiskSaveDirectory, name + " " + i + ".png"); if (!File.Exists(path)) break; } } s.Save(path, ImageFormat.Png); } s.Dispose(); } if (data.DoResize) { if ((WindowsApi.GetWindowLong(data.WindowHandle, GWL_STYLE) & WS_SIZEBOX) == WS_SIZEBOX) { WindowsApi.SetWindowPos(data.WindowHandle, (IntPtr)0, r.Left, r.Top, r.Right - r.Left, r.Bottom - r.Top, SWP_SHOWWINDOW); } } } catch (Exception) { if (data.WindowHandle != start && data.WindowHandle != taskbar) { WindowsApi.ShowWindow(start, 1); WindowsApi.ShowWindow(taskbar, 1); } MessageBox.Show("An error occurred while trying to take a screenshot.\r\n\r\nPlease make sure you have selected a valid window.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } else { MessageBox.Show("Invalid directory chosen.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } }
internal static void CaptureWindow(ref ScreenshotTask data) { IntPtr start = WindowsApi.FindWindow("Button", "Start"); IntPtr taskbar = WindowsApi.FindWindow("Shell_TrayWnd", null); if (data.ClipboardNotDisk || Directory.Exists(data.DiskSaveDirectory)) { try { // Hide the taskbar, just incase it gets in the way if (data.WindowHandle != start && data.WindowHandle != taskbar) { WindowsApi.ShowWindow(start, 0); WindowsApi.ShowWindow(taskbar, 0); Application.DoEvents(); } bool ClearTypeToggled = false; if (data.DisableClearType && ClearTypeEnabled()) { WindowsApi.SystemParametersInfo(SPI_SETFONTSMOOTHINGTYPE, 0, FE_FONTSMOOTHINGSTANDARD, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE); WindowsApi.RedrawWindow(data.WindowHandle, IntPtr.Zero, IntPtr.Zero, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); ClearTypeToggled = true; } WindowsApi.SetForegroundWindow(data.WindowHandle); bool AeroColorToggled = false; WindowsApi.DWM_COLORIZATION_PARAMS originalParameters; WindowsApi.DwmGetColorizationParameters(out originalParameters); if (data.CustomGlass && AeroEnabled()) { // Original colorization parameters originalParameters.clrGlassReflectionIntensity = 50; // Custom colorization parameters WindowsApi.DWM_COLORIZATION_PARAMS parameters; WindowsApi.DwmGetColorizationParameters(out parameters); parameters.clrAfterGlowBalance = 2; parameters.clrBlurBalance = 29; parameters.clrColor = ColorToBgra(data.AeroColor); parameters.nIntensity = 69; // Call the DwmSetColorizationParameters to make the change take effect. WindowsApi.DwmSetColorizationParameters(ref parameters, false); AeroColorToggled = true; } bool ShadowToggled = false; if (data.DisableShadow && ShadowEnabled()) { WindowsApi.SystemParametersInfo(SPI_SETDROPSHADOW, 0, false, 0); ShadowToggled = true; } var r = new WindowsRect(0); if (data.DoResize) { SmartResizeWindow(ref data, out r); Thread.Sleep(100); } int length = WindowsApi.GetWindowTextLength(data.WindowHandle); var sb = new StringBuilder(length + 1); WindowsApi.GetWindowText(data.WindowHandle, sb, sb.Capacity); string name = sb.ToString(); foreach (char inv in Path.GetInvalidFileNameChars()) { name = name.Replace(inv.ToString(), string.Empty); } Bitmap s = CaptureCompositeScreenshot(ref data); if (AeroColorToggled) { WindowsApi.DwmSetColorizationParameters(ref originalParameters, false); } if (ClearTypeToggled) { WindowsApi.SystemParametersInfo(SPI_SETFONTSMOOTHINGTYPE, 0, FE_FONTSMOOTHINGCLEARTYPE, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE); WindowsApi.RedrawWindow(data.WindowHandle, IntPtr.Zero, IntPtr.Zero, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); } if (ShadowToggled) { WindowsApi.SystemParametersInfo(SPI_SETDROPSHADOW, 0, true, 0); } // Show the taskbar again if (data.WindowHandle != start && data.WindowHandle != taskbar) { WindowsApi.ShowWindow(start, 1); WindowsApi.ShowWindow(taskbar, 1); } if (s == null) { MessageBox.Show("The screenshot taken was blank, it will not be saved.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); } else { if (data.ClipboardNotDisk && data.Background != ScreenshotTask.BackgroundType.Transparent) { // Screenshot is already opaque, don't need to modify it Clipboard.SetImage(s); } else if (data.ClipboardNotDisk) { var whiteS = new Bitmap(s.Width, s.Height, PixelFormat.Format24bppRgb); using (Graphics graphics = Graphics.FromImage(whiteS)) { graphics.Clear(Color.White); graphics.DrawImage(s, 0, 0, s.Width, s.Height); } using (var stream = new MemoryStream()) { // Save screenshot in clipboard as PNG which some applications support (eg. Microsoft Office) s.Save(stream, ImageFormat.Png); var pngClipboardData = new DataObject("PNG", stream); // Add fallback for applications that don't support PNG from clipboard (eg. Photoshop or Paint) pngClipboardData.SetData(DataFormats.Bitmap, whiteS); Clipboard.Clear(); Clipboard.SetDataObject(pngClipboardData, true); } whiteS.Dispose(); } else { name = name.Trim(); if (name == string.Empty) { name = "AeroShot"; } string path = Path.Combine(data.DiskSaveDirectory, name + ".png"); if (File.Exists(path)) { for (int i = 1; i < 9999; i++) { path = Path.Combine(data.DiskSaveDirectory, name + " " + i + ".png"); if (!File.Exists(path)) { break; } } } s.Save(path, ImageFormat.Png); } s.Dispose(); } if (data.DoResize) { if ((WindowsApi.GetWindowLong(data.WindowHandle, GWL_STYLE) & WS_SIZEBOX) == WS_SIZEBOX) { WindowsApi.SetWindowPos(data.WindowHandle, (IntPtr)0, r.Left, r.Top, r.Right - r.Left, r.Bottom - r.Top, SWP_SHOWWINDOW); } } } catch (Exception) { if (data.WindowHandle != start && data.WindowHandle != taskbar) { WindowsApi.ShowWindow(start, 1); WindowsApi.ShowWindow(taskbar, 1); } MessageBox.Show("An error occurred while trying to take a screenshot.\r\n\r\nPlease make sure you have selected a valid window.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } else { MessageBox.Show("Invalid directory chosen.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } }
private static unsafe Bitmap CaptureCompositeScreenshot(ref ScreenshotTask data) { Color tmpColor = data.BackgroundColor; if (data.Background == ScreenshotTask.BackgroundType.Transparent || data.Background == ScreenshotTask.BackgroundType.Checkerboard) { tmpColor = Color.White; } var backdrop = new Form { BackColor = tmpColor, FormBorderStyle = FormBorderStyle.None, ShowInTaskbar = false, Opacity = 0 }; // Generate a rectangle with the size of all monitors combined Rectangle totalSize = Rectangle.Empty; foreach (Screen s in Screen.AllScreens) { totalSize = Rectangle.Union(totalSize, s.Bounds); } var rct = new WindowsRect(); if (WindowsApi.DwmGetWindowAttribute(data.WindowHandle, DwmWindowAttribute.ExtendedFrameBounds, ref rct, sizeof(WindowsRect)) != 0) { // DwmGetWindowAttribute() failed, usually means Aero is disabled so we fall back to GetWindowRect() WindowsApi.GetWindowRect(data.WindowHandle, ref rct); } else { // DwmGetWindowAttribute() succeeded // Add a 100px margin for window shadows. Excess transparency is trimmed out later rct.Left -= 100; rct.Right += 100; rct.Top -= 100; rct.Bottom += 100; } // These next 4 checks handle if the window is outside of the visible screen if (rct.Left < totalSize.Left) { rct.Left = totalSize.Left; } if (rct.Right > totalSize.Right) { rct.Right = totalSize.Right; } if (rct.Top < totalSize.Top) { rct.Top = totalSize.Top; } if (rct.Bottom > totalSize.Bottom) { rct.Bottom = totalSize.Bottom; } WindowsApi.ShowWindow(backdrop.Handle, 4); WindowsApi.SetWindowPos(backdrop.Handle, data.WindowHandle, rct.Left, rct.Top, rct.Right - rct.Left, rct.Bottom - rct.Top, SWP_NOACTIVATE); backdrop.Opacity = 1; Application.DoEvents(); // Capture screenshot with white background Bitmap whiteShot = CaptureScreenRegion(new Rectangle(rct.Left, rct.Top, rct.Right - rct.Left, rct.Bottom - rct.Top)); if (data.Background == ScreenshotTask.BackgroundType.SolidColor) { backdrop.Dispose(); if (data.CaptureMouse) { DrawCursorToBitmap(whiteShot, new Point(rct.Left, rct.Top)); } Bitmap final = CropEmptyEdges(whiteShot, tmpColor); whiteShot.Dispose(); return(final); } backdrop.BackColor = Color.Black; Application.DoEvents(); // Capture screenshot with black background Bitmap blackShot = CaptureScreenRegion(new Rectangle(rct.Left, rct.Top, rct.Right - rct.Left, rct.Bottom - rct.Top)); backdrop.Dispose(); Bitmap transparentImage = DifferentiateAlpha(whiteShot, blackShot); if (data.CaptureMouse) { DrawCursorToBitmap(transparentImage, new Point(rct.Left, rct.Top)); } transparentImage = CropEmptyEdges(transparentImage, Color.FromArgb(0, 0, 0, 0)); whiteShot.Dispose(); blackShot.Dispose(); if (data.Background == ScreenshotTask.BackgroundType.Checkerboard) { var final = new Bitmap(transparentImage.Width, transparentImage.Height, PixelFormat.Format24bppRgb); Graphics finalGraphics = Graphics.FromImage(final); var brush = new TextureBrush(GenerateChecker(data.CheckerboardSize)); finalGraphics.FillRectangle(brush, finalGraphics.ClipBounds); finalGraphics.DrawImageUnscaled(transparentImage, 0, 0); finalGraphics.Dispose(); transparentImage.Dispose(); return(final); } // Returns a bitmap with transparency, calculated by differentiating the white and black screenshots return(transparentImage); }
internal static void CaptureWindow(ref ScreenshotTask data) { IntPtr start = WindowsApi.FindWindow("Button", "Start"); IntPtr taskbar = WindowsApi.FindWindow("Shell_TrayWnd", null); if (data.ClipboardNotDisk || Directory.Exists(data.DiskSaveDirectory)) { try { // Hide the taskbar, just incase it gets in the way if (data.WindowHandle != start && data.WindowHandle != taskbar) { WindowsApi.ShowWindow(start, 0); WindowsApi.ShowWindow(taskbar, 0); Application.DoEvents(); } if (WindowsApi.IsIconic(data.WindowHandle)) { WindowsApi.ShowWindow(data.WindowHandle, 1); Thread.Sleep(300); // Wait for window to be restored } else { WindowsApi.ShowWindow(data.WindowHandle, 5); Thread.Sleep(100); } WindowsApi.SetForegroundWindow(data.WindowHandle); var r = new WindowsRect(0); if (data.DoResize) { SmartResizeWindow(ref data, out r); Thread.Sleep(100); } int length = WindowsApi.GetWindowTextLength(data.WindowHandle); var sb = new StringBuilder(length + 1); WindowsApi.GetWindowText(data.WindowHandle, sb, sb.Capacity); string name = sb.ToString(); foreach (char inv in Path.GetInvalidFileNameChars()) { name = name.Replace(inv.ToString(), string.Empty); } Bitmap s = CaptureCompositeScreenshot(ref data); // Show the taskbar again if (data.WindowHandle != start && data.WindowHandle != taskbar) { WindowsApi.ShowWindow(start, 1); WindowsApi.ShowWindow(taskbar, 1); } if (s == null) { MessageBox.Show( "The screenshot taken was blank, it will not be saved.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); } else { if (data.ClipboardNotDisk && data.Background != ScreenshotTask.BackgroundType.Transparent) { // Screenshot is already opaque, don't need to modify it Clipboard.SetImage(s); } else if (data.ClipboardNotDisk) { var whiteS = new Bitmap(s.Width, s.Height, PixelFormat.Format24bppRgb); using ( Graphics graphics = Graphics.FromImage(whiteS)) { graphics.Clear(Color.White); graphics.DrawImage(s, 0, 0, s.Width, s.Height); } using (var stream = new MemoryStream()) { // Save screenshot in clipboard as PNG which some applications support (eg. Microsoft Office) s.Save(stream, ImageFormat.Png); var pngClipboardData = new DataObject("PNG", stream); // Add fallback for applications that don't support PNG from clipboard (eg. Photoshop or Paint) pngClipboardData.SetData(DataFormats.Bitmap, whiteS); Clipboard.Clear(); Clipboard.SetDataObject(pngClipboardData, true); } whiteS.Dispose(); } else { name = name.Trim(); if (name == string.Empty) { name = "AeroShot"; } string path = Path.Combine(data.DiskSaveDirectory, name + ".png"); if (File.Exists(path)) { for (int i = 1; i < 9999; i++) { path = Path.Combine(data.DiskSaveDirectory, name + " " + i + ".png"); if (!File.Exists(path)) { break; } } } s.Save(path, ImageFormat.Png); } s.Dispose(); } if (data.DoResize) { if ( (WindowsApi.GetWindowLong(data.WindowHandle, GWL_STYLE) & WS_SIZEBOX) == WS_SIZEBOX) { WindowsApi.SetWindowPos(data.WindowHandle, (IntPtr)0, r.Left, r.Top, r.Right - r.Left, r.Bottom - r.Top, SWP_SHOWWINDOW); } } } catch (Exception) { if (data.WindowHandle != start && data.WindowHandle != taskbar) { WindowsApi.ShowWindow(start, 1); WindowsApi.ShowWindow(taskbar, 1); } MessageBox.Show( "An error occurred while trying to take a screenshot.\r\n\r\nPlease make sure you have selected a valid window.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } else { MessageBox.Show("Invalid directory chosen.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } }
private static unsafe Bitmap[] CaptureCompositeScreenshot(ref ScreenshotTask data) { // Generate a rectangle with the size of all monitors combined Rectangle totalSize = Rectangle.Empty; foreach (Screen s in Screen.AllScreens) { totalSize = Rectangle.Union(totalSize, s.Bounds); } var rct = new WindowsRect(); if (WindowsApi.DwmGetWindowAttribute(data.WindowHandle, DwmWindowAttribute.ExtendedFrameBounds, ref rct, sizeof(WindowsRect)) != 0) { // DwmGetWindowAttribute() failed, usually means Aero is disabled so we fall back to GetWindowRect() WindowsApi.GetWindowRect(data.WindowHandle, ref rct); } else { // DwmGetWindowAttribute() succeeded } // Get DPI of the window (this only works properly on Win 10 1607+) but it is not really needed until Win 11 anyway int DPI = 96; try { DPI = WindowsApi.GetDpiForWindow(data.WindowHandle); } catch { } // Adjust margin for DPI double scalingFactor = DPI / 96; int backdropOffset = Convert.ToInt32(100 * scalingFactor); // Add a 100px margin for window shadows. Excess transparency is trimmed out later rct.Left -= backdropOffset; rct.Right += backdropOffset; rct.Top -= backdropOffset; rct.Bottom += backdropOffset; // These next 4 checks handle if the window is outside of the visible screen if (rct.Left < totalSize.Left) { rct.Left = totalSize.Left; } if (rct.Right > totalSize.Right) { rct.Right = totalSize.Right; } if (rct.Top < totalSize.Top) { rct.Top = totalSize.Top; } if (rct.Bottom > totalSize.Bottom) { rct.Bottom = totalSize.Bottom; } // Spawning backdrop // Handling as much as possible in the constructor makes this easier to render, which makes capture less likely to fail on underpowered PCs Color tmpColor = Color.White; var backdrop = new Form { BackColor = tmpColor, FormBorderStyle = FormBorderStyle.None, ShowInTaskbar = false, //Opacity = 0, Size = new Size(rct.Right - rct.Left, rct.Bottom - rct.Top), StartPosition = FormStartPosition.Manual, Location = new Point(rct.Left, rct.Top) }; WindowsApi.ShowWindow(backdrop.Handle, 4); if (!WindowsApi.SetWindowPos(backdrop.Handle, data.WindowHandle, rct.Left, rct.Top, rct.Right - rct.Left, rct.Bottom - rct.Top, SWP_NOACTIVATE)) { // We are unable to put backdrop directly behind the window, so we will put it into the foreground and then put the original window on top of it // This likely happens because the program we're trying to capture is running as administrator WindowsApi.SetWindowPos(backdrop.Handle, IntPtr.Zero, rct.Left, rct.Top, rct.Right - rct.Left, rct.Bottom - rct.Top, SWP_NOACTIVATE); WindowsApi.SetForegroundWindow(data.WindowHandle).ToString(); } RefreshBackdrop(); // Capture screenshot with white background Bitmap whiteShot = CaptureScreenRegion(new Rectangle(rct.Left, rct.Top, rct.Right - rct.Left, rct.Bottom - rct.Top)); backdrop.BackColor = Color.Black; RefreshBackdrop(); // Capture screenshot with black background Bitmap blackShot = CaptureScreenRegion(new Rectangle(rct.Left, rct.Top, rct.Right - rct.Left, rct.Bottom - rct.Top)); Bitmap transparentImage; Bitmap transparentInactiveImage = null; Bitmap transparentWhiteImage = null; Bitmap transparentWhiteInactiveImage = null; Bitmap transparentMaskImage = null; Bitmap transparentTransparentImage = null; Bitmap transparentTransparentInactiveImage = null; transparentImage = DifferentiateAlpha(whiteShot, blackShot, false); if (data.SaveActiveLight) { transparentWhiteImage = DifferentiateAlpha(whiteShot, blackShot, true); } whiteShot.Dispose(); blackShot.Dispose(); //Capture black mask screenshot if (data.SaveMask) { int minAlpha = 0; bool isCompositing = false; bool ShadowToggled = false; bool ColorToggled = false; try { WindowsApi.DwmIsCompositionEnabled(out isCompositing); } catch (Exception) { //OS doesn't have a supported version of DWM } //We can't disable shadows on Vista without disabling DWM, which would cause the mask to be inaccurate UInt32 ColorizationColor = 0; bool fOpaque = true; if (isCompositing && (VersionHelpers.IsWindowsVista() || VersionHelpers.IsWindows11())) { minAlpha = 254; WindowsApi.DwmGetColorizationColor(out ColorizationColor, out fOpaque); if (fOpaque == false) { WindowsApi.DwmpSetColorization(ColorizationColor, true, 0xFF); ColorToggled = true; } } else if (ShadowEnabled()) { WindowsApi.SystemParametersInfo(SPI_SETDROPSHADOW, 0, false, 0); ShadowToggled = true; } backdrop.BackColor = Color.White; RefreshBackdrop(); Bitmap whiteMaskShot = CaptureScreenRegion(new Rectangle(rct.Left, rct.Top, rct.Right - rct.Left, rct.Bottom - rct.Top)); backdrop.BackColor = Color.Black; RefreshBackdrop(); Bitmap blackMaskShot = CaptureScreenRegion(new Rectangle(rct.Left, rct.Top, rct.Right - rct.Left, rct.Bottom - rct.Top)); transparentMaskImage = CreateMask(DifferentiateAlpha(whiteMaskShot, blackMaskShot, false), minAlpha); if (ShadowToggled) { WindowsApi.SystemParametersInfo(SPI_SETDROPSHADOW, 0, true, 0); } if (ColorToggled) { WindowsApi.DwmpSetColorization(ColorizationColor, fOpaque, 0xFF); } whiteMaskShot.Dispose(); blackMaskShot.Dispose(); } //Capture active fully transparent if (data.SaveActiveTransparent) { try { //win 7 WindowsApi.DWM_COLORIZATION_PARAMS parameters, originalParameters = new WindowsApi.DWM_COLORIZATION_PARAMS(); //win vista UInt32 ColorizationColor = 0; bool fOpaque = true; if (VersionHelpers.IsWindowsVista()) { WindowsApi.DwmGetColorizationColor(out ColorizationColor, out fOpaque); if (fOpaque == false) { WindowsApi.DwmpSetColorization(0xFFFFFF, false, 0xFF); } } else { WindowsApi.DwmGetColorizationParameters(out parameters); WindowsApi.DwmGetColorizationParameters(out originalParameters); //Set custom fully transparent parameters parameters.clrAfterGlowBalance = 0; parameters.clrBlurBalance = 100; parameters.nIntensity = 0; // Call the DwmSetColorizationParameters to make the change take effect. WindowsApi.DwmSetColorizationParameters(ref parameters, false); } backdrop.BackColor = Color.White; RefreshBackdrop(); Bitmap whiteTransparentShot = CaptureScreenRegion(new Rectangle(rct.Left, rct.Top, rct.Right - rct.Left, rct.Bottom - rct.Top)); backdrop.BackColor = Color.Black; RefreshBackdrop(); Bitmap blackTransparentShot = CaptureScreenRegion(new Rectangle(rct.Left, rct.Top, rct.Right - rct.Left, rct.Bottom - rct.Top)); transparentTransparentImage = DifferentiateAlpha(whiteTransparentShot, blackTransparentShot, false); whiteTransparentShot.Dispose(); blackTransparentShot.Dispose(); if (VersionHelpers.IsWindowsVista()) { WindowsApi.DwmpSetColorization(ColorizationColor, fOpaque, 0xFF); } else { WindowsApi.DwmSetColorizationParameters(ref originalParameters, false); } } catch (Exception) { transparentTransparentImage = new Bitmap(transparentImage); } } //Show form to steal focus var emptyForm = new Form { FormBorderStyle = FormBorderStyle.None, ShowInTaskbar = false, Opacity = 0, }; WindowsApi.ShowWindow(emptyForm.Handle, 5); WindowsApi.SetWindowPos(emptyForm.Handle, data.WindowHandle, rct.Left, rct.Top, rct.Right - rct.Left, rct.Bottom - rct.Top, 0); WindowsApi.SetForegroundWindow(emptyForm.Handle); // Capture inactive screenshots if (data.SaveInactiveDark || data.SaveInactiveLight) { backdrop.BackColor = Color.White; RefreshBackdrop(); // Capture inactive screenshot with white background Bitmap whiteInactiveShot = CaptureScreenRegion(new Rectangle(rct.Left, rct.Top, rct.Right - rct.Left, rct.Bottom - rct.Top)); backdrop.BackColor = Color.Black; RefreshBackdrop(); // Capture inactive screenshot with black background Bitmap blackInactiveShot = CaptureScreenRegion(new Rectangle(rct.Left, rct.Top, rct.Right - rct.Left, rct.Bottom - rct.Top)); if (data.SaveInactiveDark) { transparentInactiveImage = DifferentiateAlpha(whiteInactiveShot, blackInactiveShot, false); } if (data.SaveInactiveLight) { transparentWhiteInactiveImage = DifferentiateAlpha(whiteInactiveShot, blackInactiveShot, true); } whiteInactiveShot.Dispose(); blackInactiveShot.Dispose(); } //Capture inactive fully transparent if (data.SaveInactiveTransparent) { try { //Get original colorization parameters WindowsApi.DWM_COLORIZATION_PARAMS parameters, originalParameters; WindowsApi.DwmGetColorizationParameters(out parameters); WindowsApi.DwmGetColorizationParameters(out originalParameters); //Set custom fully transparent parameters parameters.clrAfterGlowBalance = 0; parameters.clrBlurBalance = 100; parameters.nIntensity = 0; // Call the DwmSetColorizationParameters to make the change take effect. WindowsApi.DwmSetColorizationParameters(ref parameters, false); backdrop.BackColor = Color.White; RefreshBackdrop(); Bitmap whiteTransparentInactiveShot = CaptureScreenRegion(new Rectangle(rct.Left, rct.Top, rct.Right - rct.Left, rct.Bottom - rct.Top)); backdrop.BackColor = Color.Black; RefreshBackdrop(); Bitmap blackTransparentInactiveShot = CaptureScreenRegion(new Rectangle(rct.Left, rct.Top, rct.Right - rct.Left, rct.Bottom - rct.Top)); transparentTransparentInactiveImage = DifferentiateAlpha(whiteTransparentInactiveShot, blackTransparentInactiveShot, false); whiteTransparentInactiveShot.Dispose(); blackTransparentInactiveShot.Dispose(); WindowsApi.DwmSetColorizationParameters(ref originalParameters, false); } catch (Exception) { transparentTransparentInactiveImage = new Bitmap(transparentInactiveImage); } } backdrop.Dispose(); emptyForm.Dispose(); if (data.CaptureMouse) { DrawCursorToBitmap(transparentImage, new Point(rct.Left, rct.Top)); } Bitmap[] final = CropEmptyEdges(new[] { transparentImage, transparentInactiveImage, transparentWhiteImage, transparentWhiteInactiveImage, transparentMaskImage, transparentTransparentImage, transparentTransparentInactiveImage }, Color.FromArgb(0, 0, 0, 0), ref data); // Returns a bitmap with transparency, calculated by differentiating the white and black screenshots return(final); }