Windows 7程序开发系列之二(JumpList篇1 - User Task)
来源:互联网 发布:mac pro 待机时间 编辑:程序博客网 时间:2024/06/07 21:35
相对于上一篇中任务栏特性的开发,JumpList的开发显得稍微麻烦一些。JumpList将分为两次讲解,这次先讲解如何添加用户任务(User Task)。同样以foobar2000为例,当右键点击任务栏按钮时,显示程序的JumpList。
最下方3个项目为系统任务,一般不需要我们去操作。上方的两个任务:播放、参数选项,即为自定义的用户任务。用户任务本质上是一个快捷方式,对应于程序中由IShellLink接口表示。
一、ICustomDestinationList接口
同样先创建一个窗口,然后添加一个CreateJumpList方法,在这个方法中创建JumpList。创建JumpList需要几个步骤:1、创建 ICustomDestinationList 接口,这个接口对应的就是JumpList。2、调用BeginList 方法。3、创建IObjectCollection 接口。4、向 IObjectCollection 中添加快捷方式。5、由 IObjectCollection 接口取得IObjectArray 接口。6、将 IObjectArray 加入 ICustomDestinationList 。7、调用CommitList 方法。在CreateJumpList方法中加入下面代码:
二、IShellLink接口
上面的代码还不能编译,AddShellLink方法还没有编写。这个方法用于在IObjectCollection 中加入一个IShellLink 对象。 IShellLink 接口有几个方法用于设置属性:1、SetPath :设置目标的路径。2、SetWorkingDirectory 设置工作目录。3、SetIconLocation 设置图标。4、SetArguments 设置命令行参数。5、设置标题(这一步稍微复杂一点、在独立的方法中设置)。设置完属性后,调用 IObjectCollection 的AddObject 方法,将快捷方式加入。
SetTitle方法用于设置标题,由于IShellLink 接口本身不带有设置标题的方法。因此需要用到另一个接口IPropertyStore 来设置标题。首先由 IShellLink 接口得到 IPropertyStore 接口,然后由字符串初始化一个PROPVARIANT 对象,接下来将该 PROPVARIANT 对象设置为标题,最后提交。
上面的例子将目标路径设置为记事本的路径,并且加上命令行参数"Test.txt",当点击后,将调用记事本并传入参数"Test.txt"。
三、由当前程序实例响应用户任务
现在问题的是,在大多数情况下,用户任务应该不仅仅对应的是一个指向某个程序的快捷方式,而是应该对应的是当前程序的某个功能。比如在foobar2000中的参数选项,对应着程序中的功能。而且当选择这个用户任务的时候,应该是由当前程序的当前实例来响应这个操作,而不是由新的实例来完成这个操作。接下来要做的就是如何将用户任务反映到当前程序实例中。
这里涉及到两个问题。第一个问题是,程序必须是单实例应用程序,因为当点击用户任务时,我们不能由新的程序实例来响应。解决办法是当程序启动时,检查该程序是否已有先前实例在运行,如果有,则退出,防止第二个实例运行。第二个问题是,我们的用户任务实际是通过快捷方式传递给程序的参数来反映的。而这个参数只有第二个实例能够收到。那么在第二个实例退出之前,要想办法把参数传递到第一个实例。
我们先把之前创建的用户任务改为指向自己。修改AddShellLink方法如下,其中注释的地方即为修改过的地方:
现在的情况是,当我们点击User Task 1时,一个新的实例启动了。接下来就来解决上面提到的问题。
第一个问题的解决方法是使用Mutex(互斥量)。当第一个实例启动时,创建一个互斥量。当第二个实例启动时,同样创建这个互斥量。由于该互斥量已经创建,所以必然导致失败,第二个实例退出。当第一个实例结束的时候,撤销该互斥量。在WinMain函数的开头加上下面代码:
WinMain函数的结尾加上下面代码:
这次当我们点击User Task 1时已经看不见新的实例启动了(实际上新的实例仍然启动了,只不过检测到先前实例后,迅速退出了)。
第二个问题是如何将参数传递到第一个实例。对于Windows程序来说,最容易想到的就是通过消息发送了。但又如何得到先前实例的主窗口句柄呢?这里要用到内存映射文件(Memory Mapped File)。第一个实例运行后,将自己的主窗口句柄放入到一个内存映射文件中,第二个实例从该内存映射文件中读出先前实例的主窗口句柄。在窗口创建之后加入下面代码,将当前主窗口句柄放入内存映射文件:
该内存映射文件的名字不要和之前Mutex的名字相同,否则会创建失败。在程序退出之前要关闭文件:
在WinMain函数开头,检测到有先前实例运行之后。从这个内存映射文件读入先前实例的主窗口句柄:
得到先前实例的窗口句柄后,利用WM_COPYDATA消息,将命令行参数发送到先前实例。
然后加入对WM_COPYDATA消息的处理:
在HandleCmdLine中,我们只简单显示一条消息即可:
验证一下现在的效果:
因为JumpList即使在程序没有运行时也是存在的,所以我们在窗口创建之后也要调用一次HandleCmdLine方法,以使第一个程序实例可以响应静止状态下的用户点击。如下面的效果:
此时程序未运行,只是锁定到任务栏,点击JumpList上的用户任务,第一个程序实例启动,并响应用户任务
为了简化问题,上面的代码中省去了很多错误处理。在实际的使用中,我将单实例运行与实例间的数据传递封装在了一个辅助的类中,源代码中将会提供这个类。
上面代码需要包含的头文件:
需要连接的库:shlwapi.lib
本节源代码下载
- Windows 7程序开发系列之二(JumpList篇1 - User Task)
- Windows 7程序开发系列之二(JumpList篇1 - User Task)
- Windows 7程序开发系列之二(JumpList篇1 - User Task)
- Windows 7程序开发系列之二(JumpList篇2 - Destination)
- Windows 7程序开发系列之二(JumpList篇2 - Destination)
- Windows 7程序开发系列之二(JumpList篇2 - Destination)
- Windows 7程序开发系列 任务栏篇
- Windows 7程序开发系列之一(任务栏篇)
- Windows 7程序开发系列之一(任务栏篇)
- Windows 7程序开发系列之一(任务栏篇)
- Windows 7程序开发系列之一(任务栏篇)
- Windows 7程序开发系列之一(任务栏篇)
- JBoss 系列四十七:jBPM5示例之 User Task
- windows 7 内核程序开发二之数据结构
- .NET 4 并行(多核)编程系列之二 从Task开始
- 【Windows Mobile开发系列 之 开始二】使用VS2008进行Windows Mobile开发环境的搭建
- Windows Mobile开发系列 之 开始二】使用VS2008进行Windows Mobile开发环境的搭建
- IOS开发模块总结(二)后台运行程序(2)Task completion-UIBackgroundTaskIdentifier
- 混合高斯背景建模-视频的运动目标检测
- 关系数据库—多对多的关系
- 微信小程序的组件用法与传统HTML5标签的区别
- 骰子游戏(JAVA)
- 专注于云软件安全的8种方法
- Windows 7程序开发系列之二(JumpList篇1 - User Task)
- 什么是数据库?以及Mysql数据库
- Android 5.0以下出现 java.lang.NoClassDefFoundError
- 写递归函数的正确思维方法
- 视频压缩的基本原理,一些常见压缩算法的概念
- 如约而至:微信自用的移动端IM网络层跨平台组件库Mars已正式开源
- Windows 7程序开发系列之二(JumpList篇2 - Destination)
- 无线感测器网路
- 56-System V 共享内存-shmat 与 shmdt