對於檢索範圍來說,也是比較簡單的,根據第一節,我們知道,ISearcherFolderFactory提供了一個方法SetScope,就是讓用戶傳一個IShellItemArray的指針進去。所以,我們主要的工作就是如何來創建IShellItemArray接口指針。
1.如何創建IShellItemArray
Shell API SHGetKnownFolderIDList、SHGetIDListFromObject都可以得到一個PIDL。
1、SHGetKnownFolderIDList:根據Known folder id創建一個PIDL,比如:FOLDERID_MusicLibrary、FOLDERID_DocumentsLibrary等,這些定義可以從MSDN上面找到。
2、SHGetIDListFromObject:就是根據一個IShellItem創建一個PIDL。而這些IShellItem從哪裏來?可以用SHCreateItemFromParsingName API來創建,根據路徑解析,生成一個IShellItem接口指針。
上面所說的都是怎麼創建PIDL,對於熟悉Shell的人來說,這些都很簡單。
2.關於SdkQueryScope的設計
我們想想,對於用戶的輸入有哪些?
1,文件夾路徑,可能提供多個,也就是一個WCHAR*的數組。
2,特殊文件夾的ID,如FOLDERID_MusicLibrary、FOLDERID_DocumentsLibrary等。但我們用這些ID可能很麻煩,所以需要我們定義一種對於用戶很友好的枚舉,以供用戶使用。
目前來說這兩種對於檢索來說是夠用了。 下面這張圖說明了用戶的輸入與SdkQueryScope的輸出。
注意,對於枚舉類型,用戶可能把幾種枚舉類型聯合起來,所以,對於SdkQueryScope來說,它只能接收一個INT32值,這個值可能是一些定義枚舉的聯合。
還有,由於我們定義了一種友好的枚舉來表示一個known folder id,所以,在這個類裏面就應當有一個對應的轉換關係,我在程序內部分把我們所支持的known folder id與所定義的枚舉一一映射起來,存在一個map中。
SdkQueryScope.h
#ifdef __cplusplus
#ifndef _QUERYSCOPE_H_
#define _QUERYSCOPE_H_
#include "SdkCommon.h"
typedef enum _QUERYSCOPETYPE
{
QUERY_SCOPE_NONE = 0x00000000,
QUERY_SCOPE_PICTURES = 0x00000001,
QUERY_SCOPE_MUSIC = 0x00000002,
QUERY_SCOPE_VIDEO = 0x00000004,
QUERY_SCOPE_DECUMENT = 0x00000008,
QUERY_SCOPE_PUBLIC = 0x00000010,
QUERY_SCOPE_SAMPLEMUSIC = 0x00000020,
QUERY_SCOPE_DESKTOP = 0x00000040,
QUERY_SCOPE_STARTMENU = 0x00000080,
QUERY_SCOPE_FAVORITES = 0x00000100,
QUERY_SCOPE_COMPUTER = 0x00000200,
QUERY_SCOPE_EXTERNALSTORAGE = 0x00000400,
} QUERYSCOPETYPE;
/*!
* @brief QueryScope class.
*/
class CLASS_DECLSPEC SdkQueryScope
{
public:
SdkQueryScope();
~SdkQueryScope();
HRESULT SetScope(INT32 scopeType);
HRESULT SetScope(PCWSTR *pszScopePaths, UINT32 uCount);
HRESULT GetScope(OUT IShellItemArray **ppsia);
private:
HRESULT GetScopeType(OUT vector<QUERYSCOPETYPE> &vctScopeTypes);
static void InitializeMap();
private:
typedef map <QUERYSCOPETYPE, KNOWNFOLDERID> TYPETOFOLDERIDMAP;
typedef pair<QUERYSCOPETYPE, KNOWNFOLDERID> TYPETOFOLDERIDPAIR;
INT32 m_nScopeType;
UINT32 m_uScopePathsCount;
PCWSTR *m_pszScopePaths;
static TYPETOFOLDERIDMAP s_mapTypeToFolderID;
};
#endif // _QUERYSCOPE_H_
#endif // __cplusplus
QUERYSCOPETYPE 就個枚舉就是定義的一系列特殊文件夾的值。
static void InitializeMap();這個靜態方法就是用於初始化knonw folder id到enum之間的映射關係。
HRESULT GetScopeType(OUT vector<QUERYSCOPETYPE> &vctScopeTypes); 就是根據當前的文件夾類型的值(INT32)轉換成相應的枚舉值,並存放到一個vector中。
SdkQueryScope.cpp
#include "SdkQueryScope.h"
#define MAKE_PAIR(key, value) TYPETOFOLDERIDPAIR(key, value)
#define MAKE_STRUCT(key, value) { key, value }
SdkQueryScope::TYPETOFOLDERIDMAP SdkQueryScope::s_mapTypeToFolderID;
void SdkQueryScope::InitializeMap()
{
static BOOL isFirst = TRUE;
if (!isFirst)
{
return;
}
isFirst = FALSE;
struct
{
QUERYSCOPETYPE type;
KNOWNFOLDERID folderId;
}
static const g_szKeyValuePairs[] =
{
MAKE_STRUCT(QUERY_SCOPE_PICTURES, FOLDERID_PicturesLibrary),
MAKE_STRUCT(QUERY_SCOPE_MUSIC, FOLDERID_MusicLibrary),
MAKE_STRUCT(QUERY_SCOPE_VIDEO, FOLDERID_VideosLibrary),
MAKE_STRUCT(QUERY_SCOPE_DECUMENT, FOLDERID_DocumentsLibrary),
MAKE_STRUCT(QUERY_SCOPE_FAVORITES, FOLDERID_Favorites),
MAKE_STRUCT(QUERY_SCOPE_COMPUTER, FOLDERID_ComputerFolder),
MAKE_STRUCT(QUERY_SCOPE_PUBLIC, FOLDERID_Public),
MAKE_STRUCT(QUERY_SCOPE_DESKTOP, FOLDERID_Desktop),
};
s_mapTypeToFolderID.clear();
int size = ARRAYSIZE(g_szKeyValuePairs);
for (int i = 0; i < size; ++i)
{
s_mapTypeToFolderID.insert(MAKE_PAIR(g_szKeyValuePairs[i].type,
g_szKeyValuePairs[i].folderId));
}
}
SdkQueryScope::SdkQueryScope() : m_nScopeType(0),
m_uScopePathsCount(0),
m_pszScopePaths(NULL)
{
InitializeMap();
}
SdkQueryScope::~SdkQueryScope()
{
if (NULL != m_pszScopePaths)
{
for (UINT32 i = 0; i < m_uScopePathsCount; ++i)
{
SAFE_DELETE_ARRAY(m_pszScopePaths[i]);
}
SAFE_DELETE_ARRAY(m_pszScopePaths);
}
m_uScopePathsCount = 0;
}
HRESULT SdkQueryScope::SetScope(INT32 scopeType)
{
m_nScopeType = scopeType;
return S_OK;
}
HRESULT SdkQueryScope::SetScope(PCWSTR *pszScopePaths, UINT32 uCount)
{
if ( (NULL == pszScopePaths) || (0 == uCount) )
{
return E_INVALIDARG;
}
ClearScope();
m_uScopePathsCount = uCount;
m_pszScopePaths = new PCWSTR[uCount];
memset(m_pszScopePaths, 0, uCount * sizeof(PCWSTR));
for (UINT32 i = 0; i < uCount; ++i)
{
int length = wcslen(pszScopePaths[i]);
int ccbDest = sizeof(WCHAR) * (length + 1);
int ccbSrc = sizeof(WCHAR) * length;
WCHAR *pDest = new WCHAR[length + 1];
memset(pDest, 0, ccbDest);
memcpy_s(pDest, ccbDest, pszScopePaths[i], ccbSrc);
m_pszScopePaths[i] = pDest;
}
return S_OK;
}
HRESULT SdkQueryScope::GetScope(OUT IShellItemArray **ppsia)
{
if (NULL == ppsia)
{
return E_INVALIDARG;
}
vector<PIDLIST_ABSOLUTE> vctIDLists;
vector<QUERYSCOPETYPE> vctScopeTypes;
HRESULT hr = GetScopeType(vctScopeTypes);
for each (QUERYSCOPETYPE scope in vctScopeTypes)
{
map<QUERYSCOPETYPE, KNOWNFOLDERID>::const_iterator itor =
s_mapTypeToFolderID.find(scope);
if (itor == s_mapTypeToFolderID.end())
{
continue;
}
PIDLIST_ABSOLUTE pItemID = NULL;
hr = SHGetKnownFolderIDList(itor->second, KF_FLAG_DEFAULT, NULL, &pItemID);
if (SUCCEEDED(hr))
{
vctIDLists.push_back(pItemID);
}
}
for (UINT32 i = 0; i < m_uScopePathsCount; ++i)
{
IShellItem2 *pShellItem2 = NULL;
hr = SHCreateItemFromParsingName(m_pszScopePaths[i],
NULL, IID_PPV_ARGS(&pShellItem2));
if (SUCCEEDED(hr))
{
PIDLIST_ABSOLUTE pItemID = NULL;
hr = SHGetIDListFromObject(pShellItem2, &pItemID);
if (SUCCEEDED(hr))
{
vctIDLists.push_back(pItemID);
}
}
SAFE_RELEASE(pShellItem2);
}
int idlSize = vctIDLists.size();
if (idlSize > 0)
{
PIDLIST_ABSOLUTE *rgItemIDs = new PIDLIST_ABSOLUTE[idlSize];
for (int i = 0; i < idlSize; ++i)
{
rgItemIDs[i] = vctIDLists[i];
}
IShellItemArray *psia = NULL;
hr = SHCreateShellItemArrayFromIDLists(idlSize,
(LPCITEMIDLIST*)rgItemIDs, &psia);
if (SUCCEEDED(hr))
{
hr = psia->QueryInterface(IID_PPV_ARGS(ppsia));
}
SAFE_RELEASE(psia);
for (int i = 0; i < idlSize; ++i)
{
CoTaskMemFree(rgItemIDs[i]);
}
SAFE_DELETE_ARRAY(rgItemIDs);
}
return hr;
}
HRESULT SdkQueryScope::GetScopeType(OUT vector<QUERYSCOPETYPE> &vctScopeTypes)
{
FILTER_BITVALUE(m_nScopeType, QUERY_SCOPE_PICTURES, vctScopeTypes);
FILTER_BITVALUE(m_nScopeType, QUERY_SCOPE_MUSIC, vctScopeTypes);
FILTER_BITVALUE(m_nScopeType, QUERY_SCOPE_VIDEO, vctScopeTypes);
FILTER_BITVALUE(m_nScopeType, QUERY_SCOPE_DECUMENT, vctScopeTypes);
FILTER_BITVALUE(m_nScopeType, QUERY_SCOPE_PUBLIC, vctScopeTypes);
FILTER_BITVALUE(m_nScopeType, QUERY_SCOPE_SAMPLEMUSIC, vctScopeTypes);
FILTER_BITVALUE(m_nScopeType, QUERY_SCOPE_DESKTOP, vctScopeTypes);
FILTER_BITVALUE(m_nScopeType, QUERY_SCOPE_STARTMENU, vctScopeTypes);
FILTER_BITVALUE(m_nScopeType, QUERY_SCOPE_FAVORITES, vctScopeTypes);
FILTER_BITVALUE(m_nScopeType, QUERY_SCOPE_COMPUTER, vctScopeTypes);
return S_OK;
}
上面最關鍵的就是函數GetScope類了,我就不解釋代碼了。
關於GetScopeType的實現,我用了一個宏FILTER_BITVALUE,它的定義如下:
#ifndef FILTER_BITVALUE
#define FILTER_BITVALUE(val, bit, vct) \
{ \
if (val & bit) \
{ \
vct.push_back(bit); \
} \
}
#endif // FILTER_BITVALUE