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 }
Form1

 

完整demo下载地址:

https://wwb.lanzouj.com/iEDgB02whkda
密码:1k4f

 

posted @ 2022-04-09 17:53  阿东呢  阅读(1814)  评论(0编辑  收藏  举报