Windows 7介紹了一種庫的新概念,用戶數據的新的入口點。用戶可以輕松的以集合數據 的方式,找到並且管理他們的數據,而且這些數據可能是在計算機中的多個不同的位置。這 個庫代替了早期Windows版本中的固有文件夾(比如,我的文檔,圖片,音樂),並且把它 們都放入了主“storage”。Shell庫的 API,提供給應用程序一種簡單的方法來對該庫進行 交互操作。應用程序可以創建,交互並且像他們的環境中的一級元素一樣支持該庫。
在Windows 7中,Shell庫的概念就是,通過允許他們對其文檔庫文件夾結構的全部控制 權限,試圖去解決用戶在他們的PC上,到處存放數據的問題。換而言之,在 Windows 7中, 用戶可以在文檔庫中來定義哪個文件夾用來存放。我們也可以說,Shell庫是一種用戶自定 義的,合理的代表用戶數據的文件夾集合。在庫中所包含的文件夾,其實就是用戶告訴了 Windows,他的或者她的重要數據在哪裡存放。那麼系統將為這些文件夾進行索引,來更快 的查詢檢索、在基於文件屬性和元數據的Windows Explorer中具有更豐富的視圖展示能力。
在早期的Windows版本中,每一個應用程序都有其屬於自己的屬性庫。比如,Windows Media Player與iTunes相比,擁有不同的作用域集合,並且兩者都不是與Music文件夾一致 的。使用Shell庫的API,應用程序就可以定義並且共同使用用戶自定義的那個區域。
Shell庫中同樣也可以包含網絡文件夾。這個功能將給用戶無論是在家還是在單位,都有 一個很好的用戶體驗。無論何時用戶打開一個文件對話框,他就能獲得所有可用的庫的指向 的集合視圖。
注意 :了解更多信息,請參看Inside Windows 7: Introducing Libraries,和 Windows 7 Programming Guide - Libraries
目標
在本次動手實驗中,你將 了解到如何用編程的方式管理庫,包括如何:
• 創建新的庫
• 打開現有的庫
• 在庫中進行添加和刪除 文件夾
• 獲取和解析庫文件夾列表
• 刪除庫
• 重命 名庫
• 為庫設置一個默認保存文件夾
• 設置庫的屬性,比如文件 夾類型,圖標,鎖定到導航欄的狀態等
• 顯示"manage user interface"對話 框
系統需求
完成本實驗,你需要有以下組件:
• Microsoft Visual Studio 2008 SP1
• Windows 7
• Windows 7 SDK
練習: 開發 SLUtil
Shell庫實用工具(SLUtil)是一個用 來管理在默認的庫目錄下的庫的命令行工具。
SLUtil 命令:
命令提示
SLUtil ? [CommandName]
SLUtil Create LibraryName
SLUtil AddFolder LibraryName FolderPath
SLUtil RemoveFolder LibraryName FolderPath
SLUtil Delete LibraryName
SLUtil Rename OldName NewName
SLUtil SaveFolder LibraryName [FolderPath]
SLUtil NavPanePinnedState LibraryName [TRUE|FALSE]
SLUtil Icon LibraryName [Icon]
SLUtil FolderType LibraryName [Documents|Pictures|Music|Videos|Generic]
SLUtil ListFolders LibraryName
SLUtil ManageUI LibraryName [Title] [Instruction]
任務 1 – 創建 SLUtil 項目
1.開啟 Visual Studio 2008 並且選擇 C++ Win32 控制台應用程序。
a.輸入SLUtil作為新項目的名稱。
b.保持默認配置。
2.添加CommandLineInterpreter.h和CommandLineInterpreter.cpp文件。你可以在 Starter文件夾中找到這兩個文件。你需要使用Command宏,向命令行解釋器中添加命令。
3.使用Starter文件夾中包含必要的#include代碼的stdafx.h文件來替換現有項目中的 stdafx.h文件。
4.為了支持Windows 7 API,請將targetver.h文件中的_WIN32_WINNT更改為0x0601。
5.如果要使用命令行解釋器,直接在SLUtil.cpp文件中的#include "stdafx.h"下,添加 #include "CommandLineInterpreter.h"。
6.更改主方法來調用命令行解釋器的執行函數。你同樣需要初始化COM:
注意 :命令行解釋器是一個實用工具類,它知道如何翻譯命令行和其已經注冊了的 Command宏的執行函數
C++ (SLUtil.cpp)
#include "stdafx.h"
#include "CommandLineInterpreter.h"
int _tmain(int argc, _TCHAR* argv[])
{
//Initiate COM
CoInitialize(NULL);
CCommandLineInterpreter::Execute(argc, argv);
CoUninitialize();
return 0;
}
7.編譯該程序。
8.想要測試當前應用程序的狀態,在項目屬性中的調試框中,添加命令行變量。
9.執行該應用程序。你應該能得到下面的輸出結果:
注意 :
SLUtil ? [CommandName]
Press any key to continue ...
任務 2 –添加創建命令
對Shell庫進行編程,我們不但需要使用IshellLibrary接口,而且還需要比如 IShelItem, IShelItem2, 和 IshellItemArray之類的其他Shell接口。他們都在shobjidl.h 的頭文件中定義好了。這個頭文件同樣包含了一些Shell庫幫助方法,當有一些普通的Shell 庫操作,比如創建Shell庫COM對象或者讀取Shell庫時,這些方法將保存一些代碼。舉例說 明,下面的代碼就是 shobjidl.h文件中的一個片段:
C++ (from shobjidl.h)
__inline HRESULT SHCreateLibrary(__in REFIID riid, __deref_out void **ppv)
{
return CoCreateInstance(CLSID_ShellLibrary, NULL, CLSCTX_INPROC_SERVER,
riid, ppv);
}
1.向SLUtil.cpp文件中添加下面的代碼:
C++ (SlUtil.cpp)
//Create a new shell library
void CreateLibrary(const CCommand &command, const vector<PCWSTR> &arguments)
{
IShellLibrary *shellLibrary = NULL;
IShellItem *savedTo = NULL;
//Create the shell library COM object
HRESULT hr = SHCreateLibrary(IID_PPV_ARGS(&shellLibrary));
if (FAILED(hr))
{
wcerr << L"Create: Can't create Shell Library COM object." << endl;
exit(4);
}
//Save the new library under the user's Libraries folder.
//If a library with the same name is already exists, add a number to the
//name to create unique name
hr = shellLibrary->SaveInKnownFolder(FOLDERID_UsersLibraries, arguments[0],
LSF_MAKEUNIQUENAME, &savedTo);
if (FAILED(hr))
{
wcerr << L"Create: Can't create Shell Library." << endl;
exit(5);
}
if (shellLibrary != NULL)
shellLibrary->Release();
if (savedTo != NULL)
savedTo->Release();
}
COMMAND(L"Create", L"SLUtil Create LibraryName", L"Create a new library",
L"SLUtil Create MyLib", 1, CreateLibrary);
2.編譯並執行。
3.將命令行變量更改為:Create MyLib。
4.運行該應用程序,並且檢查驗證你創建的新的庫。
任務 3 –添加AddFolder 和RemoveFolder 命令
在一個存在的庫中,添加或刪除一個文件夾,我們需要重新打開這個庫。許多命令都需 要重新打開庫,所以我們需要創建兩個幫助方法(注意:在本次動手實驗中,我們只涉及用 戶庫的位置)。
1.向SLUtil.cpp文件中添加下面的代碼:
C++ (SLUtil.cpp)
// Get the library COM object and the full path of a library.
// If shellLibrary is NULL, don't return it.
// If libraryFullPath is NULL, don't return it.
// Call relese on the shellLibrary object.Call CoTaskMemFree on the
// libraryFullPath
HRESULT GetLibraryFromLibrariesFolder(PCWSTR libraryName, IShellLibrary **shellLibrary, bool openRead = true, PWSTR *libraryFullPath = NULL)
{
//Create the real library file name
wstring realLibraryName(libraryName);
realLibraryName += L".library-ms";
IShellItem2 *shellItem = NULL;
//Get the shell item that represent the library
HRESULT hr = SHCreateItemInKnownFolder (FOLDERID_UsersLibraries,
KF_FLAG_DEFAULT_PATH|KF_FLAG_NO_ALIAS , realLibraryName.c_str(),
IID_PPV_ARGS (&shellItem));
if (FAILED(hr))
{
return hr;
}
//In case a file-system full path is needed
//extract the information from the Shell Item ParsingPath property
if (libraryFullPath != NULL)
{
hr = shellItem->GetString(PKEY_ParsingPath, libraryFullPath);
}
//Get the shellLibrary object from the shell item with a read/write
//permitions
if (shellLibrary != NULL)
{
hr = SHLoadLibraryFromItem(shellItem, openRead ?
STGM_READ : STGM_READWRITE, IID_PPV_ARGS (shellLibrary));
}
if (shellItem != NULL)
shellItem- >Release();
return hr;
}
//Open an existing library
IShellLibrary *OpenLibrary(PCWSTR commandName, PCWSTR libraryName,
bool openRead = true)
{
IShellLibrary *shellLibrary = NULL;
HRESULT hr = GetLibraryFromLibrariesFolder(libraryName, &shellLibrary,
openRead);
if (FAILED(hr))
{
wcerr << commandName << L": Can't load library." << endl;
exit(4);
}
return shellLibrary;
}
2.現在,我們來添加AddFolder 和 RemoveFolder命令。向SLUtil.cpp文件中添加下面的 代碼:
C++ (SLUtil.cpp)
//Add a folder to a library
void AddFolder(const CCommand &command, const vector<PCWSTR> &arguments)
{
IShellLibrary *shellLibrary = OpenLibrary (L"AddFolder", arguments[0],
false);
HRESULT hr = SHAddFolderPathToLibrary (shellLibrary, arguments[1]);
if (FAILED(hr))
{
wcerr << L"AddFolder: Can't add folder to the library." << endl;
exit(6);
}
//Commit the library changes
shellLibrary->Commit();
if (shellLibrary != NULL)
shellLibrary->Release();
}
COMMAND(L"AddFolder", L"SLUtil AddFolder LibraryName FolderPath",
L"Add a folder to a library", L"SLUtil AddFolder Documents C:\\Docs",
2, AddFolder);
//Remove a folder from a library
void RemoveFolder(const CCommand &command, const vector<PCWSTR> &arguments)
{
IShellLibrary *shellLibrary = OpenLibrary (L"RemoveFolder",
arguments[0], false);
HRESULT hr = SHRemoveFolderPathFromLibrary(shellLibrary, arguments[1]);
if (FAILED(hr))
{
wcerr << L"RemoveFolder: Can't remove folder from the library."
<< endl;
exit(5);
}
//Commit the library changes
shellLibrary->Commit();
if (shellLibrary != NULL)
shellLibrary ->Release();
}
COMMAND(L"RemoveFolder", L"SLUtil RemoveFolder LibraryName FolderPath",
L"Remove a folder from a library", L"SLUtil RemoveFolder Documents C:\\Docs",
2, RemoveFolder);