此文章演示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