📄 itfindfiles.cpp
字号:
//
// @rdesc Returns a value whose meaning depends on the <p uFlags> parameter.
//
// @comm See the Win32 documentation on the <f SHGetFileInfo> function
// for a more complete description of this method and its purpose.
//
// @xref <c ITCFindFiles>
DWORD ITCFindFiles::SHGetFileInfo(DWORD dwFileAttributes,
SHFILEINFO FAR *psfi, UINT uFlags) const
{
ASSERT(!m_findStack.IsEmpty());
ITCSimpleFindFiles* pFind = m_findStack.GetTail();
return pFind->SHGetFileInfo(dwFileAttributes, psfi, uFlags);
}
/////////////////////////////////////////////////////////////////////////////
// ITCFindFiles operations
// @mfunc Call this method to begin a search. You must call this method
// before calling <mf ITCFindFiles::NextFile>. Each call to this method
// should be matched with a call to <mf ITCFindFiles::CloseSearch>.
//
// @syntax void NewSearch(CString strPattern,
// DWORD dwFindAttributes, DWORD dwFindFlags);
// @syntax void NewSearch(CString strFolder, CString strPattern,
// DWORD dwFindAttributes, DWORD dwFindFlags)
// @syntax void NewSearch(HDROP hDropInfo,
// DWORD dwFindAttributes, DWORD dwFindFlags)
//
// @parm CString | strFolder | The folder to search; can be the empty string.
// @parm CString | strPattern | The name of the file(s) to find. The name
// can contain wildcard characters (* and ?); if empty, the pattern *.* is used.
// @parm DWORD | dwFindAttributes | The file attributes of the file(s) to
// find. See the Win32 documentation on the <t WIN32_FIND_DATA> structure
// for a description of valid file attributes. You can also specify one of
// the following special values.
// @flag ITCFindFiles::AllAttributes | Finds everything.
// @flag ITCFindFiles::DefaultAttributes | Find all non-system files and folders.
// @flag ITCFindFiles::FilesOnly | Find all non-system files.
// @flag ITCFindFiles::FoldersOnly | Find all non-system folders.
// @parm DWORD | dwFindFlags | Can be a combination of the following values:
// @flag ITCFindFiles::None | No flags are set.
// @flag ITCFindFiles::IncludeSubfolders | Specifies that subfolders should be searched.
//
// @comm The <p strPattern> in the first version of this method can
// contain the folder and pattern to search, for example C:\*.*. Multiple
// searches can be performed by separating them with semicolons.
// The <p strPattern> in the second version can only contain the pattern,
// but multiple patterns can also be specified.
//
// When specifying the file attributes with the <p dwFindAttributes> parameter,
// only files that have all the specified file attributes will be returned
// in the search. If you do not specify one of the special values, you should
// use the <mf ITCFindFiles::SetFindAttributes> method to gain more
// control over attribute based searches.
//
// The third version of this method can be used to iterate through a set
// of files in a drag and drop operation. Usually you would use the
// ITCFindFiles::FilesOnly find attribute and the ITCFindFiles::IncludeSubfolders
// find flag. You are responsible for calling <f DragFinish> when the search
// is complete.
//
// @xref <c ITCFindFiles> <mf ITCFindFiles::NextFile>
// <mf ITCFindFiles::CloseSearch> <mf ITCFindFiles::SetFindAttributes>
void ITCFindFiles::NewSearch(CString strPattern,
DWORD dwFindAttributes, DWORD dwFindFlags)
{
CStringArray aMultiSearch;
ITCLIB::StringToStringArray(strPattern, ";", aMultiSearch);
// Add the searches in reverse order so they appear in the
// file list as they appear in the pattern specification.
for (int i=aMultiSearch.GetUpperBound(); i >= 0; i--)
{
ITCSimpleFindFiles* pFind = new ITCSimpleFindFiles;
pFind->NewSearch(aMultiSearch[i], dwFindAttributes);
pFind->SetUserData(dwFindFlags);
m_findStack.AddTail(pFind);
}
}
void ITCFindFiles::NewSearch(CString strFolder, CString strPattern,
DWORD dwFindAttributes, DWORD dwFindFlags)
{
CStringArray aMultiSearch;
ITCLIB::StringToStringArray(strPattern, ";", aMultiSearch);
// Add the searches in reverse order so they appear in the
// file list as they appear in the pattern specification.
for (int i=aMultiSearch.GetUpperBound(); i >= 0; i--)
{
ITCSimpleFindFiles* pFind = new ITCSimpleFindFiles;
pFind->NewSearch(strFolder, aMultiSearch[i], dwFindAttributes);
pFind->SetUserData(dwFindFlags);
m_findStack.AddTail(pFind);
}
}
void ITCFindFiles::NewSearch(HDROP hDropInfo,
DWORD dwFindAttributes, DWORD dwFindFlags)
{
ITCSimpleFindFiles* pFind = new ITCSimpleFindFiles;
pFind->NewSearch(hDropInfo, dwFindAttributes);
pFind->SetUserData(dwFindFlags);
m_findStack.AddTail(pFind);
}
// @mfunc Call this method to start or continue the file search.
// You must call <mf ITCFindFiles::NewSearch> before calling this
// method for the first time.
//
// @rdesc Nonzero if successful; otherwise 0. To get extended error
// information, call the Win32 function <f GetLastError>.
//
// The most common return values will be ERROR_FILE_NOT_FOUND if the
// search cannot be started and ERROR_NO_MORE_FILES if there are
// no more files in the search.
//
// @xref <c ITCFindFiles> <mf ITCFindFiles::NewSearch>
BOOL ITCFindFiles::NextFile()
{
ASSERT(!m_findStack.IsEmpty());
ITCSimpleFindFiles* pFind = m_findStack.GetTail();
return (pFind->IsDroppedFiles()) ? NextDropFile() : NextFindFile();
}
// @mfunc Call this method to end the search. You must call
// <mf ITCFindFiles::NewSearch> to begin a new search before
// calling <mf ITCFindFiles::NextFile> again.
//
// @xref <c ITCFindFiles> <mf ITCFindFiles::NewSearch>
void ITCFindFiles::CloseSearch()
{
ASSERT(!m_findStack.IsEmpty());
ITCSimpleFindFiles* pFind = m_findStack.GetTail();
pFind->Close();
delete pFind;
m_findStack.RemoveTail();
}
// @mfunc Appends to a <c CStringArray> the paths of files found by
// the search. This is done by calling <mf ITCFindFiles::NextFile>
// in a loop and adding the full file path of the found file to the
// list. You must call <mf ITCFindFiles::NewSearch> before calling this
// method.
//
// @parm A reference to a <c CStringArray> to append the files to.
//
// @rdesc Nonzero if successful; otherwise 0. To get extended error
// information, call the Win32 function <f GetLastError>.
// This method will return success if the last error is
// ERROR_FILE_NOT_FOUND or ERROR_NO_MORE_FILES.
//
// @xref <c ITCFindFiles> <mf ITCFindFiles::NextFile>
BOOL ITCFindFiles::BuildFileList(CStringArray& rFileList)
{
ASSERT(!m_findStack.IsEmpty());
while (NextFile())
rFileList.Add(GetFilePath());
return IsNonFatalError(::GetLastError());
}
// @mfunc This method returns the number of the files found by the search.
// This is done by calling <mf ITCFindFiles::NextFile> in a loop and
// counting each file. You must call <mf ITCFindFiles::NewSearch> before
// calling this method.
//
// @parm A reference to a <t DWORD> to return number of files found.
//
// @rdesc Nonzero if successful; otherwise 0. To get extended error
// information, call the Win32 function <f GetLastError>.
// This method will return success if the last error is
// ERROR_FILE_NOT_FOUND or ERROR_NO_MORE_FILES.
//
// @xref <c ITCFindFiles> <mf ITCFindFiles::NextFile>
BOOL ITCFindFiles::GetFileCount(DWORD& dwCount)
{
ASSERT(!m_findStack.IsEmpty());
dwCount = 0;
while (NextFile())
dwCount++;
return IsNonFatalError(::GetLastError());
}
// @mfunc Sets the function to be called for each file found in the search.
//
// @parm A pointer to the callback function.
// @parm Specifies the application-defined parameter to be passed to
// the callback function.
//
// @rdesc The previous callback function or NULL if no callback was defined.
//
// @comm The callback function is called by <mf ITCFindFiles::OnFindFile>.
//
// @xref <c ITCFindFiles> <f FindFileEnumProc>
ITCFINDFILESENUMPROC ITCFindFiles::SetCallback(ITCFINDFILESENUMPROC lpEnumProc, LONG lParam)
{
ITCFINDFILESENUMPROC lpOldEnumProc = m_lpEnumProc;
m_lpEnumProc = lpEnumProc;
m_lEnumParam = lParam;
return lpOldEnumProc;
}
/////////////////////////////////////////////////////////////////////////////
// ITCFindFiles overridables
// @mfunc This method is called for each file found in the search.
// You can use this method to stop the search when a file is found.
// The default implementation calls the callback function set by
// <mf ITCFindFiles::SetCallback> or returns nonzero if no callback is set.
//
// @rdesc Return nonzero to continue the search; otherwise 0.
//
// @xref <c ITCFindFiles> <mf ITCFindFiles::OnFilterFile>
BOOL ITCFindFiles::OnFindFile()
{
if (m_lpEnumProc)
return (m_lpEnumProc)(this, m_lEnumParam);
return TRUE; // Continue the search
}
// @mfunc If the search includes subfolders, this method is called
// for each subfolder to search. The default implementation begins
// a new search for the files in the subfolder by calling
// <mf ITCFindFiles::NewSearch> with the path returned by
// <mf ITCFindFiles::GetFilePath>. The files in the new search will
// be enumerated before the current search continues.
//
// @comm This method is not called for the folder where the search
// begins. This method is only called when subfolders need to be
// searched.
//
// @xref <c ITCFindFiles>
void ITCFindFiles::OnSearchSubfolder()
{
ASSERT(m_findStack.GetCount() >= 2);
if (m_findStack.GetCount() >= 2)
{
POSITION pos = m_findStack.GetTailPosition();
ITCSimpleFindFiles* pPrev = NULL;
// The last search is the search for each subfolder.
// The search before that contains the attributes and
// filter of the files we want to search for.
pPrev = m_findStack.GetPrev(pos);
pPrev = m_findStack.GetPrev(pos);
DWORD dwAttribSet = 0;
DWORD dwAttribClear = 0;
pPrev->GetFindAttributes(dwAttribSet, dwAttribClear);
if (HasFileAttributes(FILE_ATTRIBUTE_SYSTEM) && !(dwAttribSet & FILE_ATTRIBUTE_SYSTEM))
{
// This is a System folder and if the user didn't want
// to see System files, we shouldn't show them files
// in system folders.
}
else
{
CString strPattern = pPrev->GetFindPattern();
ITCSimpleFindFiles* pSearchSubfolder = new ITCSimpleFindFiles;
pSearchSubfolder->NewSearch(GetFilePath(), strPattern, 0);
pSearchSubfolder->SetUserData(IncludeSubfolders);
pSearchSubfolder->SetFindAttributes(dwAttribSet, dwAttribClear);
m_findStack.AddTail(pSearchSubfolder);
}
}
}
// @mfunc This method is called to determine if a file should be
// part of the search. You can override this method to perform
// custom filtering of files. The default implementation always
// returns nonzero.
//
// @rdesc Return nonzero if the file should be returned as part of
// the search; otherwise 0.
//
// @xref <c ITCFindFiles> <mf ITCFindFiles::OnFindFile>
BOOL ITCFindFiles::OnFilterFile() const
{
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// ITCFindFiles implementation
BOOL ITCFindFiles::NextFindFile()
{
ITCSimpleFindFiles* pFind = m_findStack.GetTail();
DWORD dwUserData = pFind->GetUserData();
if (dwUserData & SearchingSubfolders)
{
// We are trying to find subfolders. For each subfolder
// we find, create a new search for each of the files in
// that folder. If there are no more subfolders, close the
// search and continue with the search that got us here.
DWORD dwLastError = ::GetLastError();
if (pFind->NextFile())
{
ASSERT(IsFolder());
OnSearchSubfolder();
dwLastError = ::GetLastError();
}
else if (::GetLastError() == ERROR_FILE_NOT_FOUND)
{
dwLastError = ERROR_NO_MORE_FILES;
CloseSearch();
}
else
{
dwLastError = ::GetLastError();
CloseSearch();
}
::SetLastError(dwLastError);
return NextFile();
}
if (pFind->NextFile())
{
// We found a matching file or folder!
if (!OnFilterFile())
return NextFile();
return OnFindFile();
}
if (dwUserData & IncludeSubfolders)
{
// We have been through all the matching files and folders,
// so now we want to search the subfolders. We create a new
// search to find each subfolder, and if there are any,
// each of them will be searched. Make sure we don't search
// this folder for subfolders again.
dwUserData &= ~IncludeSubfolders;
pFind->SetUserData(dwUserData);
ITCSimpleFindFiles* pFindSubfolders = new ITCSimpleFindFiles;
pFindSubfolders->NewSearch(GetRoot(), "*.*", FILE_ATTRIBUTE_DIRECTORY);
pFindSubfolders->SetUserData(SearchingSubfolders|IncludeSubfolders);
m_findStack.AddTail(pFindSubfolders);
return NextFile();
}
if (m_findStack.GetCount() > 1)
{
// There are no more matching files or folders so continue
// with the search that got us here.
CloseSearch();
return NextFile();
}
return FALSE;
}
BOOL ITCFindFiles::NextDropFile()
{
ITCSimpleFindFiles* pFind = m_findStack.GetTail();
DWORD dwUserData = pFind->GetUserData();
if (dwUserData & SearchingSubfolders)
{
// We are trying to find subfolders. For each subfolder
// we find, create a new search for each of the files in
// that folder. If there are no more subfolders, close the
// search and continue with the search that got us here.
if (pFind->NextFile())
{
ASSERT(IsFolder());
OnSearchSubfolder();
return NextFile();
}
return FALSE;
}
if (pFind->NextFile())
{
// We found a matching file or folder!
if (!OnFilterFile())
return NextFile();
return OnFindFile();
}
if (dwUserData & IncludeSubfolders)
{
// We have been through all the matching files and folders,
// so now we want to search the subfolders. We reset the
// search to find each subfolder, and if there are any,
// each of them will be searched. Make sure we don't search
// for subfolders again.
dwUserData &= ~IncludeSubfolders;
pFind->SetUserData(dwUserData);
ITCSimpleFindFiles* pFindSubfolders = new ITCSimpleFindFiles;
pFindSubfolders->NewSearch(*pFind);
pFindSubfolders->SetFindAttributes(FILE_ATTRIBUTE_DIRECTORY, 0);
pFindSubfolders->SetUserData(SearchingSubfolders|IncludeSubfolders);
m_findStack.AddTail(pFindSubfolders);
return NextFile();
}
return FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// ITCFindFiles diagnostics
#ifdef _DEBUG
void ITCFindFiles::AssertValid() const
{
CObject::AssertValid();
ASSERT_VALID(&m_findStack);
}
void ITCFindFiles::Dump(CDumpContext& dc) const
{
CObject::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNAMIC(ITCFindFiles, CObject)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -