使用桌面窗口管理器创建特殊效果.docx
《使用桌面窗口管理器创建特殊效果.docx》由会员分享,可在线阅读,更多相关《使用桌面窗口管理器创建特殊效果.docx(18页珍藏版)》请在冰豆网上搜索。
使用桌面窗口管理器创建特殊效果
使用桌面窗口管理器创建特殊效果
RonFosner
本文讨论:
▪理解DWM
▪对DWM编程
▪在玻璃区域上绘制和合并实时缩略图
本文使用了以下技术:
WindowsVista、.NETFramework
下载本文中所用的代码:
DWM2007_04.exe(166KB)
浏览在线代码
目录
DWM的技术概览
组合桌面的好处
一些常见的组合函数
为AeroGlass做好准备
对DWM编程
在玻璃区域上绘制
缩略图
总结
我一直盼望着Windows新版本的发布。
令人感兴趣的事情莫过于浏览MSDN®和SDK文档,查找一些可以利用和依赖的最新创新,然后让朋友和同事以及您的老板(如果幸运的话)大开眼界。
WindowsVista™在这方面包含许多诱人的内容。
自从听说该版本将三维/组合层集成到桌面以来,我就特别希望获得该版本。
多年来我已编写了数不清的三维应用程序,但我发现令人烦恼的一件事是,虽然能够在三维应用程序中提供非常酷且令人赏心悦目的用户界面,但在非三维应用程序中却不能。
有了WindowsVista和桌面窗口管理器(DWM),这种情况就发生了改变(请参见图1)。
图1DWM可以实现诸如Flip3D任务切换等功能(单击该图像获得较大视图)
DWM是一种新界面,用于管理如何将运行和呈现的各种窗口合并到WindowsVista桌面上。
Windows®PresentationFoundation(WPF)提供了一种更高级别的层,控制着到桌面层的呈现,WindowsDisplayDriverModel(WDDM)用于处理到显示器的实际低级呈现。
本文仅讨论如何使用DWM界面。
有关该主题的详细信息,请阅读DavidChappell编写的MSDN文章“WindowsPresentationFoundation简介”(之所以是本文通篇关注的唯一内容,是因为它可以通过DWM界面实现新效果,而且可以修复一些特定问题。
DWM的技术概览
在除WindowsVistaHomeBasic之外的所有WindowsVista版本中均提供DWM界面,通过dwm.exe可以启动该界面。
系统中的所有应用程序都可以从DWM获益,而无需进行修改或重新编译。
不过,选择利用特定DWM功能的应用程序可以调用dwmapi.dll中的界面(DWM的公用界面),然后将这些界面传递到dwm.exe。
界面声明可在dwmapi.h中找到,并且可以从在线获取最新的API信息。
WindowsVista在设计上对每个窗口都使用图形加速器,而不是仅针对三维DirectX®应用程序。
为了实现这一点,DWM需要与WDDM通信,后者是图形处理器和视频内存的最终所有者。
(DWM依赖于milcore.dll,后者是与WindowsPresentationFoundation共享的组件,用于输出和呈现到DirectX。
)呈现操作由DWM中的单独线程处理,拥有DirectX设备的用户无法对其进行访问。
另外,大多数应用程序本身有处理呈现操作和UI的线程(如典型的Win32®应用程序中的USER消息弹出线程),但其与DWM的呈现线程不冲突。
DWM获取一个窗口列表,并在树结构中管理其位图,然后将其组合到最终桌面。
换言之,每个应用程序均呈现自己的位图,然后由DWM进行组合。
应用程序的主窗口线程呈现其场景,DWM呈现线程对该场景进行访问,并且呈现线程通过其DirectX界面更新桌面。
传递的信息被压缩为仅对以前呈现的更改(差异),大型数据(如图像)则置于共享内存中。
这就潜在地允许在一台计算机上生成场景,而最终的呈现操作可以在另一台计算机上完成。
使用过OpenGL的三维程序员会对此体系结构非常熟悉,它允许服务器管理三维场景,并且仅将差异发送到客户端计算机。
您可以分布式呈现三维场景,并让其在任何数量的客户端计算机上使用完全硬件加速运行。
此体系结构使DWM能够为远程桌面方案提供一级支持。
尽管WindowsVista将与旧版WindowsXP兼容驱动程序一起运行,但需要让WDDM视频驱动程序来获得所有DWM功能。
与某些假定情况相反,DWM不需要DirectX10,但它确实需要更多的视频/纹理内存和支持ShaderModel2.0或更高版本的视频卡。
使用WDDM的最大改变是它引入了VideoMemoryManager(VidMM),后者可以在系统内存和视频内存之间交换视频内存分布。
这意味着WDDM可以虚拟化视频卡的资源,因而在共享和交换视频内存方面以及在不同应用程序的不同线程之间对图形处理器进行上下文切换方面可以做得更好。
以前几乎不可能稳定地运行多个三维应用程序,原因是驱动程序无法处理上下文切换。
而且在WDDM出现之前,没有可用的正式计划,因此通常会出现一个DirectX应用程序耗尽其他应用程序的资源。
而使用WDDM就很难发生这种情况。
WindowsVista对驱动程序的控制也严格得多,并要求比以前Windows版本的驱动程序更强大可靠。
另外请注意,DirectX10是一个仅用于WindowsVista的API。
为DirectX以前版本设计的应用程序将运行于旧版DirectXAPI实现(预计将被称为DirectX9L)上。
这将是WDDM之前的驱动程序支持的最后版本。
DirectX9L应用程序预计将运行于装有DirectX9L的WindowsXP上和WindowsVista上。
DirectX10不包含旧式界面。
组合桌面的好处
所有这些新的子系统可让您独立呈现窗口,并在将它们呈现到桌面之前对其执行组合步骤。
在WindowsVista和随之发布的一些更新应用程序中可以很好地利用这一点。
关于这一点,我要向您展示的两个用法是Aero™玻璃效果和缩略图。
玻璃效果仅在运行AeroGlass方案并打开组合功能时才可用。
AeroBasic不提供此效果。
由于每个窗口都在自己的视频内存区中创建,因此需要由DWM将该窗口的最后组合呈现到桌面。
这意味着,DWM可以访问桌面上的图像,并可以将其与您的窗口呈现混合在一起,创建由二者组合的呈现。
在与现有桌面图像混合以创建霜冻玻璃效果的任何窗口区域中,这一点非常明显。
由于每个窗口都呈现到中间屏外表面,这意味着DWM是涉及更新玻璃效果的唯一程序。
在移动使用玻璃效果的窗口时,不需要使任何基本窗口无效。
DWM会处理半透明可视图像到新坐标的更新。
可以指示DWM为要呈现玻璃效果的窗口添加某些客户端区域,这样可让您创建供自己使用的玻璃区域。
此屏外组合使得桌面响应更快。
由于每个窗口现在都从桌面中单独呈现,因此就消除了您在更新较慢的应用程序(如Web浏览器)中经常遇到的问题。
在Windows的以前版本中,图2显示的内容并不陌生。
在另一个应用程序上方来回移动窗口时会出现这种撕裂现象,这是因为下面的窗口更新的速度太慢。
进行桌面组合之后,就不会再看到这种现象。
图2慢速呈现导致撕裂现象(单击该图像获得较大视图)
随WindowsVista一起发布的一些应用程序利用此功能将玻璃效果呈现到客户端区域中。
其中一个最好的示例是WindowsMedia®Player,该程序将框架扩展到客户端区域的底部,它在该区域中绘制一些自定义控件。
最小版本看起来与图3类似。
图3WindowsMediaPlayer中的玻璃效果(单击该图像获得较大视图)
当在我的桌面上来回移动窗口时,通过控件可以看到的图像由播放器下面的桌面部分组成。
如果将窗口移动到某个动画上,我可以透过上面的窗口看到动画!
这就是组合桌面的功能所在。
如果关闭组合效果,则仅会在窗口中获得“极光”效果,并且窗口将呈现不透明的默认窗口颜色,如图4所示。
图4关闭玻璃效果的WindowsMediaPlayer(单击该图像获得较大视图)
从本质上讲,AeroBasic和AeroGlass界面是DWMUI之前的标准和新标准之间的分水岭。
AeroBasic界面为程序提供同一API,以保持向后兼容性,但是运行Basic界面则意味着您在使用旧式窗口管理器,DWM是不活动的。
旧式界面意味着UI布局将像WindowsVista之前编写的程序预期的那样。
DWM控制着AeroGlass界面并限制对它的访问。
如果应用程序进入非客户端区域(玻璃框架),DWM将检测到它,并切换到AeroBasic框架。
WindowsVista中由于组合桌面而提供的其他新功能还有,新的WindowsFlip(Alt+Tab)和Flip3D(Alt+Windows键)任务切换器。
Flip3D特别有趣,因为它的功能取决于DWM中的一些代码,这些代码将获取场景图形中的每个顶级窗口,并将其呈现到一系列扭曲的窗口上,您可以使用键盘或鼠标在这些窗口中进行滚动(请参见图1)。
DWM控制着窗口与桌面组合引擎的交互方式。
若要让您的程序集成到DWM功能中,需要了解DWM的工作方式以及如何与之交互。
除了一些其他功能外,DWM在其公共API中有四个主要功能区:
∙基本桌面组合设置
∙在客户端窗口中呈现玻璃效果
∙呈现缩略图
∙调整呈现效果以便与多媒体程序交互
我将在本文中讲述前三部分。
最后一部分为DirectX和视频播放应用程序提供,因为DWM是异步运行的,如果不进行严格控制可能会导致采样失真。
一些常见的组合函数
如果您希望在程序中使用桌面组合功能,则需要查询和设置各种DWM参数。
例如,如果某些应用程序切换为全屏显示,然后DWM关闭组合,并以不透明的桌面背景颜色呈现,那么您的应用程序应识别这种情况并禁用特定于组合的功能。
下面是将您的程序与DWM集成的一些基本函数:
DwmEnableComposition启用或禁用DWM组合。
DWM将在当前进程中或直到重设前保持此设置。
更改设置会导致发出WM_DWMCOMPOSITIONCHANGED通知。
多数应用程序不需要调用此函数,但您可能需要监视Windows的最终消息。
DwmIsCompositionEnabled获取桌面启用DWM组合的状态。
DwmSetWindowAttribute为窗口设置指定的DWM属性的值,控制如何处理DWM过渡,是否允许非客户端呈现,以及Flip3D将如何处理窗口。
例如,如果对某个窗口关闭非客户端呈现,则稍后扩展框架或使窗口后面的内容变模糊的要求将会失败。
DwmGetWindowAttribute为指定窗口检索指定DWMWINDOWATTRIBUTE的当前值。
DwmGetColorizationColor检索用于DWM玻璃组合的当前颜色。
此值基于当前颜色方案。
更改此设置将导致发出WM_WMCOLORIZATIONCOLORCHANGED通知。
DwmDefWindowProc在使用WM_NCHITTEST通知进行调用时以及由于在扩展了客户端框架而需要处理WM_NCCALCSIZE及类似消息时,使DWM命中测试位于非客户端区域。
在您的程序中呈现玻璃效果相当简单。
DWM为此提供了两个函数:
DwmExtendFrameIntoClientArea一个简单的函数,将非客户端框架的边缘扩展到窗口内。
DwmEnableBlurBehindWindow一种更为复杂的函数,对玻璃效果的呈现方式提供更多的控制。
由于所有组合窗口都通过DWM呈现到一个屏外窗口,然后进行组合后再呈现到桌面上,因此获取这些图像并提供应用程序的实时缩略图表示并不困难。
DWM为您提供了四个函数来控制缩略图的呈现方式:
DwmQueryThumbnailSourceSize返回DWM缩略图的原始大小。
DwmRegisterThumbnail创建目标窗口和源窗口之间的缩略图关系。
DwmUnregisterThumbnail删除由DwmRegisterThumbnail创建的DWM缩略图关系。
DwmUpdateThumbnailProperties更新给定缩略图的属性。
DWM提供了五个函数用于微调DWM的呈现方式,但这些函数超出了本文的讨论范围。
为AeroGlass做好准备
若要对DWM界面编程,您需要运行能够显示AeroGlass的WindowsVista版本。
虽然最方便的方法是使用C++代码调用这些新函数,但如果可以的话,我喜欢用C#编写用户界面代码。
本文的所有代码均使用C#编写,但这意味着您必须经受严峻的考验。
若要使用本文讨论的函数,您要么需要使用C++和正确的库中的链接,要么必须用C#为函数和结构编写P/Invoke包装。
在本文的下载部分中包含一个库,其中提供了DWM所需函数和结构的包装,因此您可以从C#程序调用它。
基本上,这只是从dwmapi.dll下载界面的一组说明。
为使用本文中使用的用于玻璃效果和缩略图的DWM函数,您需要创建DWM函数和数据结构的C#声明。
我为本文创建的声明类似于图5。
Figure5DWM的C#声明
复制代码
internalclassDwmApi
{
[DllImport("dwmapi.dll",PreserveSig=false)]
publicstaticexternvoidDwmEnableBlurBehindWindow(
IntPtrhWnd,DWM_BLURBEHINDpBlurBehind);
[DllImport("dwmapi.dll",PreserveSig=false)]
publicstaticexternvoidDwmExtendFrameIntoClientArea(
IntPtrhWnd,MARGINSpMargins);
[DllImport("dwmapi.dll",PreserveSig=false)]
publicstaticexternboolDwmIsCompositionEnabled();
[DllImport("dwmapi.dll",PreserveSig=false)]
publicstaticexternvoidDwmEnableComposition(boolbEnable);
[DllImport("dwmapi.dll",PreserveSig=false)]
publicstaticexternvoidDwmGetColorizationColor(
outintpcrColorization,
[MarshalAs(UnmanagedType.Bool)]outboolpfOpaqueBlend);
[DllImport("dwmapi.dll",PreserveSig=false)]
publicstaticexternIntPtrDwmRegisterThumbnail(
IntPtrdest,IntPtrsource);
[DllImport("dwmapi.dll",PreserveSig=false)]
publicstaticexternvoidDwmUnregisterThumbnail(IntPtrhThumbnail);
[DllImport("dwmapi.dll",PreserveSig=false)]
publicstaticexternvoidDwmUpdateThumbnailProperties(
IntPtrhThumbnail,DWM_THUMBNAIL_PROPERTIESprops);
[DllImport("dwmapi.dll",PreserveSig=false)]
publicstaticexternvoidDwmQueryThumbnailSourceSize(
IntPtrhThumbnail,outSizesize);
[StructLayout(LayoutKind.Sequential)]
publicclassDWM_THUMBNAIL_PROPERTIES
{
publicuintdwFlags;
publicRECTrcDestination;
publicRECTrcSource;
publicbyteopacity;
[MarshalAs(UnmanagedType.Bool)]
publicboolfVisible;
[MarshalAs(UnmanagedType.Bool)]
publicboolfSourceClientAreaOnly;
publicconstuintDWM_TNP_RECTDESTINATION=0x00000001;
publicconstuintDWM_TNP_RECTSOURCE=0x00000002;
publicconstuintDWM_TNP_OPACITY=0x00000004;
publicconstuintDWM_TNP_VISIBLE=0x00000008;
publicconstuintDWM_TNP_SOURCECLIENTAREAONLY=0x00000010;
}
[StructLayout(LayoutKind.Sequential)]
publicclassMARGINS
{
publicintcxLeftWidth,cxRightWidth,
cyTopHeight,cyBottomHeight;
publicMARGINS(intleft,inttop,intright,intbottom)
{
cxLeftWidth=left;cyTopHeight=top;
cxRightWidth=right;cyBottomHeight=bottom;
}
}
[StructLayout(LayoutKind.Sequential)]
publicclassDWM_BLURBEHIND
{
publicuintdwFlags;
[MarshalAs(UnmanagedType.Bool)]
publicboolfEnable;
publicIntPtrhRegionBlur;
[MarshalAs(UnmanagedType.Bool)]
publicboolfTransitionOnMaximized;
publicconstuintDWM_BB_ENABLE=0x00000001;
publicconstuintDWM_BB_BLURREGION=0x00000002;
publicconstuintDWM_BB_TRANSITIONONMAXIMIZED=0x00000004;
}
[StructLayout(LayoutKind.Sequential)]
publicstructRECT
{
publicintleft,top,right,bottom;
publicRECT(intleft,inttop,intright,intbottom)
{
this.left=left;this.top=top;
this.right=right;this.bottom=bottom;
}
}
}
如果您使用的是C#,则需要在您的代码中创建与此类似的声明。
然后,如果您运行的是WindowsVista,则可以进行DWM调用。
当然,不应仅假定您的应用程序运行于WindowsVista上。
为保险起见,您需要确认Environment.OSVersion.Version.Major至少为6.0。
或者,您可以捕获由于尝试通过P/Invoke调用不存在的函数而导致的异常。
如果希望使用玻璃效果,则您使用的计算机需要满足三个要求。
首先,需要运行WindowsVista的Premium、Business或Ultimate版本。
其次,硬件应能够运行Aero界面(详细信息请参见WindowsVista中选择WindowsAero颜色方案。
需要谨慎使用此操作,因为用户过度使用该效果会对计算机的GPU造成负担。
图6窗口颜色和外观选项(单击该图像获得较大视图)
通过打开“个性化”控制面板并单击“Window颜色和外观”选项启用Aero方案。
在此屏幕上(请参见图6),确保选中了“启用透明效果”选项,然后单击“打开传统风格的外观属性”链接。
在“外观设置”对话框中的“颜色方案”下单击WindowsAero(请参见图7)。
在单击“确定”后,将会看到Aero界面和玻璃效果。
如果愿意,还可以自定义窗口颜色和不透明级别。
图7WindowsAero玻璃效果(单击该图像获得较大视图)
对DWM编程
通过调用DwmIsCompositionEnabled可以检查在您的程序中是否启用了Aero方案。
但是请注意,不但用户可以随时更改当前Aero方案,而且其他应用程序也能够以编程方式启用或禁用该方案。
因此检查一次此函数的结果可能不够可靠。
DwmEnableComposition函数可让程序打开或关闭Aero方案。
例如,如果您编写的应用程序可能遇到兼容性问题,则在应用程序运行时可能需要禁用组合(如果您编写的是全屏DirectX专用应用程序,将会自动禁用组合)。
此设置仅在设置它的进程期间保持,当进程结束时,组合标志将被重设为其初始值。
通常情况下,除非由于应用程序兼容性原因,否则应用程序不应使用此设置,而应让系统或用户作出决定。
当桌面组合的状态更改时,将广播WM_DWMCOMPOSITIONCHANGED消息。
您无法通过参数了解是否启用或禁用了组合,因此,如果感兴趣,由您自己决定调用DwmIsCompositionEnabled。
执行检查的代码非常简单,难点是当禁用组合时,如何决定窗口的外观。
复制代码
//ChecktoseeifcompositionisEnabled
if(DwmIsCompositionEnabled())
{
//enableglassrendering
}
else