Windows文件检索之——查询范围

对于检索范围来说,也是比较简单的,根据第一节,我们知道,ISearcherFolderFactory提供了一个方法SetScope,就是让用户传一个IShellItemArray的指针进去。所以,我们主要的工作就是如何来创建IShellItemArray接口指针。

1.如何创建IShellItemArray

Shell API提供了一个方法,SHCreateShellItemArrayFromIDLists,根据PIDL列表来创建IShellItemArray接口指针,所以,我们的工作就是如何创建出这些PIDL。
我们知道,当用户去检索时,在设置检索范围时,他最大的可能是设置一个文件夹路径,如C:\FolderA,也有可能根据一些固定的文件夹,如Windows Librayr,所以,我们设计的类SdkQueryScope至少要提供一种服务,就是把一个或多个路径或特殊文件夹转换成PIDL,然后用这些PIDL去创建一个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的设计

对于我们封装的这个类来说,它本质上就把用户的一些输入转换成一个IShellItemArray指针,以供ISearchFolderItemFactory接口使用,所以我们很容易抽象出它的输出就是一个IShellItemArray*,那它的输入是什么呢?

我们想想,对于用户的输入有哪些?

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





  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值