internal static void InvalidatePreview(TaskbarWindow taskbarWindow) { if (taskbarWindow != null) _ = DesktopWindowManager.DwmInvalidateIconicBitmaps( taskbarWindow.WindowToTellTaskbarAbout); }
internal static void AddTabbedThumbnail(TabbedThumbnail preview) { // Create a TOP-LEVEL proxy window for the user's source window/control TaskbarWindow taskbarWindow = preview.WindowHandle == IntPtr.Zero ? GetTaskbarWindow(preview.WindowsControl, TaskbarProxyWindowType.TabbedThumbnail) : GetTaskbarWindow(preview.WindowHandle, TaskbarProxyWindowType.TabbedThumbnail); // get the TaskbarWindow for UIElement/WindowHandle respectfully. //create taskbar, or set its TabbedThumbnail if (taskbarWindow == null) { taskbarWindow = new TaskbarWindow(preview); _taskbarWindowList.Add(taskbarWindow); } else if (taskbarWindow.TabbedThumbnail == null) taskbarWindow.TabbedThumbnail = preview; // Listen for Title changes preview.TitleChanged += new EventHandler(ThumbnailPreview_TitleChanged); preview.TooltipChanged += new EventHandler(ThumbnailPreview_TooltipChanged); // Get/Set properties for proxy window IntPtr windowHandle = taskbarWindow.WindowToTellTaskbarAbout; // Register this new tab and set it as being active. TaskbarList.Instance.RegisterTab(windowHandle, preview.ParentWindowHandle); TaskbarList.Instance.SetTabOrder(windowHandle, IntPtr.Zero); TaskbarList.Instance.SetTabActive(windowHandle, preview.ParentWindowHandle, 0); // We need to make sure we can set these properties even when running with admin var changeFilterResult = new ChangeFilterStruct { cbSize = (uint)Marshal.SizeOf #if CS7 < #else (typeof( #endif ChangeFilterStruct #if CS7 >( #else ) #endif ) }; _ = HandlerNativeMethods.ChangeWindowMessageFilterEx( windowHandle, WindowMessage.DWMSendIconicThumbnail, MessageFilterAction.Allow, ref changeFilterResult); changeFilterResult = new ChangeFilterStruct { cbSize = (uint)Marshal.SizeOf #if CS7 < #else (typeof( #endif ChangeFilterStruct #if CS7 >( #else ) #endif ) }; _ = HandlerNativeMethods.ChangeWindowMessageFilterEx( windowHandle, WindowMessage.DWMSendIconicLivePreviewBitmap, MessageFilterAction.Allow, ref changeFilterResult); // BUG: There should be somewhere to disable CustomWindowPreview. I didn't find it. DesktopWindowManager.EnableCustomWindowPreview(windowHandle, true); // Make sure we use the initial title set by the user // Trigger a "fake" title changed event, so the title is set on the taskbar thumbnail. // Empty/null title will be ignored. ThumbnailPreview_TitleChanged(preview, EventArgs.Empty); ThumbnailPreview_TooltipChanged(preview, EventArgs.Empty); // Indicate to the preview that we've added it on the taskbar preview.AddedToTaskbar = true; }
private static bool DispatchLivePreviewBitmapMessage(ref System.Windows.Forms.Message m, TaskbarWindow taskbarWindow) { if (m.Msg == (int)WindowMessage.DWMSendIconicLivePreviewBitmap) { // Try to get the width/height int width = (int)(((long)m.LParam) >> 16); int height = (int)(((long)m.LParam) & (0xFFFF)); // Default size for the thumbnail var realWindowSize = new System.Drawing.Size(200, 200); if (taskbarWindow.TabbedThumbnail.WindowHandle != IntPtr.Zero) _ = HandlerNativeMethods.GetClientSize(taskbarWindow.TabbedThumbnail.WindowHandle, out realWindowSize); else if (taskbarWindow.TabbedThumbnail.WindowsControl != null) realWindowSize = new System.Drawing.Size( Convert.ToInt32(taskbarWindow.TabbedThumbnail.WindowsControl.RenderSize.Width), Convert.ToInt32(taskbarWindow.TabbedThumbnail.WindowsControl.RenderSize.Height)); // If we don't have a valid height/width, use the original window's size if (width <= 0) width = realWindowSize.Width; if (height <= 0) height = realWindowSize.Height; // Fire an event to let the user update their bitmap // Raise the event taskbarWindow.TabbedThumbnail.OnTabbedThumbnailBitmapRequested(); // capture the bitmap for the given control // If the user has already specified us a bitmap to use, use that. IntPtr hBitmap = taskbarWindow.TabbedThumbnail.CurrentHBitmap == IntPtr.Zero ? GrabBitmap(taskbarWindow, realWindowSize) : taskbarWindow.TabbedThumbnail.CurrentHBitmap; // If we have a valid parent window handle, // calculate the offset so we can place the "peek" bitmap // correctly on the app window if (taskbarWindow.TabbedThumbnail.ParentWindowHandle != IntPtr.Zero && taskbarWindow.TabbedThumbnail.WindowHandle != IntPtr.Zero) { // if we don't have a offset specified already by the user... Point offset = !taskbarWindow.TabbedThumbnail.PeekOffset.HasValue ? Shell.DesktopWindowManager.GetParentOffsetOfChild(taskbarWindow.TabbedThumbnail.WindowHandle, taskbarWindow.TabbedThumbnail.ParentWindowHandle) : new Point(Convert.ToInt32(taskbarWindow.TabbedThumbnail.PeekOffset.Value.X), Convert.ToInt32(taskbarWindow.TabbedThumbnail.PeekOffset.Value.Y)); // Only set the peek bitmap if it's not null. // If it's null (either we didn't get the bitmap or size was 0), // let DWM handle it if (hBitmap != IntPtr.Zero && offset.X >= 0 && offset.Y >= 0) DesktopWindowManager.SetPeekBitmap( taskbarWindow.WindowToTellTaskbarAbout, hBitmap, offset, taskbarWindow.TabbedThumbnail.DisplayFrameAroundBitmap); // If the bitmap we have is not coming from the user (i.e. we created it here), // then make sure we delete it as we don't need it now. if (taskbarWindow.TabbedThumbnail.CurrentHBitmap == IntPtr.Zero) _ = GDI.DeleteObject(hBitmap); return true; } // Else, we don't have a valid window handle from the user. This is mostly likely because // we have a WPF UIElement control. If that's the case, use a different screen capture method // and also couple of ways to try to calculate the control's offset w.r.t it's parent. else if (taskbarWindow.TabbedThumbnail.ParentWindowHandle != IntPtr.Zero && taskbarWindow.TabbedThumbnail.WindowsControl != null) { System.Windows.Point offset; if (!taskbarWindow.TabbedThumbnail.PeekOffset.HasValue) { // Calculate the offset for a WPF UIElement control // For hidden controls, we can't seem to perform the transform. GeneralTransform objGeneralTransform = taskbarWindow.TabbedThumbnail.WindowsControl.TransformToVisual(taskbarWindow.TabbedThumbnail.WindowsControlParentWindow); offset = objGeneralTransform.Transform(new System.Windows.Point(0, 0)); } else offset = new System.Windows.Point(taskbarWindow.TabbedThumbnail.PeekOffset.Value.X, taskbarWindow.TabbedThumbnail.PeekOffset.Value.Y); // Only set the peek bitmap if it's not null. // If it's null (either we didn't get the bitmap or size was 0), // let DWM handle it if (hBitmap != IntPtr.Zero) if (offset.X >= 0 && offset.Y >= 0) DesktopWindowManager.SetPeekBitmap( taskbarWindow.WindowToTellTaskbarAbout, hBitmap, new Point((int)offset.X, (int)offset.Y), taskbarWindow.TabbedThumbnail.DisplayFrameAroundBitmap); else DesktopWindowManager.SetPeekBitmap( taskbarWindow.WindowToTellTaskbarAbout, hBitmap, taskbarWindow.TabbedThumbnail.DisplayFrameAroundBitmap); // If the bitmap we have is not coming from the user (i.e. we created it here), // then make sure we delete it as we don't need it now. if (taskbarWindow.TabbedThumbnail.CurrentHBitmap == IntPtr.Zero) _ = GDI.DeleteObject(hBitmap); return true; } else { // Else (no parent specified), just set the bitmap. It would take over the entire // application window (would work only if you are a MDI app) // Only set the peek bitmap if it's not null. // If it's null (either we didn't get the bitmap or size was 0), // let DWM handle it if (hBitmap != null) DesktopWindowManager.SetPeekBitmap(taskbarWindow.WindowToTellTaskbarAbout, hBitmap, taskbarWindow.TabbedThumbnail.DisplayFrameAroundBitmap); // If the bitmap we have is not coming from the user (i.e. we created it here), // then make sure we delete it as we don't need it now. if (taskbarWindow.TabbedThumbnail.CurrentHBitmap == IntPtr.Zero) _ = GDI.DeleteObject(hBitmap); return true; } } return false; }
private static bool DispatchSendIconThumbnailMessage(ref System.Windows.Forms.Message m, TaskbarWindow taskbarWindow) { if (m.Msg == (int)WindowMessage.DWMSendIconicThumbnail) { int width = (int)((long)m.LParam >> 16); int height = (int)(((long)m.LParam) & (0xFFFF)); var requestedSize = new System.Drawing.Size(width, height); // Fire an event to let the user update their bitmap taskbarWindow.TabbedThumbnail.OnTabbedThumbnailBitmapRequested(); IntPtr hBitmap; // Default size for the thumbnail var realWindowSize = new System.Drawing.Size(200, 200); // Get the size of teh control or UIElement if (taskbarWindow.TabbedThumbnail.WindowHandle != IntPtr.Zero) _ = HandlerNativeMethods.GetClientSize(taskbarWindow.TabbedThumbnail.WindowHandle, out realWindowSize); else if (taskbarWindow.TabbedThumbnail.WindowsControl != null) realWindowSize = new System.Drawing.Size( Convert.ToInt32(taskbarWindow.TabbedThumbnail.WindowsControl.RenderSize.Width), Convert.ToInt32(taskbarWindow.TabbedThumbnail.WindowsControl.RenderSize.Height)); if (realWindowSize.Height == -1 && realWindowSize.Width == -1) realWindowSize.Width = realWindowSize.Height = 199; // capture the bitmap for the given control // If the user has already specified us a bitmap to use, use that. if (taskbarWindow.TabbedThumbnail.ClippingRectangle != null && taskbarWindow.TabbedThumbnail.ClippingRectangle.Value != Rectangle.Empty) { hBitmap = taskbarWindow.TabbedThumbnail.CurrentHBitmap == IntPtr.Zero ? GrabBitmap(taskbarWindow, realWindowSize) : taskbarWindow.TabbedThumbnail.CurrentHBitmap; // Clip the bitmap we just got. Bitmap bmp = Image.FromHbitmap(hBitmap); Rectangle clippingRectangle = taskbarWindow.TabbedThumbnail.ClippingRectangle.Value; // If our clipping rect is out of bounds, update it if (clippingRectangle.Height > requestedSize.Height) clippingRectangle.Height = requestedSize.Height; if (clippingRectangle.Width > requestedSize.Width) clippingRectangle.Width = requestedSize.Width; // NOTE: Is this a memory leak? bmp = bmp.Clone(clippingRectangle, bmp.PixelFormat); // Make sure we dispose the bitmap before assigning, otherwise we'll have a memory leak if (hBitmap != IntPtr.Zero && taskbarWindow.TabbedThumbnail.CurrentHBitmap == IntPtr.Zero) _ = GDI.DeleteObject(hBitmap); hBitmap = bmp.GetHbitmap(); bmp.Dispose(); } else { // Else, user didn't want any clipping, if they haven't provided us a bitmap, // use the screencapture utility and capture it. hBitmap = taskbarWindow.TabbedThumbnail.CurrentHBitmap; // If no bitmap, capture one using the utility if (hBitmap == IntPtr.Zero) hBitmap = GrabBitmap(taskbarWindow, realWindowSize); } // Only set the thumbnail if it's not null. // If it's null (either we didn't get the bitmap or size was 0), // let DWM handle it if (hBitmap != IntPtr.Zero) { Bitmap temp = TabbedThumbnailScreenCapture.ResizeImageWithAspect( hBitmap, requestedSize.Width, requestedSize.Height, true); if (taskbarWindow.TabbedThumbnail.CurrentHBitmap == IntPtr.Zero) _ = GDI.DeleteObject(hBitmap); hBitmap = temp.GetHbitmap(); DesktopWindowManager.SetIconicThumbnail(taskbarWindow.WindowToTellTaskbarAbout, hBitmap); temp.Dispose(); } // If the bitmap we have is not coming from the user (i.e. we created it here), // then make sure we delete it as we don't need it now. if (taskbarWindow.TabbedThumbnail.CurrentHBitmap == IntPtr.Zero) _ = GDI.DeleteObject(hBitmap); return true; } return false; }