/// <summary> /// This method will show the supplied context menu at the mouse cursor, also makes sure it has focus and it's not /// visible in the taskbar. /// </summary> /// <param name="menu"></param> private static void ShowMenuAtCursor(ContextMenuStrip menu) { // find a suitable location var location = Cursor.Position; var menuRectangle = new NativeRect(location, menu.Size).Intersect(WindowCapture.GetScreenBounds()); if (menuRectangle.Height < menu.Height) { location.Offset(-40, -(menuRectangle.Height - menu.Height)); } else { location.Offset(-40, -10); } // This prevents the problem that the context menu shows in the task-bar // TODO: Get a handle // User32Api.SetForegroundWindow(PluginUtils.Host.NotifyIcon.ContextMenuStrip.Handle); menu.Show(location); menu.Focus(); // Wait for the menu to close while (true) { if (menu.Visible) { Application.DoEvents(); Thread.Sleep(200); } else { //menu.Dispose(); break; } } }
/// <summary> /// Capture DWM Window /// </summary> /// <param name="interopWindow">IInteropWindow</param> /// <param name="capture">Capture to fill</param> /// <param name="windowCaptureMode">Wanted WindowCaptureModes</param> /// <param name="autoMode">True if auto modus is used</param> /// <returns>ICapture with the capture</returns> public static ICapture CaptureDwmWindow(this IInteropWindow interopWindow, ICapture capture, WindowCaptureModes windowCaptureMode, bool autoMode) { var thumbnailHandle = IntPtr.Zero; Form tempForm = null; var tempFormShown = false; try { tempForm = new Form { ShowInTaskbar = false, FormBorderStyle = FormBorderStyle.None, TopMost = true }; // Register the Thumbnail Dwm.DwmRegisterThumbnail(tempForm.Handle, interopWindow.Handle, out thumbnailHandle); // Get the original size Dwm.DwmQueryThumbnailSourceSize(thumbnailHandle, out var sourceSize); if (sourceSize.Width <= 0 || sourceSize.Height <= 0) { return(null); } // Calculate the location of the temp form var windowRectangle = interopWindow.GetInfo().Bounds; var formLocation = windowRectangle.Location; var borderSize = new Size(); var doesCaptureFit = false; if (!interopWindow.IsMaximized()) { // Assume using it's own location formLocation = windowRectangle.Location; using (var workingArea = new Region(Screen.PrimaryScreen.Bounds)) { // Find the screen where the window is and check if it fits foreach (var screen in Screen.AllScreens) { if (!Equals(screen, Screen.PrimaryScreen)) { workingArea.Union(screen.Bounds); } } // If the formLocation is not inside the visible area if (!workingArea.AreRectangleCornersVisisble(windowRectangle)) { // If none found we find the biggest screen foreach (var screen in Screen.AllScreens) { var newWindowRectangle = new NativeRect(screen.WorkingArea.Location, windowRectangle.Size); if (workingArea.AreRectangleCornersVisisble(newWindowRectangle)) { formLocation = screen.Bounds.Location; doesCaptureFit = true; break; } } } else { doesCaptureFit = true; } } } else if (!WindowsVersion.IsWindows8OrLater) { //GetClientRect(out windowRectangle); borderSize = interopWindow.GetInfo().BorderSize; formLocation = new NativePoint(windowRectangle.X - borderSize.Width, windowRectangle.Y - borderSize.Height); } tempForm.Location = formLocation; tempForm.Size = sourceSize; // Prepare rectangle to capture from the screen. var captureRectangle = new NativeRect(formLocation.X, formLocation.Y, sourceSize.Width, sourceSize.Height); if (interopWindow.IsMaximized()) { // Correct capture size for maximized window by offsetting the X,Y with the border size // and subtracting the border from the size (2 times, as we move right/down for the capture without resizing) captureRectangle = captureRectangle.Inflate(borderSize.Width, borderSize.Height); } else { // TODO: Also 8.x? if (WindowsVersion.IsWindows10) { captureRectangle = captureRectangle.Inflate(CoreConfiguration.Win10BorderCrop.Width, CoreConfiguration.Win10BorderCrop.Height); } if (autoMode) { // check if the capture fits if (!doesCaptureFit) { // if GDI is allowed.. (a screenshot won't be better than we comes if we continue) using (var thisWindowProcess = Process.GetProcessById(interopWindow.GetProcessId())) { if (!interopWindow.IsApp() && WindowCapture.IsGdiAllowed(thisWindowProcess)) { // we return null which causes the capturing code to try another method. return(null); } } } } } // Prepare the displaying of the Thumbnail var props = new DwmThumbnailProperties { Opacity = 255, Visible = true, Destination = new NativeRect(0, 0, sourceSize.Width, sourceSize.Height) }; Dwm.DwmUpdateThumbnailProperties(thumbnailHandle, ref props); tempForm.Show(); tempFormShown = true; // Intersect with screen captureRectangle = captureRectangle.Intersect(capture.ScreenBounds); // Destination bitmap for the capture Bitmap capturedBitmap = null; // Check if we make a transparent capture if (windowCaptureMode == WindowCaptureModes.AeroTransparent) { // Use white, later black to capture transparent tempForm.BackColor = Color.White; // Make sure everything is visible tempForm.Refresh(); Application.DoEvents(); try { using (var whiteBitmap = WindowCapture.CaptureRectangle(captureRectangle)) { // Apply a white color tempForm.BackColor = Color.Black; // Make sure everything is visible tempForm.Refresh(); if (!interopWindow.IsApp()) { // Make sure the application window is active, so the colors & buttons are right // TODO: Await? interopWindow.ToForegroundAsync(); } // Make sure all changes are processed and visible Application.DoEvents(); using (var blackBitmap = WindowCapture.CaptureRectangle(captureRectangle)) { capturedBitmap = ApplyTransparency(blackBitmap, whiteBitmap); } } } catch (Exception e) { Log.Warn().WriteLine(e, "Exception: "); // Some problem occurred, cleanup and make a normal capture if (capturedBitmap != null) { capturedBitmap.Dispose(); capturedBitmap = null; } } } // If no capture up till now, create a normal capture. if (capturedBitmap == null) { // Remove transparency, this will break the capturing if (!autoMode) { tempForm.BackColor = Color.FromArgb(255, CoreConfiguration.DWMBackgroundColor.R, CoreConfiguration.DWMBackgroundColor.G, CoreConfiguration.DWMBackgroundColor.B); } else { var colorizationColor = Dwm.ColorizationSystemDrawingColor; // Modify by losing the transparency and increasing the intensity (as if the background color is white) colorizationColor = Color.FromArgb(255, (colorizationColor.R + 255) >> 1, (colorizationColor.G + 255) >> 1, (colorizationColor.B + 255) >> 1); tempForm.BackColor = colorizationColor; } // Make sure everything is visible tempForm.Refresh(); if (!interopWindow.IsApp()) { // Make sure the application window is active, so the colors & buttons are right interopWindow.ToForegroundAsync(); } // Make sure all changes are processed and visible Application.DoEvents(); // Capture from the screen capturedBitmap = WindowCapture.CaptureRectangle(captureRectangle); } if (capturedBitmap != null) { // Not needed for Windows 8 if (!WindowsVersion.IsWindows8OrLater) { // Only if the Inivalue is set, not maximized and it's not a tool window. if (CoreConfiguration.WindowCaptureRemoveCorners && !interopWindow.IsMaximized() && !interopWindow.GetInfo().ExtendedStyle.HasFlag(ExtendedWindowStyleFlags.WS_EX_TOOLWINDOW)) { // Remove corners if (!Image.IsAlphaPixelFormat(capturedBitmap.PixelFormat)) { Log.Debug().WriteLine("Changing pixelformat to Alpha for the RemoveCorners"); var tmpBitmap = capturedBitmap.CloneBitmap(PixelFormat.Format32bppArgb) as Bitmap; capturedBitmap.Dispose(); capturedBitmap = tmpBitmap; } RemoveCorners(capturedBitmap); } } } capture.Bitmap = capturedBitmap; // Make sure the capture location is the location of the window, not the copy capture.Location = interopWindow.GetInfo().Bounds.Location; } finally { if (thumbnailHandle != IntPtr.Zero) { // Unregister (cleanup), as we are finished we don't need the form or the thumbnail anymore Dwm.DwmUnregisterThumbnail(thumbnailHandle); } if (tempForm != null) { if (tempFormShown) { tempForm.Close(); } tempForm.Dispose(); tempForm = null; } } return(capture); }
/// <summary> /// Extension method to capture a bitmap of the screen area where the InteropWindow is located /// </summary> /// <param name="interopWindow">InteropWindow</param> /// <param name="clientBounds">true to use the client bounds</param> /// <returns>Bitmap</returns> public static Bitmap CaptureFromScreen(this IInteropWindow interopWindow, bool clientBounds = false) { var bounds = clientBounds ? interopWindow.GetInfo().ClientBounds: interopWindow.GetInfo().Bounds; return(WindowCapture.CaptureRectangle(bounds)); }
/// <summary> /// Default Constructor /// </summary> public Capture() { _screenBounds = WindowCapture.GetScreenBounds(); _captureDetails = new CaptureDetails(); }