C#- 调用DWMAPI绘制缩略图到winform窗口 (多窗口图像捕获)
此文章演示C#如何使用DwmApi来捕获程序的缩略图来映射到winform窗体上。
实现:
1.可随意捕获多个程序的缩略图。
2.并可设置缩略图的大小尺寸。
3.零延迟实时捕获缩略图。
注意点:
使用此接口捕获应用程序的缩略图时,必须保证要捕获的应用程序在任务栏上出现。 (缩小到后台没任务栏的程序是没办法捕获的)。
一、使用VisualStudio创建一个winform项目
二、定义DwmApi接口:
1 public class DwmApi 2 { 3 /// <summary> 4 /// 在目标窗口和源窗口之间创建桌面窗口管理器(DWM)缩略图关系 返回0为成功 5 /// </summary> 6 /// <param name="hwndDestination">将使用 DWM 缩略图的窗口句柄。将目标窗口句柄设置为顶级窗口类型以外的任何内容都将导致返回值 E_INVALIDARG。</param> 7 /// <param name="hwndSource">用作缩略图源的窗口句柄。将源窗口句柄设置为顶级窗口类型以外的任何内容都将导致返回值 E_INVALIDARG。</param> 8 /// <param name="phThumbnailId">指向句柄的指针,当此函数成功返回时,表示 DWM 缩略图的注册。</param> 9 /// <returns></returns> 10 [DllImport("Dwmapi.dll")] 11 public static extern int DwmRegisterThumbnail(IntPtr hwndDestination, IntPtr hwndSource, out IntPtr phThumbnailId); 12 13 /// <summary> 14 /// 更新桌面窗口管理器 (DWM) 缩略图的属性。 15 /// </summary> 16 /// <param name="hThumbnailId">要更新的 DWM 缩略图的句柄。空或无效的缩略图以及其他进程拥有的缩略图将导致返回值 E_INVALIDARG。</param> 17 /// <param name="ptnProperties">指向包含新缩略图属性的DWM_THUMBNAIL_PROPERTIES结构的指针</param> 18 /// <returns></returns> 19 [DllImport("Dwmapi.dll")] 20 public static extern int DwmUpdateThumbnailProperties(IntPtr hThumbnailId, DWM_THUMBNAIL_PROPERTIES ptnProperties); // 返回0为成功 21 22 /// <summary> 23 /// 检索桌面窗口管理器 (DWM) 缩略图的源大小。 24 /// </summary> 25 /// <param name="hThumbnailId">要更新的 DWM 缩略图的句柄。</param> 26 /// <param name="pSize">输出大小</param> 27 /// <returns></returns> 28 [DllImport("Dwmapi.dll")] 29 public static extern int DwmQueryThumbnailSourceSize(IntPtr hThumbnailId, out PSIZE pSize); 30 31 /// <summary> 32 /// 删除由创建的桌面窗口管理器(DWM)缩略图关系DwmRegisterThumbnail功能 33 /// </summary> 34 /// <param name="hThumbnailId"></param> 35 /// <returns></returns> 36 [DllImport("Dwmapi.dll")] 37 public static extern int DwmUnregisterThumbnail(IntPtr hThumbnailId); // 返回0为成功 38 39 40 [DllImport("user32.dll")] 41 public static extern bool GetClientRect(IntPtr hwnd, ref RECT lpRect); 42 43 44 45 [DllImport("user32.dll", SetLastError = true)] 46 public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); //获取窗口句柄 47 48 [DllImport("user32.dll", SetLastError = true)] 49 public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow); //获取子窗体句柄 50 }
三、定义结构体
1 /// <summary> 2 /// rect 3 /// </summary> 4 [StructLayout(LayoutKind.Sequential)] 5 public struct RECT 6 { 7 public int Left; //左边开始绘制位置 8 public int Top; //上面开始绘制位置 9 public int Right; //右边截止绘制位置 10 public int Bottom; //下边截止绘制位置 11 } 12 13 /// <summary> 14 /// 缩略图的尺寸 15 /// </summary> 16 [StructLayout(LayoutKind.Sequential)] 17 public struct PSIZE 18 { 19 /// <summary> 20 /// 缩略图的宽度 21 /// </summary> 22 public int x; 23 24 /// <summary> 25 /// 缩略图的高度 26 /// </summary> 27 public int y; 28 } 29 30 /// <summary> 31 /// 参阅 官方文档 https://docs.microsoft.com/en-us/windows/win32/api/dwmapi/ns-dwmapi-dwm_thumbnail_properties 32 /// </summary> 33 [StructLayout(LayoutKind.Sequential)] 34 public class DWM_THUMBNAIL_PROPERTIES 35 { 36 /// <summary> 37 /// DWM 缩略图常量值的按位组合,指示设置了此结构的哪些成员。 官方说明:https://docs.microsoft.com/en-us/windows/win32/dwm/dwm-tnp-constants 38 /// </summary> 39 public int dwFlags { get; set; } 40 41 /// <summary> 42 /// 目标窗口中将呈现缩略图的区域。 43 /// </summary> 44 public RECT rcDestination { get; set; } 45 46 /// <summary> 47 /// 用作缩略图的源窗口区域。默认情况下,整个窗口用作缩略图。 48 /// </summary> 49 public RECT rcSource { get; set; } 50 51 /// <summary> 52 /// 渲染缩略图的不透明度。0 是完全透明的,而 255 是完全不透明的。默认值为 255。 53 /// </summary> 54 public int opacity { get; set; } 55 56 /// <summary> 57 /// TRUE使缩略图可见;否则,FALSE。默认值为FALSE。 58 /// </summary> 59 public bool fVisible { get; set; } 60 61 /// <summary> 62 /// TRUE仅使用缩略图源的客户区;否则,FALSE。默认值为FALSE。 63 /// </summary> 64 public bool fSourceClientAreaOnly { get; set; } 65 }
四、封装一个捕获映射缩略图的方法
1 /// <summary> 2 /// 映射窗口 3 /// </summary> 4 /// <param name="targetHwnd">要映射到的目标窗口句柄</param> 5 /// <param name="sourceHwnd">被映射的源窗口句柄</param> 6 /// <param name="DrawPosition">绘制位置</param> 7 public void MappingWindow(IntPtr targetHwnd, IntPtr sourceHwnd, RECT DrawPosition, out IntPtr thumbnail) 8 { 9 10 11 int DWM_TNP_RECTDESTINATION = 0x00000001; 12 13 int DWM_TNP_VISIBLE = 0x00000008; 14 15 int DWM_TNP_SOURCECLIENTAREAONLY = 0x00000010; 16 17 DWM_THUMBNAIL_PROPERTIES dskThumbProps = new DWM_THUMBNAIL_PROPERTIES(); 18 19 if (DwmApi.DwmRegisterThumbnail(targetHwnd, sourceHwnd, out thumbnail) == 0) //返回0为成功 20 { 21 dskThumbProps.dwFlags = DWM_TNP_RECTDESTINATION; 22 dskThumbProps.rcDestination = DrawPosition; 23 //dskThumbProps.fSourceClientAreaOnly = false; 24 //dskThumbProps.fVisible = true; 25 //dskThumbProps.opacity = (255 * 70) / 100; 26 27 28 /* 29 * 保持缩略图原大小 取消以下代码 30 * 31 PSIZE size = new PSIZE(); 32 DwmApi.DwmQueryThumbnailSourceSize(thumbnail,out size); //获取缩略图原大小 33 34 RECT rectNew = new RECT(); //保持原大小 35 rectNew.Right = size.x; 36 rectNew.Bottom = size.y; 37 dskThumbProps.rcDestination = rectNew; 38 39 */ 40 41 42 int result = DwmApi.DwmUpdateThumbnailProperties(thumbnail, dskThumbProps); 43 44 } 45 else 46 { 47 MessageBox.Show("未获取到缩略图,该程序不在任务栏或为后台应用"); 48 } 49 }
五、窗口拖两个panel控件用于定位捕获的缩略图位置
六、实现调用
1 try 2 { 3 //*********************捕获微信缩略图示例************************** 4 5 // 获取要捕获缩略图的窗口句柄 6 7 // 第一种方式 通过进程来获取句柄 8 var process = Process.GetProcessesByName("WeChat")[0]; 9 IntPtr window = process.MainWindowHandle; 10 11 // 第二种方式 通过winApi来获取 12 IntPtr window2 = DwmApi.FindWindow("WeChatMainWndForPC", null); 13 14 RECT rect = new RECT(); 15 //bool re = DwmApi.GetClientRect(this.Handle, ref rect); 16 17 rect.Top = this.panel_app1.Top; 18 rect.Left = this.panel_app1.Left; 19 rect.Right = this.panel_app1.Right; //缩略图宽度 20 rect.Bottom = this.panel_app1.Bottom; //缩略图高度 21 22 MappingWindow(this.Handle, window, rect,out thumbnailApp1); 23 24 25 //*************************捕获记事本******************************** 26 27 var process2 = Process.GetProcessesByName("notepad")[0]; 28 IntPtr notepad = process2.MainWindowHandle; 29 30 rect.Top = this.panel_app2.Top; 31 rect.Left = this.panel_app2.Left; 32 rect.Right = this.panel_app2.Right; //缩略图宽度 33 rect.Bottom = this.panel_app2.Bottom; //缩略图高度 34 35 MappingWindow(this.Handle, notepad, rect, out thumbnailApp2); 36 37 } 38 catch (Exception ex) 39 { 40 MessageBox.Show(ex.Message); 41 }
ps:此时已经则实时捕获到微信和记事本的缩略图到winform上了 效果如下:
实时动态变化的,零延迟。
附上Fomr1.cs 完整代码
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Diagnostics; 6 using System.Drawing; 7 using System.Linq; 8 using System.Text; 9 using System.Threading.Tasks; 10 using System.Windows.Forms; 11 12 namespace CaptureThumbnailsDemo 13 { 14 public partial class Form1 : Form 15 { 16 public Form1() 17 { 18 InitializeComponent(); 19 } 20 21 IntPtr thumbnailApp1; //DWM 缩略图的句柄 1 22 IntPtr thumbnailApp2; //DWM 缩略图的句柄 2 23 24 private void Form1_Load(object sender, EventArgs e) 25 { 26 27 try 28 { 29 //*********************捕获微信缩略图示例************************** 30 31 // 获取要捕获缩略图的窗口句柄 32 33 // 第一种方式 通过进程来获取句柄 34 var process = Process.GetProcessesByName("WeChat")[0]; 35 IntPtr window = process.MainWindowHandle; 36 37 // 第二种方式 通过winApi来获取 38 IntPtr window2 = DwmApi.FindWindow("WeChatMainWndForPC", null); 39 40 RECT rect = new RECT(); 41 //bool re = DwmApi.GetClientRect(this.Handle, ref rect); 42 43 rect.Top = this.panel_app1.Top; 44 rect.Left = this.panel_app1.Left; 45 rect.Right = this.panel_app1.Right; //缩略图宽度 46 rect.Bottom = this.panel_app1.Bottom; //缩略图高度 47 48 MappingWindow(this.Handle, window, rect,out thumbnailApp1); 49 50 51 //*************************捕获记事本******************************** 52 53 var process2 = Process.GetProcessesByName("notepad")[0]; 54 IntPtr notepad = process2.MainWindowHandle; 55 56 rect.Top = this.panel_app2.Top; 57 rect.Left = this.panel_app2.Left; 58 rect.Right = this.panel_app2.Right; //缩略图宽度 59 rect.Bottom = this.panel_app2.Bottom; //缩略图高度 60 61 MappingWindow(this.Handle, notepad, rect, out thumbnailApp2); 62 63 } 64 catch (Exception ex) 65 { 66 MessageBox.Show(ex.Message); 67 } 68 69 70 71 } 72 73 /// <summary> 74 /// 映射窗口 75 /// </summary> 76 /// <param name="targetHwnd">要映射到的目标窗口句柄</param> 77 /// <param name="sourceHwnd">被映射的源窗口句柄</param> 78 /// <param name="DrawPosition">绘制位置</param> 79 public void MappingWindow(IntPtr targetHwnd, IntPtr sourceHwnd, RECT DrawPosition, out IntPtr thumbnail) 80 { 81 82 83 int DWM_TNP_RECTDESTINATION = 0x00000001; 84 85 int DWM_TNP_VISIBLE = 0x00000008; 86 87 int DWM_TNP_SOURCECLIENTAREAONLY = 0x00000010; 88 89 DWM_THUMBNAIL_PROPERTIES dskThumbProps = new DWM_THUMBNAIL_PROPERTIES(); 90 91 if (DwmApi.DwmRegisterThumbnail(targetHwnd, sourceHwnd, out thumbnail) == 0) //返回0为成功 92 { 93 dskThumbProps.dwFlags = DWM_TNP_RECTDESTINATION; 94 dskThumbProps.rcDestination = DrawPosition; 95 //dskThumbProps.fSourceClientAreaOnly = false; 96 //dskThumbProps.fVisible = true; 97 //dskThumbProps.opacity = (255 * 70) / 100; 98 99 100 /* 101 * 保持缩略图原大小 取消以下代码 102 * 103 PSIZE size = new PSIZE(); 104 DwmApi.DwmQueryThumbnailSourceSize(thumbnail,out size); //获取缩略图原大小 105 106 RECT rectNew = new RECT(); //保持原大小 107 rectNew.Right = size.x; 108 rectNew.Bottom = size.y; 109 dskThumbProps.rcDestination = rectNew; 110 111 */ 112 113 114 int result = DwmApi.DwmUpdateThumbnailProperties(thumbnail, dskThumbProps); 115 116 } 117 else 118 { 119 MessageBox.Show("未获取到缩略图,该程序不在任务栏或为后台应用"); 120 } 121 } 122 123 /// <summary> 124 /// 注销微信缩略图 125 /// </summary> 126 /// <param name="sender"></param> 127 /// <param name="e"></param> 128 private void btn_UThumbnail_Click(object sender, EventArgs e) 129 { 130 if (thumbnailApp1 != IntPtr.Zero) 131 { 132 if (DwmApi.DwmUnregisterThumbnail(thumbnailApp1) == 0) 133 { 134 MessageBox.Show("已注销缩略图"); 135 } 136 else 137 { 138 MessageBox.Show("操作失败"); 139 } 140 } 141 } 142 143 private void Form1_FormClosing(object sender, FormClosingEventArgs e) 144 { 145 if (thumbnailApp1 != IntPtr.Zero) 146 { 147 DwmApi.DwmUnregisterThumbnail(thumbnailApp1); 148 } 149 if (thumbnailApp2 != IntPtr.Zero) 150 { 151 DwmApi.DwmUnregisterThumbnail(thumbnailApp2); 152 } 153 } 154 155 private void btn_UThumbnailApp2_Click(object sender, EventArgs e) 156 { 157 if (thumbnailApp2 != IntPtr.Zero) 158 { 159 if (DwmApi.DwmUnregisterThumbnail(thumbnailApp2) == 0) 160 { 161 MessageBox.Show("已注销缩略图"); 162 } 163 else 164 { 165 MessageBox.Show("操作失败"); 166 } 167 } 168 } 169 } 170 }
完整demo下载地址:
https://wwb.lanzouj.com/iEDgB02whkda
密码:1k4f