在Windows 7操作系统中,应用程序可以通过编程方式自定义其任务列表,从而提供给用户更加直观和便捷的操作体验。任务列表允许应用程序定义一些快捷命令,例如“新建文档”。本文将介绍如何通过编程方式添加自定义任务,并在程序中处理这些任务。
本文的示例代码基于Visual Studio 2008、WTL 8.0和Windows 7SDK Beta版本构建。
在之前的文章中,了解到任务列表可以包含两种类型的条目:目标和任务。本文将重点介绍任务,即应用程序可以执行的命令,如“新建文档”。任务在内部表示为IShellLink,因此任务应该是可以通过命令行与应用程序通信的命令。
用户可以将应用程序固定到任务栏,并从固定快捷方式中调出任务列表。这意味着在用户执行任务之前,应用程序不必正在运行。因此,任务必须是随时可以执行的操作。例如,IE8有一个任务是打开一个新的InPrivate浏览器窗口,无论IE是否已经运行,都可以执行此操作。微软建议任务列表应该是静态的,不根据应用程序的当前状态而变化。
任务显示在它们自己的类别中,类似于上次看到的“最近”和“频繁”类别。任务类别始终是列表中的最后一个类别(最接近底部),但只要列表中有足够的空间,其项目总是显示出来。这可能会减少其他类别的空间,因此,在决定要放入列表的任务时,要考虑如果任务太多,将会减少最近使用或频繁使用的文件的空间,如果在任务列表中包含这些类别的话。
虽然没有文档记录任务的最大数量,但最大数量受到屏幕空间和可用性考虑的限制。Windows 7Beta版本似乎没有强制执行最大数量(能够创建一个超出1920x1200屏幕边缘的任务列表),而RC版本最多有16个。不应依赖这个数字在未来保持不变,因为微软可能会根据设计或可用性决策更改任务列表的内部工作方式。如果添加了太多任务,任务列表将显示尽可能多的任务,其余的将不可见。
使用任务需要创建自定义任务列表,因此程序如下:
示例应用程序在WinMain()中设置其任务列表,以便每次运行程序时都执行此操作。(这意味着自定义任务列表在运行程序一次之前不会出现。)创建任务列表不是一个耗时的操作,因此这不会导致启动延迟。
在示例项目中,所有与任务列表相关的代码都在SetUpJumpList()中。首先创建一个新的任务列表:
bool SetUpJumpList() {
CComPtr pDestList;
pDestList.CoCreateInstance(CLSID_DestinationList);
pDestList->SetAppID(g_wszAppID);
UINT cMaxSlots;
CComPtr pRemovedItems;
pDestList->BeginList(&cMaxSlots, IID_PPV_ARGS(&pRemovedItems));
CComPtr pObjColl;
pObjColl.CoCreateInstance(CLSID_EnumerableObjectCollection);
AddJumpListTasks(pObjColl);
CComQIPtr pTasksArray = pObjColl;
pDestList->AddUserTasks(pTasksArray);
pDestList->CommitList();
}
接下来,创建一个对象集合来保存任务。通过创建一个带有CLSID_EnumerableObjectCollection的COM对象,并请求一个IObjectCollection接口来实现这一点:
示例项目的AddJumpListTasks()函数创建了四个任务,如文章开头的屏幕截图所示。每个任务的创建方式相同,通过创建一个ShellLink对象并查询一个IShellLink接口,然后调用相应的IShellLink方法。每个任务有五个属性,其中四个属性通过IShellLink方法设置:
最后一个属性,即在任务列表项中显示的文本,是通过查询ShellLink对象的IPropertyStore接口并设置PKEY_Title属性来设置的。
让看看如何创建一个任务。如果曾经处理过快捷方式,这应该很熟悉,快捷方式也使用IShellLink。为了简单起见,这里所有的值都是硬编码的,但示例项目的AddJumpListTasks()查询了一些公共数据(如可执行文件路径),并为每个任务调用一次AddJumpListTask()。
bool AddJumpListTask(IObjectCollection* pObjColl) {
CComPtr pLink;
pLink.CoCreateInstance(CLSID_ShellLink);
TCHAR szExePath[MAX_PATH];
GetModuleFileName(NULL, szExePath, _countof(szExePath));
pLink->SetPath(szExePath);
pLink->SetArguments(_T("/r"));
pLink->SetIconLocation(szExePath, -IDI_RED);
pLink->SetDescription(_T("Run the clock with red text"));
CComQIPtr pPropStore = pLink;
PROPVARIANT pv;
InitPropVariantFromString(L"Red Text", &pv);
pPropStore->SetValue(PKEY_Title, pv);
PropVariantClear(&pv);
pPropStore->Commit();
pObjColl->AddObject(pLink);
}
创建分隔符
任务列表中还可以放置一个分隔符。可以在Green Text和Random Colors项之间看到一个分隔符:
在Windows 7 Beta版本中,分隔符非常小,不会占用任务列表中的全高槽。然而,在RC版本中,线条更宽,分隔符周围有更多的垂直空间:
分隔符基本上是一个任务,其ShellLink有一个属性将其标记为分隔符。所有其他方面都与常规任务相同,即创建一个ShellLink对象并将其添加到对象集合中。要创建分隔符,只需要做一件事:将ShellLink的PKEY_AppUserModel_IsDestListSeparator属性设置为TRUE:
bool AddJumpListSeparator(IObjectCollection* pObjColl) {
CComPtr pLink;
pLink.CoCreateInstance(CLSID_ShellLink);
CComQIPtr pPropStore = pLink;
PROPVARIANT pv;
InitPropVariantFromBoolean(TRUE, &pv);
pPropStore->SetValue(PKEY_AppUserModel_IsDestListSeparator, pv);
PropVariantClear(&pv);
pPropStore->Commit();
pObjColl->AddObject(pLink);
}
就是这样!请注意,Windows将在任务列表的开头和结尾检查分隔符并删除它们。它还将多个连续的分隔符合并为一个。