Windows 7程序开发系列之二(JumpList篇2 - Destination)

JumpList中除了有User Task外,还有Destination。与User Task不同,Destination中是与该程序相关联的文件的链接。Destination还可以分类,Windows已经自动为我们管理了“最近“和“常用“两个类别。比如记事本程序,使用“最近”这个类别:

       这对于大多数程序已经足够。但Windows也为我们提供了管理自己的类别的接口。程序可以根据自己的需要,添加自己的类别。本节将介绍如何将自己的类别加入JumpList。

一、向 JumpList中加入自定义类别

     首先来定义一些准备要放入JumpList的文件:

[cpp]  view plain copy
  1. LPCTSTR szFiles[] = {  
  2.     TEXT("TestFile1.txt"),  
  3.     TEXT("TestFile2.txt"),   
  4.     TEXT("TestFile3.txt")  
  5. };  

     响应按键消息,当按下“j”的时候,创建JumpList。

[cpp]  view plain copy
  1. case WM_CHAR:  
  2.     switch(wParam)  
  3.     {  
  4.     case 'j':  
  5.         CreateJumpList();  
  6.         break;  
  7.     }  
  8.     break;  

[cpp]  view plain copy
  1. //创建Destination List  
  2. void CreateJumpList()   
  3. {  
  4.     //创建文件  
  5.     for (int i = 0; i < ARRAYSIZE(szFiles); ++i)  
  6.     {  
  7.         CreateFile(szFiles[i], GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);  
  8.     }  
  9.     //JumpList  
  10.     ICustomDestinationList *pCDL = NULL;  
  11.     HRESULT hr = CoCreateInstance(CLSID_DestinationList, NULL,   
  12.         CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pCDL));  
  13.     if(SUCCEEDED(hr))  
  14.     {  
  15.         //BeginList  
  16.         UINT uMaxSlots;  
  17.         IObjectArray *pOARemoved = NULL;  
  18.         hr = pCDL->BeginList(&uMaxSlots, IID_PPV_ARGS(&pOARemoved));  
  19.         if (SUCCEEDED(hr))  
  20.         {  
  21.             //ObjectCollection  
  22.             IObjectCollection *pOC = NULL;  
  23.             hr = CoCreateInstance(CLSID_EnumerableObjectCollection, NULL,  
  24.                 CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pOC));  
  25.             if(SUCCEEDED(hr))  
  26.             {  
  27.                 //每个文件分别创建ShellItem  
  28.                 for(int i = 0; i < ARRAYSIZE(szFiles); ++i)  
  29.                 {  
  30.                     //拼接文件路径  
  31.                     WCHAR pszPath[MAX_PATH];  
  32.                     WCHAR pszCurDir[MAX_PATH];  
  33.                     GetCurrentDirectory(ARRAYSIZE(pszCurDir), pszCurDir);  
  34.                     PathCombine(pszPath, pszCurDir, szFiles[i]);  
  35.                     //根据文件路径创建ShellItem  
  36.                     IShellItem *pSI = NULL;  
  37.                     hr = SHCreateItemFromParsingName(pszPath, NULL, IID_PPV_ARGS(&pSI));  
  38.                     if (SUCCEEDED(hr))  
  39.                     {  
  40.                         pOC->AddObject(pSI);  
  41.                         pSI->Release();  
  42.                     }  
  43.                 }  
  44.                 IObjectArray *pOA = NULL;  
  45.                 hr = pOC->QueryInterface(IID_PPV_ARGS(&pOA));  
  46.                 if (SUCCEEDED(hr))  
  47.                 {  
  48.                     //将自定义Category加入JumpList  
  49.                     pCDL->AppendCategory(TEXT("My Custom Category"), pOA);  
  50.                     pOA->Release();  
  51.                 }  
  52.                 hr = pCDL->CommitList();  
  53.                 pOC->Release();  
  54.             }  
  55.             pOARemoved->Release();  
  56.         }  
  57.         pCDL->Release();  
  58.     }  
  59. }  

     上面的代码首先在当前文件夹内,将上面定义的几个文件创建出来。然后其他的步骤与创建User Task类似。不过中途向IObejctCollection 接口中加入的是IShellItem 接口,而不是IShellLink 接口。创建IShellItem 接口时,先取得文件的完整路径,然后使用API函数SHCreateItemFromParsingName 创建。取得IObjectArray 接口后调用AppendCategory将自定义的类别加入JumpList。

     执行上面程序,在窗口上按“j”。没有作用,效果没有达到。前面提到过,Destination中的文件是与我们的应用程序关联的文件。我们加入的是3个txt文件,而我们的应用程序目前并没有与txt文件关联。下面还有一些工作要做。

二、Application ID

      首先要提一下AppID,它是一个字符串,Windows用它来标识一个程序。在缺省的情况下,我们的程序不需要设置AppID,Windows会自动为我们生成和管理AppID。但是在某些情况下,我们自己管理AppID更好,比如上面提到的文件关联。只有与我们的程序关联的文件才会显示到Destination中。Windows7中,任务栏按钮的分组也是以AppID为依据的,具有相同AppID的窗口,他们的任务栏按钮会被分为一组,即使它们由不同的程序创建。反之,具有不同AppID的窗口,即使她们是由同一个程序创建,它们的任务栏按钮也不会被分到一组中。下面我们来做一下这个实验:

       1.为应用程序设置AppID。API函数SetCurrentProcessExplicitAppUserModelID 用于设置应用程序的AppID(函数名字稍微有点长)。

       2.为窗口设置AppID。窗口缺省的AppID与创建它的应用程序相同。因此,由同一个程序创建的两个窗口,在任务栏中会被归为一组(前提是这两个窗口都具有任务栏按钮)。如果我们为窗口设置不同的AppID,这两个窗口就不会被归为一组。设置窗口的AppID没有直接的API函数。与设置IShellLink 接口的title一样,需要用到IPropertyStore 这个接口。编写下面的函数,用于设置窗口的AppID。

[cpp]  view plain copy
  1. void SetWndAppID( HWND hWnd, LPCTSTR szAppID )  
  2. {  
  3.     IPropertyStore *pPS = NULL;  
  4.     HRESULT hr = SHGetPropertyStoreForWindow(hWnd, IID_PPV_ARGS(&pPS));  
  5.     if(SUCCEEDED(hr))  
  6.     {  
  7.         PROPVARIANT pv;  
  8.         if(szAppID != NULL)  
  9.         {  
  10.             hr = InitPropVariantFromString(szAppID, &pv);  
  11.         }  
  12.         else  
  13.         {  
  14.             PropVariantInit(&pv);  
  15.         }  
  16.         if(SUCCEEDED(hr))  
  17.         {  
  18.             hr = pPS->SetValue(PKEY_AppUserModel_ID, pv);  
  19.             if(SUCCEEDED(hr))  
  20.             {  
  21.                 pPS->Commit();  
  22.             }  
  23.             PropVariantClear(&pv);  
  24.         }  
  25.         pPS->Release();  
  26.     }  
  27. }  

       该函数接受一个窗口句柄和AppID(字符串)。通过API函数SHGetPropertyStoreForWindow 取得IPropertyStore接口。通过字符串初始化一个PropVariant ,然后将其设置为AppID。

       新建一个Windows程序,在其中创建两个窗口,最好都是overlappped窗口,这样的窗口在任务栏中会有按钮。在没有为窗口设置AppID的情况下,两个窗口的任务栏按钮被合并为一组(前提是打开了Windows7的任务栏按钮合并)。

任务栏按钮被合并:

如果我们为窗口设置不同的 AppID:

[cpp]  view plain copy
  1. LPCTSTR APP_ID[] = {  
  2.     TEXT("wilford.TestAppID.ID"),  
  3.     TEXT("wilford.TestAppID.ID1"),   
  4.     TEXT("wilford.TestAppID.ID2")  
  5. };  

[cpp]  view plain copy
  1. SetWndAppID(g_hWnd1, APP_ID[1]);  
  2. SetWndAppID(g_hWnd2, APP_ID[2]);  

任务栏按钮不会被分组:

三、将文件类型与AppID关联

      文件关联是通过注册表来实现的,所要设置的项较多,我使用了一些辅助的函数(这些代码来自Microsoft的教程),用来完成这些工作。如何操作注册表不是本篇的课题,因此就不作讲解了,在文末的代码下载中会提供这些辅助代码,下面只说一下需要设置哪些键值。

      1.在注册表中注册AppID。通过下面的注册表导出文件的内容,我们可以看到注册一个AppID所需要的注册表结构。

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT/Wilford.JumpList2]
"FriendlyTypeName"="Custom Jump List Document"

[HKEY_CLASSES_ROOT/Wilford.JumpList2/CurVer]
@="Wilford.JumpList2"

[HKEY_CLASSES_ROOT/Wilford.JumpList2/DefaultIcon]
@="c://Users//wilford//Documents//Visual Studio 2008//Projects//Course//JumpList2//Debug//JumpList2.exe,0"

[HKEY_CLASSES_ROOT/Wilford.JumpList2/shell]
@="Open"

[HKEY_CLASSES_ROOT/Wilford.JumpList2/shell/Open]

[HKEY_CLASSES_ROOT/Wilford.JumpList2/shell/Open/Command]
@="c://Users//wilford//Documents//Visual Studio 2008//Projects//Course//JumpList2//Debug//JumpList2.exe %1"

        2.将文件类型与AppID关联。这里将.txt类型的文件与我们上面创建的AppID相关联。

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT/.txt/OpenWithProgids]
"Wilford.JumpList2"=hex(0):

        在程序中加入注册AppID的代码,当按下“r”键时,注册AppID。当然如果不在程序中做,而是直接导入上面的注册表文件,也是可以的,对应的程序路径需要改一下。

[cpp]  view plain copy
  1. case 'r':  
  2.     if (!FileRegistration::AreFileExtensionsRegistered(APP_ID))  
  3.     {  
  4.         if (E_ACCESSDENIED == FileRegistration::RegisterFileExtensions(  
  5.             APP_ID, szExt, ARRAYSIZE(szExt)))  
  6.         {  
  7.             MessageBox(g_hWnd, TEXT("Access Denied!"), TEXT("Error"), MB_OK | MB_ICONERROR);  
  8.         }  
  9.     }  
  10.     break;  

        现在再重新创建JumpList,可以看到应有的效果了。

 

Windows7程序开发系列就到这里了。以后如果还有新的研究,会发新的教程上来。

 

本节源代码

Application ID演示代码 


原文链接:http://blog.csdn.net/ntwilford/article/details/5648781

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值