Windows 7程序开发系列之二(JumpList篇2 - Destination)
2015-06-03 12:22
525 查看
JumpList中除了有User Task外,还有Destination。与User Task不同,Destination中是与该程序相关联的文件的链接。Destination还可以分类,Windows已经自动为我们管理了“最近“和“常用“两个类别。比如记事本程序,使用“最近”这个类别:
这对于大多数程序已经足够。但Windows也为我们提供了管理自己的类别的接口。程序可以根据自己的需要,添加自己的类别。本节将介绍如何将自己的类别加入JumpList。
首先来定义一些准备要放入JumpList的文件:
[cpp] view
plaincopy
LPCTSTR szFiles[] = {
TEXT("TestFile1.txt"),
TEXT("TestFile2.txt"),
TEXT("TestFile3.txt")
};
响应按键消息,当按下“j”的时候,创建JumpList。
[cpp] view
plaincopy
case WM_CHAR:
switch(wParam)
{
case 'j':
CreateJumpList();
break;
}
break;
[cpp] view
plaincopy
//创建Destination List
void CreateJumpList()
{
//创建文件
for (int i = 0; i < ARRAYSIZE(szFiles); ++i)
{
CreateFile(szFiles[i], GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
}
//JumpList
ICustomDestinationList *pCDL = NULL;
HRESULT hr = CoCreateInstance(CLSID_DestinationList, NULL,
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pCDL));
if(SUCCEEDED(hr))
{
//BeginList
UINT uMaxSlots;
IObjectArray *pOARemoved = NULL;
hr = pCDL->BeginList(&uMaxSlots, IID_PPV_ARGS(&pOARemoved));
if (SUCCEEDED(hr))
{
//ObjectCollection
IObjectCollection *pOC = NULL;
hr = CoCreateInstance(CLSID_EnumerableObjectCollection, NULL,
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pOC));
if(SUCCEEDED(hr))
{
//每个文件分别创建ShellItem
for(int i = 0; i < ARRAYSIZE(szFiles); ++i)
{
//拼接文件路径
WCHAR pszPath[MAX_PATH];
WCHAR pszCurDir[MAX_PATH];
GetCurrentDirectory(ARRAYSIZE(pszCurDir), pszCurDir);
PathCombine(pszPath, pszCurDir, szFiles[i]);
//根据文件路径创建ShellItem
IShellItem *pSI = NULL;
hr = SHCreateItemFromParsingName(pszPath, NULL, IID_PPV_ARGS(&pSI));
if (SUCCEEDED(hr))
{
pOC->AddObject(pSI);
pSI->Release();
}
}
IObjectArray *pOA = NULL;
hr = pOC->QueryInterface(IID_PPV_ARGS(&pOA));
if (SUCCEEDED(hr))
{
//将自定义Category加入JumpList
pCDL->AppendCategory(TEXT("My Custom Category"), pOA);
pOA->Release();
}
hr = pCDL->CommitList();
pOC->Release();
}
pOARemoved->Release();
}
pCDL->Release();
}
}
上面的代码首先在当前文件夹内,将上面定义的几个文件创建出来。然后其他的步骤与创建User Task类似。不过中途向IObejctCollection 接口中加入的是IShellItem 接口,而不是IShellLink 接口。创建IShellItem 接口时,先取得文件的完整路径,然后使用API函数SHCreateItemFromParsingName 创建。取得IObjectArray 接口后调用AppendCategory将自定义的类别加入JumpList。
执行上面程序,在窗口上按“j”。没有作用,效果没有达到。前面提到过,Destination中的文件是与我们的应用程序关联的文件。我们加入的是3个txt文件,而我们的应用程序目前并没有与txt文件关联。下面还有一些工作要做。
首先要提一下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
plaincopy
void SetWndAppID( HWND hWnd, LPCTSTR szAppID )
{
IPropertyStore *pPS = NULL;
HRESULT hr = SHGetPropertyStoreForWindow(hWnd, IID_PPV_ARGS(&pPS));
if(SUCCEEDED(hr))
{
PROPVARIANT pv;
if(szAppID != NULL)
{
hr = InitPropVariantFromString(szAppID, &pv);
}
else
{
PropVariantInit(&pv);
}
if(SUCCEEDED(hr))
{
hr = pPS->SetValue(PKEY_AppUserModel_ID, pv);
if(SUCCEEDED(hr))
{
pPS->Commit();
}
PropVariantClear(&pv);
}
pPS->Release();
}
}
该函数接受一个窗口句柄和AppID(字符串)。通过API函数SHGetPropertyStoreForWindow 取得IPropertyStore接口。通过字符串初始化一个PropVariant ,然后将其设置为AppID。
新建一个Windows程序,在其中创建两个窗口,最好都是overlappped窗口,这样的窗口在任务栏中会有按钮。在没有为窗口设置AppID的情况下,两个窗口的任务栏按钮被合并为一组(前提是打开了Windows7的任务栏按钮合并)。
任务栏按钮被合并:
如果我们为窗口设置不同的 AppID:
[cpp] view
plaincopy
LPCTSTR APP_ID[] = {
TEXT("wilford.TestAppID.ID"),
TEXT("wilford.TestAppID.ID1"),
TEXT("wilford.TestAppID.ID2")
};
[cpp] view
plaincopy
SetWndAppID(g_hWnd1, APP_ID[1]);
SetWndAppID(g_hWnd2, APP_ID[2]);
任务栏按钮不会被分组:
文件关联是通过注册表来实现的,所要设置的项较多,我使用了一些辅助的函数(这些代码来自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
plaincopy
case 'r':
if (!FileRegistration::AreFileExtensionsRegistered(APP_ID))
{
if (E_ACCESSDENIED == FileRegistration::RegisterFileExtensions(
APP_ID, szExt, ARRAYSIZE(szExt)))
{
MessageBox(g_hWnd, TEXT("Access Denied!"), TEXT("Error"), MB_OK | MB_ICONERROR);
}
}
break;
现在再重新创建JumpList,可以看到应有的效果了。
Windows7程序开发系列就到这里了。以后如果还有新的研究,会发新的教程上来。
本节源代码
Application ID演示代码
原文链接:http://blog.csdn.net/ntwilford/article/details/5648781
这对于大多数程序已经足够。但Windows也为我们提供了管理自己的类别的接口。程序可以根据自己的需要,添加自己的类别。本节将介绍如何将自己的类别加入JumpList。
一、向 JumpList中加入自定义类别
首先来定义一些准备要放入JumpList的文件:[cpp] view
plaincopy
LPCTSTR szFiles[] = {
TEXT("TestFile1.txt"),
TEXT("TestFile2.txt"),
TEXT("TestFile3.txt")
};
响应按键消息,当按下“j”的时候,创建JumpList。
[cpp] view
plaincopy
case WM_CHAR:
switch(wParam)
{
case 'j':
CreateJumpList();
break;
}
break;
[cpp] view
plaincopy
//创建Destination List
void CreateJumpList()
{
//创建文件
for (int i = 0; i < ARRAYSIZE(szFiles); ++i)
{
CreateFile(szFiles[i], GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
}
//JumpList
ICustomDestinationList *pCDL = NULL;
HRESULT hr = CoCreateInstance(CLSID_DestinationList, NULL,
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pCDL));
if(SUCCEEDED(hr))
{
//BeginList
UINT uMaxSlots;
IObjectArray *pOARemoved = NULL;
hr = pCDL->BeginList(&uMaxSlots, IID_PPV_ARGS(&pOARemoved));
if (SUCCEEDED(hr))
{
//ObjectCollection
IObjectCollection *pOC = NULL;
hr = CoCreateInstance(CLSID_EnumerableObjectCollection, NULL,
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pOC));
if(SUCCEEDED(hr))
{
//每个文件分别创建ShellItem
for(int i = 0; i < ARRAYSIZE(szFiles); ++i)
{
//拼接文件路径
WCHAR pszPath[MAX_PATH];
WCHAR pszCurDir[MAX_PATH];
GetCurrentDirectory(ARRAYSIZE(pszCurDir), pszCurDir);
PathCombine(pszPath, pszCurDir, szFiles[i]);
//根据文件路径创建ShellItem
IShellItem *pSI = NULL;
hr = SHCreateItemFromParsingName(pszPath, NULL, IID_PPV_ARGS(&pSI));
if (SUCCEEDED(hr))
{
pOC->AddObject(pSI);
pSI->Release();
}
}
IObjectArray *pOA = NULL;
hr = pOC->QueryInterface(IID_PPV_ARGS(&pOA));
if (SUCCEEDED(hr))
{
//将自定义Category加入JumpList
pCDL->AppendCategory(TEXT("My Custom Category"), pOA);
pOA->Release();
}
hr = pCDL->CommitList();
pOC->Release();
}
pOARemoved->Release();
}
pCDL->Release();
}
}
上面的代码首先在当前文件夹内,将上面定义的几个文件创建出来。然后其他的步骤与创建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
plaincopy
void SetWndAppID( HWND hWnd, LPCTSTR szAppID )
{
IPropertyStore *pPS = NULL;
HRESULT hr = SHGetPropertyStoreForWindow(hWnd, IID_PPV_ARGS(&pPS));
if(SUCCEEDED(hr))
{
PROPVARIANT pv;
if(szAppID != NULL)
{
hr = InitPropVariantFromString(szAppID, &pv);
}
else
{
PropVariantInit(&pv);
}
if(SUCCEEDED(hr))
{
hr = pPS->SetValue(PKEY_AppUserModel_ID, pv);
if(SUCCEEDED(hr))
{
pPS->Commit();
}
PropVariantClear(&pv);
}
pPS->Release();
}
}
该函数接受一个窗口句柄和AppID(字符串)。通过API函数SHGetPropertyStoreForWindow 取得IPropertyStore接口。通过字符串初始化一个PropVariant ,然后将其设置为AppID。
新建一个Windows程序,在其中创建两个窗口,最好都是overlappped窗口,这样的窗口在任务栏中会有按钮。在没有为窗口设置AppID的情况下,两个窗口的任务栏按钮被合并为一组(前提是打开了Windows7的任务栏按钮合并)。
任务栏按钮被合并:
如果我们为窗口设置不同的 AppID:
[cpp] view
plaincopy
LPCTSTR APP_ID[] = {
TEXT("wilford.TestAppID.ID"),
TEXT("wilford.TestAppID.ID1"),
TEXT("wilford.TestAppID.ID2")
};
[cpp] view
plaincopy
SetWndAppID(g_hWnd1, APP_ID[1]);
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
plaincopy
case 'r':
if (!FileRegistration::AreFileExtensionsRegistered(APP_ID))
{
if (E_ACCESSDENIED == FileRegistration::RegisterFileExtensions(
APP_ID, szExt, ARRAYSIZE(szExt)))
{
MessageBox(g_hWnd, TEXT("Access Denied!"), TEXT("Error"), MB_OK | MB_ICONERROR);
}
}
break;
现在再重新创建JumpList,可以看到应有的效果了。
Windows7程序开发系列就到这里了。以后如果还有新的研究,会发新的教程上来。
本节源代码
Application ID演示代码
原文链接:http://blog.csdn.net/ntwilford/article/details/5648781
相关文章推荐
- 禁止 IOS 系统 数字 变超链 (自动识别为电话号码)
- c++学习二
- UITableView 基本使用方法总结
- 讲解JavaScript中for...in语句的使用方法
- [Erlang]erlang与php的通信
- UITableView 基本使用方法总结
- IOS——UITextField被键盘遮蔽解决方案
- Android常用自定义控件
- Linux应用程序学习之制作静态函数库
- php操作memcache缓存方法分享
- C++学习一
- 设置linux终端字符颜色
- 重要的是你心甘情愿
- 卡特兰数问题
- 最爱 《弹痕》 mobi 分享
- Windows 7程序开发系列之二(JumpList篇1 - User Task)
- JavaScript中for循环的使用详解
- 安卓开发前期所有准备
- Windows 7程序开发系列之一(任务栏篇)
- android的m、mm、mmm编译命令的使用