WPF自定义任务栏缩略图

任务栏缩略图预览

在Windows7系统上,微软首次推出任务栏缩略图预览功能。

当鼠标划会任务栏上的程序时,会打开一个预览窗口,可以对整个窗口内容进行预览。

效果如下:

在后面的Windows 8/8.1/10/11系统上,都延续了这个功能。

但是这种预览是基于窗口本身内容的,如果我们想修改这个缩略图的内容,类似网易云这样,就需要一些技术手段。

可以借助dwm里的几个函数来实现。

用到的DWM函数

DwmSetWindowAttribute

设置窗口管理器(DWM)非客户端呈现属性的值

函数声明如下:

复制代码
1 HRESULT DwmSetWindowAttribute(
2   [in] HWND    hwnd,
3   [in] DWORD   dwAttribute,
4   [in] LPCVOID pvAttribute,
5   [in] DWORD   cbAttribute
6 );

参数说明:

hwnd :要为其设置属性值的窗口的句柄。

dwAttribute:描述要设置的值的标志,指定为 DWMWINDOWATTRIBUTE 枚举的值。 此参数指定要设置的属性,pvAttribute 参数指向包含属性值的对象。

pvAttribute:指向包含要设置的属性值的对象的指针。 值集的类型取决于 dwAttribute 参数的值。 DWMWINDOWATTRIBUTE 枚举主题指示,在每个标志的行中,应向 pvAttribute 参数传递指向的值类型。

cbAttribute:通过 pvAttribute 参数设置的属性值的大小(以字节为单位)。 值集的类型及其大小(以字节为单位)取决于 dwAttribute 参数的值。

DwmSetIconicThumbnail

设置窗口或选项卡上要用作缩略图表示形式的静态图标位图。

函数声明如下:

复制代码
1 HRESULT DwmSetIconicThumbnail(
2   [in] HWND    hwnd,
3   [in] HBITMAP hbmp,
4   [in] DWORD   dwSITFlags
5 );

参数说明:

hwnd:窗口或选项卡的句柄。此窗口必须属于调用进程。

hbmp:位图的句柄,用于表示 hwnd 指定的窗口。

dwSITFlags:缩略图的显示选项。 以下值之一:

|---------------------------------|-----------------|
| 值 | 说明 |
| 0 (0x00000000) | 提供的缩略图周围不显示任何框架 |
| DWM_SIT_DISPLAYFRAME 0x00000001 | 在提供的缩略图周围显示一个框架 |

在WPF中自定义任务缩略图的步骤

1、在Window.Loaded事件中调用DwmSetWindowAttribute设置相关属性

2、增加一个Windows消息的处理函数

3、当收到WM_DWMSENDICONICTHUMBNAIL(0x0323)消息时,调用DwmSetIconicThumbnail设置缩略图。

注意:缩略图不应超过该消息中指定的最大 x 坐标(宽度)和 y 坐标(高度)。 缩略图还必须具有 32 位颜色深度。

缩略图的大小可以通过消息的lParam参数解析。

lParam的高16位是宽度,低16位是高度。

解析方法如下:

复制代码
1  private short HIWORD(IntPtr lParam)
2  {
3      return (short)(((ulong)lParam >> 16) & 0xFFFF);
4  }
5 
6  private short LOWORD(IntPtr lParam)
7  {
8      return (short)((ulong)lParam & 0xFFFF);
9  }
复制代码
1 var width = HIWORD(lParam);
2 var height = LOWORD(lParam);

引入签名

新建一个WPF工程,创建一个DWM.cs,内容如下:

复制代码
 1     public class DWM
 2     {
 3         public const int WM_DWMSENDICONICTHUMBNAIL = 0x0323;
 4         public const int FORCE_ICONIC_REPRESENTATION = 7;
 5         public const int HAS_ICONIC_BITMAP = 10;
 6         public const int DISPLAYFRAME = 1;
 7 
 8         [DllImport("dwmapi.dll")]
 9         public static extern int DwmSetIconicThumbnail(IntPtr hwnd, IntPtr hbmp, int dwSITFlags);
10 
11         [DllImport("dwmapi.dll")]
12         public static extern int DwmSetWindowAttribute(IntPtr hwnd, int dwAttribute, IntPtr pvAttribute, int cbAttribute);
13     }

设置DWM属性并增加窗口的消息处理函数

为主窗口增加一个Loaded事件,在Loaded事件中,增加如下代码:

复制代码
 1         private void Window_Loaded(object sender, RoutedEventArgs e)
 2         {
 3             int size = Marshal.SizeOf(typeof(Int32));
 4             IntPtr pBool = Marshal.AllocHGlobal(size);
 5             Marshal.WriteInt32(pBool, 0, 1);  // last parameter 0 (FALSE), 1 (TRUE)
 6 
 7             //设置属性
 8             var result = DWM.DwmSetWindowAttribute(new WindowInteropHelper(this).Handle, DWM.FORCE_ICONIC_REPRESENTATION, pBool, sizeof(int));
 9             result = DWM.DwmSetWindowAttribute(new WindowInteropHelper(this).Handle, DWM.HAS_ICONIC_BITMAP, pBool, sizeof(int));
10 
11             Marshal.FreeHGlobal(pBool);
12 
13             //Windows消息处理函数
14             HwndSource.FromHwnd(new WindowInteropHelper(this).Handle).AddHook(WndProc);
15         }

设置缩略图

复制代码
 1      private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
 2      {
 3          switch (msg)
 4          {
 5              case DWM.WM_DWMSENDICONICTHUMBNAIL:
 6                  var bmp = (Bitmap)Bitmap.FromFile(@"xxx.bmp");
 7                  var hBitmap = bmp.GetHbitmap();
 8                  DWM.DwmSetIconicThumbnail(hwnd, hBitmap, DWM.DISPLAYFRAME);
 9                  handled = true;
10                  break;
11          }
12          return IntPtr.Zero;
13      }

效果如下:

也可以自行绘制

复制代码
 1         private IntPtr CreateBitmap(int width,int height)
 2         {
 3             Bitmap bitmap = new Bitmap(width, height);
 4             using (Graphics g = Graphics.FromImage(bitmap))
 5             {
 6                 g.DrawString("HelloWorld", new Font("Arial",13), System.Drawing.Brushes.Red, 20, 20);
 7             }
 8 
 9             return bitmap.GetHbitmap();
10         }

运行效果如下:

示例代码

下载

参考资料

DWM 缩略图概述 - Win32 apps | Microsoft Learn

相关推荐
hao_wujing2 小时前
分布式 L2 网关下的 OVS 未知单播泛洪
分布式·wpf
Crazy Struggle6 小时前
C#+ WPF 实现蓝牙转WIFI计步上位机
c#·wpf·上位机软件
CV大法好10 小时前
WPF通过反射机制动态加载控件
visualstudio·c#·wpf
麻花20131 天前
WPF的下拉复选框多选,数据来源数据库的表
java·前端·wpf
军训猫猫头1 天前
32.失焦提示 C#例子 WPF例子
ui·c#·wpf
麻花20131 天前
WPF的一些控件的触发事件记录
wpf
one9962 天前
WPF-绑定
microsoft·c#·.net·wpf
one9962 天前
WPF 数据绑定中的通知机制及其性能考虑
c#·.net·wpf
weixin_464078073 天前
WPF使用ContentControl控件实现区域导航,并使用Prism依赖注入优化
wpf