Windows文件检索之——接口设计
2013-02-26 13:29
246 查看
这一节我们讲文件检索,主要讲一讲它用到了哪些COM接口和Shell相关知识。这里,我们重点讲一讲它的本质,至于如何利用设计模式的东西去包装,用没用线程等,这里就不用讲了。我们需要的是关注本质。
其实对于熟悉Shell的人来说,Search这一部分是比较简单的。我们很幸运,由于之前做的一个项目是仅仅是运行在Windows 7之上的,所以我们这个检索模块可以不用支持Windows 7以下的OS,我们找到一个Shell接口------ISearchFolderItemFactory,我们可以利用这个接口来进行检索,严格来说没有检索,我们只是给它设置一定的Scop和一定的Condition,从而得到检索文件夹对应的PIDL(Shell的东西),然后再根据这个PIDL,来枚举它对应的Shell Item,从而根据这些Item得到其对应的文件路径,只要得到文件路径后,就可以得到我们想要的东西了。
对于我们来说,我们只需用到GetIDList、SetContion、SetScope这三个函数。下面分别对这三个函数进行一点说明。
这个函数用于得到检索文件夹的ITEMIDLIST(PIDL)。这个函数相当重要。
这个函数给当前这个Search Factory设置一个检索条件,参数是一个ICondition接口的指针,这里我们先不关注如何创建这个接口的指针,以后的小节会讲到。如果用户不调用这个方法的话,那么这个检索结果就不会有过滤。
以上就是我们要用到的三个函数及ISearchFolderItemFactory接口。
下面这张图说明了我们这SdkFileSearcher类的结构。
对于用户来说,Shell和Windows Search的接口已经被我们定义的这一层封装了。
SdkFileSearcher.h
SdkFileSearcher.cpp
下一节,我们就讲一下如何创建检索条件。
其实对于熟悉Shell的人来说,Search这一部分是比较简单的。我们很幸运,由于之前做的一个项目是仅仅是运行在Windows 7之上的,所以我们这个检索模块可以不用支持Windows 7以下的OS,我们找到一个Shell接口------ISearchFolderItemFactory,我们可以利用这个接口来进行检索,严格来说没有检索,我们只是给它设置一定的Scop和一定的Condition,从而得到检索文件夹对应的PIDL(Shell的东西),然后再根据这个PIDL,来枚举它对应的Shell Item,从而根据这些Item得到其对应的文件路径,只要得到文件路径后,就可以得到我们想要的东西了。
1.ISearchFolderItemFactory接口
ISearchFolderItemFactory : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE SetDisplayName( LPCWSTR pszDisplayName) = 0; virtual HRESULT STDMETHODCALLTYPE SetFolderTypeID( FOLDERTYPEID ftid) = 0; virtual HRESULT STDMETHODCALLTYPE SetFolderLogicalViewMode( FOLDERLOGICALVIEWMODE flvm) = 0; virtual HRESULT STDMETHODCALLTYPE SetIconSize( int iIconSize) = 0; virtual HRESULT STDMETHODCALLTYPE SetVisibleColumns( UINT cVisibleColumns, __RPC__in_ecount_full(cVisibleColumns) PROPERTYKEY *rgKey) = 0; virtual HRESULT STDMETHODCALLTYPE SetSortColumns( UINT cSortColumns, __RPC__in_ecount_full(cSortColumns) SORTCOLUMN *rgSortColumns) = 0; virtual HRESULT STDMETHODCALLTYPE SetGroupColumn( __RPC__in REFPROPERTYKEY keyGroup) = 0; virtual HRESULT STDMETHODCALLTYPE SetStacks( UINT cStackKeys, __RPC__in_ecount_full(cStackKeys) PROPERTYKEY *rgStackKeys) = 0; virtual HRESULT STDMETHODCALLTYPE SetScope( __RPC__in_opt IShellItemArray *psiaScope) = 0; virtual HRESULT STDMETHODCALLTYPE SetCondition( __RPC__in_opt ICondition *pCondition) = 0; virtual HRESULT STDMETHODCALLTYPE GetShellItem( __RPC__in REFIID riid, __RPC__deref_out_opt void **ppv) = 0; virtual HRESULT STDMETHODCALLTYPE GetIDList( __RPC__deref_out_opt PIDLIST_ABSOLUTE *ppidl) = 0; };
对于我们来说,我们只需用到GetIDList、SetContion、SetScope这三个函数。下面分别对这三个函数进行一点说明。
2. GetIDList
HRESULT GetIDList( PIDLIST_ABSOLUTE *ppidl );
这个函数用于得到检索文件夹的ITEMIDLIST(PIDL)。这个函数相当重要。
3.SetCondition
HRESULT SetCondition( ICondition *pCondition );
这个函数给当前这个Search Factory设置一个检索条件,参数是一个ICondition接口的指针,这里我们先不关注如何创建这个接口的指针,以后的小节会讲到。如果用户不调用这个方法的话,那么这个检索结果就不会有过滤。
4.SetScope
HRESULT SetScope( IShellItemArray *psiaScope );这个函数用来设置检索的范围。它的参数是一个IShellItemArray的指针,表明这是一个IShellItem的数据。我们可以很轻松的利用Shell APIs来创建这个接口指针。这里也不讲,以后会讲到的。
以上就是我们要用到的三个函数及ISearchFolderItemFactory接口。
5.SdkFileSearcher类
在这个类里面,我把检索条件抽象成了一个类SdkQueryCondition,而检索范围抽象也SdkQueryScope。还依赖一个类,SdkFileSearcherNotify,这个类定义了两个接口,用于通知用户检索完毕或检索到一条数据。下面这张图说明了我们这SdkFileSearcher类的结构。
对于用户来说,Shell和Windows Search的接口已经被我们定义的这一层封装了。
SdkFileSearcher.h
#ifdef __cplusplus #ifndef _MEDIAFILESEARCH_H_ #define _MEDIAFILESEARCH_H_ #include <process.h> #include "SdkCommon.h" #include "SdkQueryCondition.h" #include "SdkQueryScope.h" #include "SdkFileSearcherNotify.h" class CLASS_DECLSPEC SdkFileSearcher { public: SdkFileSearcher(); ~SdkFileSearcher(); HRESULT SetCondition(INT32 queryKind); HRESULT SetCondition(LPCWSTR *ppszQuerys, UINT32 uCount); HRESULT SetCondition(const SdkQueryCondition *pQueryCondition); INT32 GetCodition() const; HRESULT SetScope(INT32 scopeType); HRESULT SetScope(PCWSTR *pszScopePaths, UINT32 uCount); HRESULT SetScope(const SdkQueryScope *pQueryScope); HRESULT Search(); HRESULT SearchAsync(); void CancelSearch(); void StopSearch(); void SetSearchNotify(SdkFileSearcherNotify *pSearcherNotify); const vector<wstring>& GetSearchResult(); protected: BOOL HasCancelled(); HRESULT EnumSearchResult(IN LPITEMIDLIST pidl); HRESULT GetShellItemInfo(IN IShellFolder *psf, IN LPCITEMIDLIST pidl); static unsigned int WINAPI SearchThreadProc(LPVOID lpParameter); private: BOOL m_hasStopped; BOOL m_hasCancel; INT_PTR m_nTag; INT32 m_nQueryConditionKind; HANDLE m_uThreadHandle; SdkQueryScope *m_pTempQueryScope; SdkQueryScope *m_pQueryScope; SdkQueryCondition *m_pTempQueryCondition; SdkQueryCondition *m_pQueryCondition; SdkFileSearcherNotify *m_pSearcherNotify; ISearchFolderItemFactory *m_pSearchFolderItemFactory; vector<wstring> m_vctSearchResults; }; #endif // _MEDIAFILESEARCH_H_ #endif // __cplusplus
SdkFileSearcher.cpp
#include "SdkFileSearcher.h" #include "SdkCommonHelper.h" #include "SdkLogger.h" SdkFileSearcher::SdkFileSearcher() : m_pSearchFolderItemFactory(NULL), m_pTempQueryScope(NULL), m_pTempQueryCondition(NULL), m_pSearcherNotify(NULL), m_hasCancel(FALSE), m_hasStopped(FALSE), m_nTag(0), m_uThreadHandle(NULL), m_nQueryConditionKind(QUERY_KIND_NONE), m_pQueryScope(new SdkQueryScope()), m_pQueryCondition(new SdkQueryCondition()) { } SdkFileSearcher::~SdkFileSearcher() { SAFE_RELEASE(m_pSearchFolderItemFactory); SAFE_DELETE(m_pQueryScope); SAFE_DELETE(m_pQueryCondition); } HRESULT SdkFileSearcher::SetCondition(INT32 queryKind) { HRESULT hr = E_FAIL; m_nQueryConditionKind = queryKind; if (NULL != m_pQueryCondition) { ClearSearchCondition(); hr = m_pQueryCondition->SetCondition(queryKind); } return hr; } HRESULT SdkFileSearcher::SetCondition(LPCWSTR *ppszQuerys, UINT32 uCount) { HRESULT hr = E_FAIL; if (NULL != m_pQueryCondition) { ClearSearchCondition(); hr = m_pQueryCondition->SetCondition(ppszQuerys, uCount); } return hr; } HRESULT SdkFileSearcher::SetCondition(const SdkQueryCondition *pQueryCondition) { ClearSearchCondition(); m_pTempQueryCondition = const_cast<SdkQueryCondition*>(pQueryCondition); return S_OK; } INT32 SdkFileSearcher::GetCodition() const { return m_nQueryConditionKind; } HRESULT SdkFileSearcher::SetScope(INT32 scopeType) { HRESULT hr = E_FAIL; if (NULL != m_pQueryScope) { ClearSearchScope(); hr = m_pQueryScope->SetScope(scopeType); } return hr; } HRESULT SdkFileSearcher::SetScope(PCWSTR *pszScopePaths, UINT32 uCount) { HRESULT hr = E_FAIL; if (NULL != m_pQueryScope) { ClearSearchScope(); hr = m_pQueryScope->SetScope(pszScopePaths, uCount); } return hr; } HRESULT SdkFileSearcher::SetScope(const SdkQueryScope *pQueryScope) { ClearSearchScope(); m_pTempQueryScope = const_cast<SdkQueryScope*>(pQueryScope); return S_OK; } HRESULT SdkFileSearcher::Search() { SAFE_RELEASE(m_pSearchFolderItemFactory); CoCreateInstance(CLSID_SearchFolderItemFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&m_pSearchFolderItemFactory)); if (NULL == m_pSearchFolderItemFactory) { return E_FAIL; } m_hasCancel = FALSE; m_hasStopped = FALSE; ClearSearchResult(); HRESULT hr = E_FAIL; SdkQueryScope *pQueryScope = (NULL != m_pTempQueryScope) ? m_pTempQueryScope : m_pQueryScope; SdkQueryCondition *pQueryCondition = (NULL != m_pTempQueryCondition) ? m_pTempQueryCondition : m_pQueryCondition; IShellItemArray *psiaScope = NULL; // +1 hr = pQueryScope->GetScope(&psiaScope); if (SUCCEEDED(hr)) { hr = m_pSearchFolderItemFactory->SetScope(psiaScope); } ICondition *pCondition = NULL; if (SUCCEEDED(hr)) { // +2 hr = pQueryCondition->GetCondition(&pCondition); if (SUCCEEDED(hr)) { hr = m_pSearchFolderItemFactory->SetCondition(pCondition); } } if (SUCCEEDED(hr)) { // +3 PIDLIST_ABSOLUTE pSearchIDL = NULL; hr = m_pSearchFolderItemFactory->GetIDList(&pSearchIDL); if (SUCCEEDED(hr)) { EnumSearchResult(pSearchIDL); // -3 CoTaskMemFree(pSearchIDL); } } // -2 SAFE_RELEASE(pCondition); // -1 SAFE_RELEASE(psiaScope); // If user stops searching, do not call finish searching result callback. if (!m_hasStopped) { // Notify caller that the searching operation is finished. if (NULL != m_pSearcherNotify) { m_pSearcherNotify->OnSearchFinish(this); } } return hr; } HRESULT SdkFileSearcher::SearchAsync() { // Stop search thread first. StopSearch(); m_hasCancel = FALSE; unsigned int dwThreadId = 0; m_uThreadHandle = (HANDLE)_beginthreadex(NULL, 0, SdkFileSearcher::SearchThreadProc, (LPVOID)this, 0, &dwThreadId); return S_OK; } void SdkFileSearcher::CancelSearch() { m_hasCancel = TRUE; } void SdkFileSearcher::StopSearch() { m_hasStopped = TRUE; WaitForSingleObject(m_uThreadHandle, 5000); } void SdkFileSearcher::SetSearchNotify(SdkFileSearcherNotify *pSearcherNotify) { m_pSearcherNotify = pSearcherNotify; } const vector<wstring>& SdkFileSearcher::GetSearchResult() { return m_vctSearchResults; } ////////////////////////////////////////////////////////////////////////// BOOL SdkFileSearcher::HasCancelled() { return (m_hasCancel || m_hasStopped); } HRESULT SdkFileSearcher::EnumSearchResult(IN LPITEMIDLIST pidl) { IShellFolder *psfDesktop = NULL; IShellFolder *psfSearch = NULL; IEnumIDList *penumIDList = NULL; // +1 HRESULT hr = SHGetDesktopFolder(&psfDesktop); if (SUCCEEDED(hr) && !HasCancelled()) { // +2 hr = psfDesktop->BindToObject(pidl, NULL, IID_IShellFolder, (LPVOID*)&psfSearch); } if (SUCCEEDED(hr) && !HasCancelled()) { // +3 hr = psfSearch->EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &penumIDList); } if (SUCCEEDED(hr)) { ULONG celtFetched = 0; PITEMID_CHILD pChild = NULL; while ( !HasCancelled() && SUCCEEDED( penumIDList->Next(1, &pChild, &celtFetched)) && (1 == celtFetched) ) { GetShellItemInfo(psfSearch, pChild); CoTaskMemFree(pChild); } } // -3 SAFE_RELEASE(penumIDList); // -2 SAFE_RELEASE(psfSearch); // -1 SAFE_RELEASE(psfDesktop); return hr; } HRESULT SdkFileSearcher::GetShellItemInfo(IN IShellFolder *psf, IN LPCITEMIDLIST pidl) { LPITEMIDLIST pRealIDL = NULL; HRESULT hr = SHGetRealIDL(psf, pidl, &pRealIDL); if (SUCCEEDED(hr)) { STRRET strName; hr = psf->GetDisplayNameOf(pRealIDL, SHGDN_FORPARSING, &strName); if (SUCCEEDED(hr)) { WCHAR szName[MAX_PATH] = { 0 }; hr = StrRetToBuf(&strName, pRealIDL, szName, MAX_PATH); if (SUCCEEDED(hr)) { // Add to vector to use subsequently. m_vctSearchResults.push_back(wstring(szName)); // Once find one result, notify caller. if (NULL != m_pSearcherNotify) { m_pSearcherNotify->OnSearchOneResult(this, szName); } } } CoTaskMemFree(pRealIDL); } return hr; } unsigned int WINAPI SdkFileSearcher::SearchThreadProc(LPVOID lpParameter) { CoInitialize(NULL); SdkFileSearcher *pThis = static_cast<SdkFileSearcher*>(lpParameter); if (NULL != pThis) { pThis->Search(); pThis->m_uThreadHandle = NULL; } CoUninitialize(); return 0; }
下一节,我们就讲一下如何创建检索条件。
相关文章推荐
- EasyPlayerPro(Windows)流媒体播放器开发之接口设计
- Windows文件检索之——查询条件
- 系统设计(目录、文件、业务类、业务接口)
- EasyPlayerPro(Windows)流媒体播放器开发之接口设计
- 20169205 项目进度三 文件资源管理器接口设计文档
- 基于XML的配置文件访问接口设计和实现
- 面向Windows的文件透明加解密解决方案(4)——客户端服务设计与功能实现
- Windows下实现文件检索
- 第三章 设计自己TLS类_AFXTLS_.H文件 windows程序设计 王艳平版
- Windows RT IRandomAccessStream 接口会在读过文件结尾时报告无效位置
- Windows文件检索之——查询范围
- 【每日一博】Spring 文件上传接口设计与实现
- Windows文件检索、复制工具(Python Tkinter)
- Windows下使用标准Shell接口遍历文件和文件夹(1)
- 第三章 设计自己TLS类CPP文件 Windows程序设计 王艳平版
- 面向Windows的文件透明加解密解决方案(4)——客户端服务设计与功能实现
- 基于python的接口测试框架设计(二)配置一些参数及文件
- Windows下使用标准Shell接口遍历文件和文件夹
- ZZ: 使用 "接口" 了解设计模式--策略模式(多态)集合框架 泛型、文件、文件流 IO(流)
- 基于XML的配置文件访问接口设计和实现