任务栏缩略图预览
在Windows7系统上,微软首次推出任务栏缩略图预览功能。
当鼠标划会任务栏上的程序时,会打开一个预览窗口,可以对整个窗口内容进行预览。
效果如下:
在后面的Windows 8/8.1/10/11系统上,都延续了这个功能。
但是这种预览是基于窗口本身内容的,如果我们想修改这个缩略图的内容,类似网易云这样,就需要一些技术手段。
可以借助dwm里的几个函数来实现。
用到的DWM函数
设置窗口管理器(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 参数的值。
设置窗口或选项卡上要用作缩略图表示形式的静态图标位图。
函数声明如下:
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 }
运行效果如下: