使用DWM(DesktopWindowManage)在WPF程序中绘制缩略图
2023年7月19日发(作者:)
使⽤DWM(DesktopWindowManage)在WPF程序中绘制缩略图DWM是在Windows Vista后出现的操作系统窗⼝渲染程序,在中⽂化的系统中被描述为“桌⾯窗⼝管理器”,该进程随着系统⼀起启动,同时提供⼀些Api给其他程序进⾏调⽤。这⾥展⽰其中的⼀个功能——由窗⼝向DWM订阅其他窗⼝的缩略图,并由DWM绘制到请求的窗⼝上。这⼀过程将使⽤以下四个API/// /// 向DWM管理器订阅某窗⼝的缩略图 /// /// 显⽰缩略图的窗⼝句柄 /// 被显⽰缩略图的窗⼝句柄 /// 当获取成功时,缩略图的句柄 /// 当函数执⾏成功时,返回S_OK,否则,返回HRESULT错误代码 [DllImport("")] public static extern int DwmRegisterThumbnail(IntPtr dest, IntPtr src, out IntPtr thumb); /// /// 向DWM退订某个缩略图 /// /// 需要退订的缩略图的句柄,null或不存在的句柄将会返回E_INVALIDARG /// 当函数执⾏成功时,返回S_OK,否则,返回HRESULT错误代码 [DllImport("")] public static extern int DwmUnregisterThumbnail(IntPtr thumb); /// /// 查询DWM提供的缩略图的⼤⼩ /// /// 需要查询的缩略图的句柄 /// 当函数执⾏成功时,返回带有缩略图Size信息的PSIZE结构体 /// 当函数执⾏成功时,返回S_OK,否则,返回HRESULT错误代码 [DllImport("")] public static extern int DwmQueryThumbnailSourceSize(IntPtr thumb, out PSIZE size); /// /// 更新DWM的相关属性 /// /// 要更新的缩略图句柄,当这个句柄被其他线程持有时,将会返回E_INVALIDARG。 /// 指向DWM_THUMBNAIL_PROPERTIES结构体的指针,带有更新后的缩略图属性 /// 当函数执⾏成功时,返回S_OK,否则,返回HRESULT错误代码。 [DllImport("")] public static extern int DwmUpdateThumbnailProperties(IntPtr hThumb, ref DWM_THUMBNAIL_PROPERTIES props);过程中可能会⽤到的常量和结构体定义如下 #region 常量定义 public static readonly int GWL_STYLE = -16; public static readonly int DWM_TNP_VISIBLE = 0x8; public static readonly int DWM_TNP_OPACITY = 0x4; public static readonly int DWM_TNP_RECTDESTINATION = 0x1; public static readonly ulong WS_VISIBLE = 0x10000000L; public static readonly ulong WS_BORDER = 0x00800000L; public static readonly ulong WS_CAPTION = 0x00C00000L; public static readonly ulong WS_CHILDWINDOW = 0x40000000L; public static readonly ulong TARGETWINDOW = WS_BORDER | WS_VISIBLE; #endregion #region 结构体定义 /// /// 缩略图的尺⼨ /// [StructLayout(tial)] public struct PSIZE { /// /// 缩略图的宽度 /// public int x; /// /// 缩略图的⾼度 /// public int y; } /// /// 缩略图属性 /// [StructLayout(tial)] public struct DWM_THUMBNAIL_PROPERTIES { /// /// 标志位常量组,表⽰结构体中哪些成员被设置 /// public int dwFlags; /// /// ⽬标窗⼝中将被⽤于显⽰缩略图的区域 /// public Rect rcDestination; /// /// 要显⽰出缩略图的源窗⼝区域,默认情况下将会使⽤全部区域作为缩略图 /// public Rect rcSource; /// /// 缩略图的不透明度,取值范围为0-255,默认值为255 /// public byte opacity; /// /// 缩略图可见性,当该值为true时,缩略图可见。默认值为false /// public bool fVisible; /// /// 当该值为true时,仅使⽤缩略图来源的客户区,默认值为false /// public bool fSourceClientAreaOnly; } /// /// 显⽰应⽤缩略图的位置 /// [StructLayout(tial)] public struct Rect { public Rect(int left, int top, int right, int bottom) public Rect(int left, int top, int right, int bottom) { Left = left; Top = top; Right = right; Bottom = bottom; } public Rect(double left, double top, double right, double bottom) { Left = (int)left; Top = (int)top; Right = (int)right; Bottom = (int)bottom; } public int Left; public int Top; public int Right; public int Bottom; }需要的win32Api如下 /// /// 检索给定句柄的窗⼝的相关信息 /// /// 窗⼝的句柄,以及窗⼝所属的类的句柄。 /// /// 需要检索的值对0的偏移常量。有效值的范围是0到额外的窗⼝内存字节数减4。 /// 例如,如果指定了12个或更多字节的额外内存,则值8将是第三个32位整数的索引 /// /// 如果函数成功,则返回所请求的值。否则,返回0 /// [DllImport("")] public static extern ulong GetWindowLongA(IntPtr hWnd, int nIndex); /// /// /// /// 指向应⽤程序定义的回调函数 /// 参见 /// /// 要传递给回调函数的应⽤程序定义的值 /// 如果函数执⾏成功,返回⾮0值,否则,返回0 /// [DllImport("")] public static extern int EnumWindows(EnumWindowsCallback lpEnumFunc, int lParam); [DllImport("")] public static extern int EnumChildWindows(IntPtr hwnd, EnumWindowsCallback lpEnumFunc, int lParam); /// /// 提供回调函数的委托 /// /// 窗⼝句柄 /// 传⼊的⾃定义值 /// 继续进⾏枚举时,返回true,否则返回false public delegate bool EnumWindowsCallback(IntPtr hwnd, int lParam); /// /// /// 包含⽂本的窗⼝或控件的句柄 /// 通过将句柄传递给每个窗⼝,依次传递给应⽤程序定义的回调函数,枚举屏幕上的所有顶级窗⼝。枚举窗⼝⼀直持续到最后⼀个顶级窗⼝被枚举或回调函数返回 /// 将指定窗⼝标题栏的⽂本(如果有的话)复制到缓冲区中。如果指定的窗⼝是控件,则复制该控件的⽂本。但是,GetWindowText不能在另⼀个应⽤程序中检索控 /// 包含⽂本的窗⼝或控件的句柄 /// 将接收⽂本的缓冲区。如果字符串与缓冲区⼀样长或更长,则该字符串将被截断并以空字符结束 /// 要复制到缓冲区的最⼤字符数,包括空字符。如果⽂本超过这个限制,就会被截断。 /// [DllImport("", CharSet = e)] public static extern void GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); /// /// /// 需要激活的窗⼝的句柄 /// 如果函数执⾏成功,返回⾮0值,否则,返回0 /// [DllImport("")] public static extern bool SetForegroundWindow(int hWnd); /// /// 获取桌⾯窗⼝的句柄 /// /// 桌⾯窗⼝的句柄 [DllImport("")] public static extern int GetDesktopWindow(); /// /// 设置指定窗⼝的显⽰状态 /// /// 指定的窗⼝句柄 /// 相应的状态值 /// 当指定的窗⼝可见时,返回true,不可见时则返回false /// [DllImport("")] public static extern bool ShowWindow(int hWnd, int nCmdShow); /// /// 检测给定的窗⼝是否图标化或最⼩化 /// /// 给定的窗⼝句柄 /// 当窗⼝被最⼩化时,返回⾮0值,否则,返回0 /// [DllImport("")] public static extern int IsIconic(int hWnd); /// 将创建指定窗⼝的线程带到前台并激活该窗⼝。键盘输⼊直接指向窗⼝,并为⽤户更改各种视觉提⽰。系统为创建前台窗⼝的线程分配的优先级略⾼于其他线程准备完毕之后,创建⼀个新的WPF⼯程,并在其中放置⼀个Rectangle作为缩略图位置标记。随后通过int EnumWindows(EnumWindowsCallback lpEnumFunc, int lParam);枚举系统中的窗⼝,并通过传⼊委托进⾏窗⼝句柄的过滤⼯作。这⾥采⽤的过滤语句如下 if ((dowLongA(hwnd, _STYLE) & _VISIBLE) == _VISIBLE)使⽤这条语句可以捕捉到较多的窗⼝,包括使⽤了⽆边框技术的窗⼝,例如WPS、Tim、微信等窗⼝。但是在Win10下会同时捕捉到未打开的Edge、设置,在Win7下会捕捉到开始菜单按钮图标,需要在后期进⾏进⼀步过滤。如果需要显⽰桌⾯的缩略图,可以关注标题为 Program Manager 的程序句柄,通过此句柄可以获取桌⾯缩略图。收集到桌⾯显⽰的窗⼝的句柄之后,下⼀步就是向DWM订阅窗⼝缩略图,由DWM进⾏缩略图的绘制。订阅需要使⽤使⽤此函数int DwmRegisterThumbnail(IntPtr dest, IntPtr src, out IntPtr thumb);⽬标窗⼝的句柄已经在之前的操作中获取。此时需要获取绘制缩略图的窗⼝的句柄。在WPF程序中,可以采⽤这种⽅法获取var windowHandle = new WindowInteropHelper(this).Handle;其中this是需要绘制缩略图窗⼝的引⽤。如此即可向DWM订阅窗⼝缩略图,当返回值为0时,表⽰订阅成功。订阅成功后,IntPtr thumb表⽰的是缩略图的句柄,这⼀句柄将在退订缩略图的时候使⽤,所以需要⽤变量或者容器将其暂存。在订阅成功后即可指定缩略图的绘制位置,使⽤的函数如下int DwmUpdateThumbnailProperties(IntPtr hThumb, ref DWM_THUMBNAIL_PROPERTIES props);这⾥的hThumb是刚刚获取的缩略图句柄,props是先前定义的结构体,携带绘制缩略图的位置信息。需要注意的是缩略图绘制使⽤的是拉伸模式,假如希望保持宽⾼⽐的话请⾃⾏通过代码调整。通过如下函数可以查询缩略图源窗⼝的⼤⼩信息int DwmQueryThumbnailSourceSize(IntPtr thumb, out PSIZE size);最后通过⼀定的算法,借助最初设置的Rectangle计算出缩略图相对于⽬标窗⼝四条边的像素距离,即可绘制出给定句柄的窗⼝的缩略图。这⾥不再详述。 _THUMBNAIL_PROPERTIES props = new _THUMBNAIL_PROPERTIES { fVisible = true, dwFlags = _TNP_VISIBLE | _TNP_RECTDESTINATION | _TNP_OPACITY, opacity = 255 ination = new (, , , ); }做完这⼀步就能在窗⼝中看到其他窗⼝的缩略图了。在关闭程序前,还要将已经订阅了的缩略图退订,通过Api将之前收集的缩略图句柄逐⼀关闭即可。int DwmUnregisterThumbnail(IntPtr thumb);
发布者:admin,转转请注明出处:http://www.yc00.com/web/1689721715a281056.html
评论列表(0条)