Windows 7 引入了很多新特性,其中最直观的莫过于用户界面上的变化。很多人也因为不能适应这种变化而回到了XP。但是在我看来这些新的特性却是一种进步,使用了一段时间之后,也萌生了要做一点开发的冲动。于是把以前一个电源管理的小软件重写了一次(点此下载 ),利用了Windows 7 的任务栏特性和JumpList。

  关于Windows 7开发的中文资料比较少。微软官方的教程还比较丰富,但都是英文的,可能某些英文不太好的朋友学起来比较吃力。我把任务栏和JumpList这两个方面做一个简短的教程,希望对后来者有所帮助。

  任务栏方面的东西比JumpList稍微简单一点,就先从任务栏说起。Windows7的任务栏包含了几个新的特性:Progress Bar(进度条)、Overlay Icon(覆盖图标)、 Thumbnail(缩略图)、Thumbnail Toolbar(位于缩略图下方的工具栏)、Tooltip(鼠标指向时的提示信息)、Aero Peek Preview(当鼠标停放在缩略图上时显示窗口预览)。下面是一张foobar2000运行时的截图:

  

  上图中foobar2000使用Progress Bar显示当前歌曲的播放进度,并且在右下角有一个白色的小三角形(Overlay Icon)显示当前是播放还是暂停,使用Thumbnail显示唱片封面,Thumbnail Toolbar有三个按钮分别是上一曲、暂停、下一曲,上方的Tooltip提示当前播放曲目,当鼠标放在缩略图上时,Aero Peek功能会隐藏所有窗口,只显示当前窗口的预览图。上面的Progress Bar和Overlay Icon不太清晰,下面的比较清晰:

  

  这篇文章中,将会讲解这些功能的开发。

  MSDN上很容易找到SDK的下载地址,我就不贴了。SDK有1.44G,下载需要一点时间。安装过程也没什么可讲,就是安装完后在开始菜单中找到Microsoft Windows SDK v7.0->Visual Studio Registration->Windows SDK Configuration Tool,将v7.0设置为当前版本,这样VS中的Windows SDK将使用v7.0版。 与任务栏按钮相关的功能都在这个接口中,Progress Bar, Overlay Icon等。首先创建一个Win32项目,并创建一个简单的窗口,具体不再赘述,文章末尾会给出代码。在WinMain函数的开头,注册一个"TaskbarButtonCreated"的消息,

  //注册用户消息

  WM_TASKBARBUTTONCREATED=::RegisterWindowMessage (TEXT ("TaskbarButtonCreated" ));

  这样我们在WndProc中就可以收到我们注册的 WM_TASKBARBUTTONCREATED消息了。在这个消息中,创建ITaskbarList4 接口对象,并调用初始化方法。至于COM相关的内容,已经超出了本教程的范围,有兴趣的可以参考相关资料。

  //创建接口对象 ITaskbarList

  if (msg==WM_TASKBARBUTTONCREATED )

  {

  ::CoCreateInstance (CLSID_TaskbarList,NULL,CLSCTX_INPROC_SERVER,IID_PPV_ARGS (&g_pTaskbar ));

  g_pTaskbar->HrInit ();

  } SetProgressState 方法设置进度条的状态,实际反映出来就是进度条的颜色,它接受一个窗口句柄和一个状态标记为参数。其中 TBPF_NOPROGRESS 为取消进度条,TBPF_INDETERMINATE 是一个不断滚动的,无确定值的进度条。

  SetProgressValue 方法设置进度条的值,也就是当前进度。它的参数是窗口句柄、当前值和总值。如果用这个方法设置了进度条,之前设置的TBPF_INDETERMINATE 将无效。

  SetOverlayIcon 设置覆盖图标,他的参数是窗口句柄、图标句柄和描述。其中图标要求16X16大小。如果图标句柄为NULL,则取消覆盖图标。

  在g_pTaskbar对象初始化后,加入下面代码:

  g_pTaskbar->SetProgressState (g_hWnd,TBPF_ERROR );

  g_pTaskbar->SetProgressValue (g_hWnd,50,100 );

  g_pTaskbar->SetOverlayIcon (g_hWnd,g_hRed,TEXT ("Error" ));

  这段代码将进度条状态设置为ERROR(红色),进度为50%,并在右下角显示一个红色图标(图标已在WinMain函数中加载)。运行后效果如下:

  

  Toolbar稍微麻烦一点,需要设置一个结构THUMBBUTTON 。其中参数dwMask 是一些标记的组合,这里我们设置为THB_ICON | THB_TOOLTIP ,即我们会使用icon和tooltip这两个字段(注意此处的tooltip是按钮的tooltip,不要与上面的tooltip混淆了)。iId 关系到事件的响应,可按顺序编号。hIcon 是该按钮使用的图标句柄。szTip 中设置提示信息。使用下面的代码增加3个按钮:

  THUMBBUTTONMASKdwMask=THB_ICON | THB_TOOLTIP ;

  THUMBBUTTONthbButtons[3];

  thbButtons[0].dwMask=dwMask ;

  thbButtons[0].iId=0 ;

  thbButtons[0].hIcon=g_hRed ;

  StringCbCopy (thbButtons[0].szTip,sizeof (thbButtons[0].szTip),TEXT ("Red" ));

  thbButtons[1].dwMask=dwMask ;

  thbButtons[1].iId=1 ;

  thbButtons[1].hIcon=g_hGreen ;

  StringCbCopy (thbButtons[1].szTip,sizeof (thbButtons[1].szTip),TEXT ("Green" ));

  thbButtons[2].dwMask=dwMask ;

  thbButtons[2].iId=2 ;

  thbButtons[2].hIcon=g_hBlue ;

  StringCbCopy (thbButtons[2].szTip,sizeof (thbButtons[2].szTip),TEXT ("Blue" ));

  g_pTaskbar->ThumbBarAddButtons (g_hWnd,ARRAYSIZE (thbButtons),thbButtons );

  效果如下:

  

  按钮有了,该响应这些按钮的消息了。点击这些按钮后,windows将会发送一个WM_COMMAND 消息,其中wParam 的高位为THBN_CLICKED ,低位是按钮的id(由参数iId设置 )。

  caseWM_COMMAND:

  if (HIWORD (wParam ) ==THBN_CLICKED )

  {

  OnThumbnailButtonClicked (LOWORD (wParam ));

  }

break ;

  voidOnThumbnailButtonClicked ( intid )

  {

  switch (id )

  {

  case0:

  SetForegroundWindow (g_hWnd );

  MessageBox (g_hWnd,TEXT ("Red button clicked!"),NULL,MB_OK );

  break ;

  case1:

  SetForegroundWindow (g_hWnd );

  MessageBox (g_hWnd,TEXT ("Green button clicked!"),NULL,MB_OK );

  break ;

  case2:

  SetForegroundWindow (g_hWnd );

  MessageBox (g_hWnd,TEXT ("Blue button clicked!"),NULL,MB_OK );

  break ;

  }

  }

  现在点击工具栏上的按钮将会有显示对应的消息框。

  Tooltip比较简单。SetThumbnailTooltip 传入窗口句柄和描述的文字就可以了。在 WM_TASKBARBUTTONCREATED 消息处理中加入下面代码:

  g_pTaskbar->SetThumbnailTooltip (g_hWnd,TEXT ("Some information" ));

  信息提示显示在预览窗之上:

  

  到目前为止,这个程序的缩略图和Aero Peek预览仍然是由系统来控制。对于大多数程序来说,系统自动产生的缩略图和预览几经足够。但有时候我们想要自己控制,比如foobar2000需要在缩略图中显示唱片封面(见第一张图)。

  要实现手动控制,需要在窗口创建以后设置一下窗口的属性,告诉Windows该窗口的缩略图和预览图需要由程序提供。在窗口创建之后加入下面代码:

  //设置窗口属性,打开自定义缩 略图和AeroPeek预览

  BOOLtruth=TRUE ;

  DwmSetWindowAttribute (g_hWnd,DWMWA_HAS_ICONIC_BITMAP,&truth,sizeof (truth ));

  DwmSetWindowAttribute (g_hWnd,DWMWA_FORCE_ICONIC_REPRESENTATION,&truth,sizeof (truth ));

  通过这样的设置以后,在WndProc中就可以收到WM_DWMSENDICONICTHUMBNAIL 和WM_DWMSENDICONICLIVEPREVIEWBITMAP 这两个消息,它们分别是Windows向程序请求Thumbnail和Aero Peek Preview时发送的消息。对于第一个消息,参数wParam的高位和低位分别表示所请求的缩略图的最大宽度和高度。在消息处理中,通过DwmSetIconicThumbnail 将一个位图句柄(HBITMAP)发送给系统。这里系统要求的位图大小不能超过参数传入的最大宽度和高度,而且必须是32位的位图,但是一般的软件只能保存24位的位图,这样的位图不符合要求,是无法显示的。于是我利用GDI+写了两个辅助函数,用于将PNG格式的资源加载为HBITMAP,以及缩放大小。

  第一个函数是加载PNG格式的资源,参数分别是:模块句柄(如果是本模块可使用GetModuleHandle(NULL)取得句柄),资源id,资源类型。这段代码所做的就是将资源加载到内存中,并由这块内存创建一个Bitmap对象。

  //将PNG等格式的资源加载为 GdiPlus::Bitmap

  Gdiplus::Bitmap*LoadBitmapFromResource ( HMODULEhModule,UINTresID,LPCTSTRresType )

  {

  //分配一块内存,把 加载的资源拷贝到内存中

  //取得资源的句柄

  HRSRChRsrc=http://blog.soso.com/qz.q/FindResource (hModule,MAKEINTRESOURCE (resID),resType );

  if (hRsrc=http://blog.soso.com/qz.q/=NULL )

  {

  returnNULL ;

  }

  //资源的大小

  intsize=SizeofResource (GetModuleHandle (NULL),hRsrc );

  //加载资源

  HGLOBALhGlobal=LoadResource (GetModuleHandle (NULL),hRsrc );

  if (hGlobal==NULL )

  {

  returnNULL ;

  }

  //分配相同大小的一块内存

  HGLOBALhGlobal2=GlobalAlloc (GMEM_MOVEABLE,size );

  if (hGlobal2==NULL )

  {

  FreeResource (hGlobal );

  returnNULL ;

  }

  //锁资源

  LPVOIDlpVoid=LockResource (hGlobal );

  if (lpVoid==NULL )

  {

  FreeResource (hGlobal );

  GlobalFree (hGlobal2 );

  returnNULL ;

  }

  //锁内存

  LPVOIDlpVoid2=GlobalLock (hGlobal2 );

  if (lpVoid2==NULL )

  {

  UnlockResource (hGlobal );

  FreeResource (hGlobal );

  GlobalFree (hGlobal2 );

  returnNULL ;

  }

  //将资源拷贝到内存

  memcpy (lpVoid2,lpVoid,size );

  //解锁

  GlobalUnlock (hGlobal2 );

  UnlockResource (hGlobal );

  //创建流

  LPSTREAMlpStream ;

  HRESULThr=CreateStreamOnHGlobal (hGlobal2,TRUE,&lpStream );

  if (hr!=S_OK )

  {

  FreeResource (hGlobal );

  GlobalFree (hGlobal2 );

  returnNULL ;

  }

  //基于流创建GdiPlus::Bitmap

  Gdiplus::Bitmap*bmp=Gdiplus::Bitmap::FromStream (lpStream );

//释放资源和内存

  FreeResource (hGlobal );

  GlobalFree (hGlobal2 );

  returnbmp ;

  }

  第二个函数是缩放Bitmap对象,最后一个参数可以选择是否要保持长宽比

  //缩放 GdiPlua::Bitmap

  Gdiplus::Bitmap*ResizeBitmap ( Gdiplus::Bitmap*bmpSrc, intdestWidth,intdestHeight,boolkeepAspect=true )

  {

  //取得源图片宽度和高度

  intsrcWidth=bmpSrc->GetWidth ();

  intsrcHeight=bmpSrc->GetHeight ();

  //计算横向和纵向的缩放比率

  floatscaleH= (float )destWidth/srcWidth ;

  floatscaleV= (float )destHeight/srcHeight ;

  //如果需要保持长宽比,则横向和纵向统一采用较小的缩放比率

  if (keepAspect )

  {

  if (scaleH>scaleV )

  {

  scaleH=scaleV ;

  }

  else

  {

  scaleV=scaleH ;

  }

  }

  //计算目标宽高

  destWidth = (int )(srcWidth*scaleH );

  destHeight= (int )(srcHeight*scaleV );

  //创建目标Bitmap

  Gdiplus::Bitmap*bmpDest=newGdiplus::Bitmap (destWidth,destHeight,PixelFormat32bppARGB );

  Gdiplus::Graphicsgraphic (bmpDest );

  //设置插值算法

  graphic.SetInterpolationMode (Gdiplus::InterpolationModeHighQualityBicubic );

  //将源图像绘制到目 标图像上

  graphic.DrawImage (bmpSrc,Gdiplus::Rect (0,0,destWidth,destHeight),

  0,0,srcWidth,srcHeight,Gdiplus::UnitPixel );

  graphic.Flush ();

  returnbmpDest ;

  }

  在调用这两个函数之前,还有一点工作要做。那就是要初始化GDI+。在WinMain函数的开头,加入下面的初始化代码:

  //初始化GDI+

  ULONG_PTRtoken ;

  Gdiplus::GdiplusStartupInputinput ;

  Gdiplus::GdiplusStartup (&token,&input,NULL );

  在WinMain函数结束的时候别忘了关闭GDI+:

  //关闭GDI+

  Gdiplus::GdiplusShutdown (token );

  准备工作做好以后,可以正式来处理缩略图了。消息处理函数中,加入下面的消息处理代码:

  caseWM_DWMSENDICONICTHUMBNAIL:

  OnSendThumbnail (hWnd,HIWORD (lParam),LOWORD (lParam ));

  break ;

  在这里我们得到了缩略图需要的宽和高,转到OnSendThumbnail函数中处理。

  voidOnSendThumbnail ( HWNDhWnd,intwidth,intheight )

  {

  //将资源加载为Bitmap

  Gdiplus::Bitmap*bmp=LoadBitmapFromResource (GetModuleHandle (NULL),IDB_THUMB,TEXT ("PNG" ));

  //缩放Bitmap

  Gdiplus::Bitmap*bmpResized=ResizeBitmap (bmp,width,height,false );

  //取得位图句柄

  HBITMAPhbmp ;

  bmpResized->GetHBITMAP (UINT (Gdiplus::Color::AlphaMask),&hbmp );

  //发送位图句柄

  DwmSetIconicThumbnail (hWnd,hbmp,0 );

  //释放对象

  DeleteObject (hbmp );

  deletebmpResized ;

  deletebmp ;

  }

  因为没有保持长宽比,所以得到下面的效果:

  

  如果保持长宽比,将得到下面的效果:

  

  接下来处理Aero Peek预览图,对应的Windows消息是WM_DWMSENDICONICLIVEPREVIEWBITMAP , 但是在该消息的参数中,没有提供宽和高。而如果我们提供的预览图的宽和高超过了窗口的客户区大小,同样是不能显示的。所以我们要手动获取客户区的大小,然后将图像缩放到客户区的尺寸。加入如下消息处理:

  caseWM_DWMSENDICONICLIVEPREVIEWBITMAP:

  OnSendPreview (hWnd );

  break ;

  voidOnSendPreview ( HWNDhWnd )

  {

  //取得窗口客户区域

  RECTrcClient ;

  GetClientRect (hWnd,&rcClient );

  //将资源加载为 Bitmap

  Gdiplus::Bitmap*bmp=LoadBitmapFromResource (GetModuleHandle (NULL),IDB_PREVIEW,TEXT ("PNG" ));

  Gdiplus::Bitmap*bmpResized=ResizeBitmap (bmp,rcClient.right-rcClient.left,

  rcClient.bottom-rcClient.top,false );

  //取得位图句柄

  HBITMAPhbmp ;

  bmpResized->GetHBITMAP (UINT (Gdiplus::Color::AlphaMask),&hbmp );

  //发送位图句柄

  DwmSetIconicLivePreviewBitmap (hWnd,hbmp,NULL,0 );

  //释放对象

  DeleteObject (hbmp );
deletebmpResized ;

  deletebmp ;

  }

  得到下面的效果 ,这张变形金刚的图片是我们发送给Windows的预览图,实际程序的界面上并没有这张图 。

  

  有一点要提醒一下,Windows会将缩略图缓存,并不会每次都向程序请求缩略图,所以如果要更新缩略图的话需要调用API函数DwmInvalidateIconicBitmaps ,这样当Windows再次需要显示缩略图时,就会发送WM_DWMSENDICONICTHUMBNAIL消息,向应用程序请求缩略图。

  至此,上面提到的所有功能都已实现。有几个头文件需要包含到程序中:

  #include <shobjidl.h>

  #include <dwmapi.h>

  #include <tchar.h>

  #include <strsafe.h>

  #include <GdiPlus.h>

  编译时需要链接的库有:dwmapi.lib gdiplus.lib

转载于:https://www.cnblogs.com/MaxWoods/archive/2010/09/28/1837741.html

Windows 7程序开发系列之一(任务栏篇)相关推荐

  1. 《基于Windows 7特性的程序开发系列》视频分享

    前一阵录制了<基于Windows 7特性的程序开发系列>视频课程,主要针对WinForm.WPF 开发具有Windows 7 特性的程序.现已发布到MSDN Webcast 欢迎大家拍砖. ...

  2. Silverlight for Windows Phone 7开发系列(2):第一个Silverlight程序

    前言 上一篇讲述了Windows Phone 7开发环境的搭建,这篇文章讲述如何创建,部署,调试以及运行Silverlight for Windows Phone应用程序,同时介绍如何Microsof ...

  3. 【微信小程序开发•系列文章一】入门

    本系统文章主要有以下几篇: <[微信小程序开发•系列文章一]入门> <[微信小程序开发•系列文章二]视图层> <[微信小程序开发•系列文章三]数据层> <[微 ...

  4. 桌面应用开发框架 - Windows桌面程序开发工具

    桌面应用开发框架 - Windows桌面程序开发工具 桌面应用开发 桌面应用开发是指基于Windows操作系统开发的应用程序,在Windows环境运行,包括32位\64位的应用程序, 从开发者层面讲, ...

  5. C++ WINDOWS API 第1章 Windows 应用程序开发入门

    目录 1.1       第一个实例程序.. 1 1.1.1       start.exe. 1 1.1.2       Windows API 2 1.1.3       程序入口函数.. 2 1 ...

  6. Jerry Wang的微信小程序开发系列文章

    微信小程序开发系列一:微信小程序的申请和开发环境的搭建 微信小程序开发系列二:微信小程序的视图设计 微信小程序开发系列教程三:微信小程序的调试方法 微信小程序开发系列四:微信小程序之控制器的初始化逻辑 ...

  7. 微信小程序开发系列七:微信小程序的页面跳转

    微信小程序开发系列教程 微信小程序开发系列一:微信小程序的申请和开发环境的搭建 微信小程序开发系列二:微信小程序的视图设计 微信小程序开发系列三:微信小程序的调试方法 微信小程序开发系列四:微信小程序 ...

  8. 微信小程序开发系列六:微信框架API的调用

    微信小程序开发系列教程 微信小程序开发系列一:微信小程序的申请和开发环境的搭建 微信小程序开发系列二:微信小程序的视图设计 微信小程序开发系列三:微信小程序的调试方法 微信小程序开发系列四:微信小程序 ...

  9. 微信小程序开发系列五:微信小程序中如何响应用户输入事件

    微信小程序开发系列教程 微信小程序开发系列一:微信小程序的申请和开发环境的搭建 微信小程序开发系列二:微信小程序的视图设计 微信小程序开发系列三:微信小程序的调试方法 微信小程序开发系列四:微信小程序 ...

最新文章

  1. linux下 命令 实验,实验一:Linux命令实验
  2. SQL注入(1)--判断是否存在SQL注入漏洞
  3. 用python爬虫爬取无水印图片_使用python 爬虫,爬取图片
  4. Python错误,pip安装包或更新时因超时而报错误
  5. [读码][js,css3]能感知鼠标方向的图片遮罩效果
  6. 自动初始化 git Bash脚本
  7. 【预测模型】基于matlab BP神经网络预测【含Matlab源码 221期】
  8. 人工智能、机器学习、神经网络和深度学习的关系
  9. sql做题记录(一)
  10. mycat + keepalived + haproxy + mmm
  11. html js css 简明教程,Web前端开发简明教程(HTML+CSS+JavaScript+jQuery)
  12. 2017年度全球一级市场“投资龙虎榜”发布 | 钛媒体Pro独家
  13. C51/C52单片机printf打印出来的值是原来值的256倍
  14. 歌单助手:一键导出网易云音乐歌单列表,推荐你喜爱的专辑
  15. 滴水课后作业(6-10)
  16. CLion 的 Debug 模式是怎么回事
  17. 华为云通用计算增强型C6到底怎么样?
  18. Virtual DOM 的实现原理
  19. 渗透测试-红/蓝队Hvv技术手册/面试
  20. 做刀尖上的舞者 京东无线服务端的三次架构演进

热门文章

  1. dto 是只给前端需要的数据吗_解决消息队列的数据积压很难?其实只需要这三招...
  2. 云服务器上部署pytorch,flask部署pytorch-服务端
  3. python强制转型,python2--python3如何转型
  4. java object 判断null_java判断object为null
  5. mysql 子表 关联查询语句_MySQL-基本查询语句及方法,连表和子查询
  6. php备份网站程序,使用PHP备份整个网站
  7. 处理字典值是把字典放内存还是用sql处理_python基础~元祖与字典原理
  8. mysql建用户无密码_mysql 新建用户,授权,删除用户,修改密码
  9. php 转换为自定义类,PHP面向对象教程之自定义类_PHP
  10. 苹果5s现在还能用吗_苹果ios稳定企业签名,现在苹果企业签名还是最稳定的苹果签名吗...