www.pudn.com > VC写的MP3播放器源代码.zip > ITFindFiles.cpp


///////////////////////////////////////////////////////////////////////////// 
 
///////////////////////////////////////////////////////////////////////////// 
// 
// $NoKeywords: $ 
// 
// @doc EXTERNAL UTILITY 
 
#include "StdAfx.h" 
 
#include "ITFindFiles.h" 
#include "ITSimpleFindFiles.h" 
#include "ITAPI.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
DWORD ITCFindFiles::None = 0x0000; 
DWORD ITCFindFiles::IncludeSubfolders = 0x0001; 
DWORD ITCFindFiles::SearchingSubfolders = 0x0002; 
 
DWORD ITCFindFiles::AllAttributes = ITCSimpleFindFiles::AllAttributes; 
DWORD ITCFindFiles::DefaultAttributes = ITCSimpleFindFiles::DefaultAttributes; 
DWORD ITCFindFiles::FilesOnly = ITCSimpleFindFiles::FilesOnly; 
DWORD ITCFindFiles::FoldersOnly = ITCSimpleFindFiles::FoldersOnly; 
 
///////////////////////////////////////////////////////////////////////////// 
// ITCFindFiles helpers 
 
static BOOL IsNonFatalError(DWORD dwError) 
{ 
	BOOL bNonFatal = FALSE; // Assume so 
 
	switch (dwError) 
	{ 
	case ERROR_FILE_NOT_FOUND: 
	case ERROR_NO_MORE_FILES: 
		bNonFatal = TRUE; 
		break; 
	} 
 
	return bNonFatal; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// ITCFindFiles construction 
 
// @mfunc Constructs a  object. 
// 
// @xref  
ITCFindFiles::ITCFindFiles() 
{ 
	m_lpEnumProc = NULL; 
	m_lEnumParam = 0; 
} 
 
// @mfunc Destroys a  object. 
// 
// @xref  
ITCFindFiles::~ITCFindFiles() 
{ 
	while (!m_findStack.IsEmpty()) 
		CloseSearch(); 
	m_findStack.RemoveAll(); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// ITCFindFiles attributes 
 
// @mfunc Call this method to determine if the found file is archived.  
// You must call  at least once before 
// calling this method. 
// 
// @rdesc Nonzero if the file is archived; otherwise 0.  
// 
// @xref  
BOOL ITCFindFiles::IsArchived() const 
{ 
	return HasFileAttributes(FILE_ATTRIBUTE_ARCHIVE); 
} 
 
// @mfunc Call this method to determine if the found file is compressed.  
// You must call  at least once before 
// calling this method. 
// 
// @rdesc Nonzero if the file is compressed; otherwise 0.  
// 
// @xref  
BOOL ITCFindFiles::IsCompressed() const 
{ 
	return HasFileAttributes(FILE_ATTRIBUTE_COMPRESSED); 
} 
 
// @mfunc Call this method to determine if the found file is a folder.  
// You must call  at least once before 
// calling this method. 
// 
// @rdesc Nonzero if the file is a folder; otherwise 0.  
// 
// @xref  
BOOL ITCFindFiles::IsFolder() const 
{ 
	return HasFileAttributes(FILE_ATTRIBUTE_DIRECTORY); 
} 
 
// @mfunc Call this method to determine if the found file is hidden.  
// You must call  at least once before 
// calling this method. 
// 
// @rdesc Nonzero if the file is hidden; otherwise 0.  
// 
// @xref  
BOOL ITCFindFiles::IsHidden() const 
{ 
	return HasFileAttributes(FILE_ATTRIBUTE_HIDDEN); 
} 
 
// @mfunc Call this method to determine if the found file is normal.  
// You must call  at least once before 
// calling this method. 
// 
// @rdesc Nonzero if the file is normal; otherwise 0.  
// 
// @xref  
BOOL ITCFindFiles::IsNormal() const 
{ 
	return HasFileAttributes(FILE_ATTRIBUTE_NORMAL); 
} 
 
// @mfunc Call this method to determine if the found file is offline.  
// You must call  at least once before 
// calling this method. 
// 
// @rdesc Nonzero if the file is offline; otherwise 0.  
// 
// @xref  
BOOL ITCFindFiles::IsOffline() const 
{ 
	return HasFileAttributes(FILE_ATTRIBUTE_OFFLINE); 
} 
 
// @mfunc Call this method to determine if the found file is read-only.  
// You must call  at least once before 
// calling this method. 
// 
// @rdesc Nonzero if the file is read-only; otherwise 0.  
// 
// @xref  
BOOL ITCFindFiles::IsReadOnly() const 
{ 
	return HasFileAttributes(FILE_ATTRIBUTE_READONLY); 
} 
 
// @mfunc Call this method to determine if the found file is a system file.  
// You must call  at least once before 
// calling this method. 
// 
// @rdesc Nonzero if the file is a system file; otherwise 0.  
// 
// @xref  
BOOL ITCFindFiles::IsSystem() const 
{ 
	return HasFileAttributes(FILE_ATTRIBUTE_SYSTEM); 
} 
 
// @mfunc Call this method to determine if the found file is temporary.  
// You must call  at least once before 
// calling this method. 
// 
// @rdesc Nonzero if the file is a temporary file; otherwise 0.  
// 
// @xref  
BOOL ITCFindFiles::IsTemporary() const 
{ 
	return HasFileAttributes(FILE_ATTRIBUTE_TEMPORARY); 
} 
 
// @mfunc Call this method to test the file attributes of the found file. 
// You must call  at least once before 
// calling this method. 
// 
// @parm Specifies one or more file attributes, identified in the 
//  structure. Any combination of the attributes is 
// acceptable. 
// 
// @rdesc Nonzero if the file has all of the specified attributes; otherwise 0. 
// 
// @xref  
BOOL ITCFindFiles::HasFileAttributes(DWORD dwFileAttributes) const 
{ 
	ASSERT(!m_findStack.IsEmpty()); 
	ITCSimpleFindFiles* pFind = m_findStack.GetTail(); 
	return pFind->HasFileAttributes(dwFileAttributes); 
} 
 
// @mfunc Call this method to get the length of the found file, in bytes. 
// You must call  at least once before 
// calling this method. 
//  
// This method will only return a valid length if the file is less than 
// four gigabytes in size. 
// 
// @rdesc The length of the found file, in bytes. 
// 
// @xref  
DWORD ITCFindFiles::GetLength() const 
{ 
	ASSERT(!m_findStack.IsEmpty()); 
	ITCSimpleFindFiles* pFind = m_findStack.GetTail(); 
	return pFind->GetLength(); 
} 
 
// @mfunc Returns the file attributes, identified in the  
// structure, of the found file. You must call  
// at least once before calling this method. 
// 
// @rdesc The file attributes of the found file. 
// 
// @xref  
DWORD ITCFindFiles::GetFileAttributes() const 
{ 
	ASSERT(!m_findStack.IsEmpty()); 
	ITCSimpleFindFiles* pFind = m_findStack.GetTail(); 
	return pFind->GetFileAttributes(); 
} 
 
// @mfunc Call this method to get the root of the found file. 
// You must call  at least once before 
// calling this method. 
// 
// @rdesc The root of the search. 
// 
// @comm This method returns the drive specifier and path name where 
// the search began. This method will always return the complete 
// path of the search origin. 
// 
// @xref   
//   
//  
CString ITCFindFiles::GetRoot() const 
{ 
	ASSERT(!m_findStack.IsEmpty()); 
	ITCSimpleFindFiles* pFind = m_findStack.GetTail(); 
	return pFind->GetRoot(); 
} 
 
// @mfunc Call this method to get the extension of the found file. For example, 
// if the name of the file is DATA.TXT,  
// returns "TXT". 
// 
// You must call  at least once before calling 
// this method. 
// 
// @rdesc The extension of the found file. 
// 
// @xref   
//   
//  
CString ITCFindFiles::GetFileExt() const 
{ 
	ASSERT(!m_findStack.IsEmpty()); 
	ITCSimpleFindFiles* pFind = m_findStack.GetTail(); 
	return pFind->GetFileExt(); 
} 
 
// @mfunc Call this method to get the full path of the found file. You 
// must call  at least once before 
// calling this method. 
// 
// @rdesc The path of the found file. 
// 
// @xref   
//   
//  
CString ITCFindFiles::GetFilePath() const 
{ 
	ASSERT(!m_findStack.IsEmpty()); 
	ITCSimpleFindFiles* pFind = m_findStack.GetTail(); 
	return pFind->GetFilePath(); 
} 
 
// @mfunc Call this method to get the name of the found file, 
// without the extension. You must call  
// at least once before calling this method. 
// 
// @rdesc The title of the found file. 
// 
// @xref   
//   
//  
CString ITCFindFiles::GetFileTitle() const 
{ 
	ASSERT(!m_findStack.IsEmpty()); 
	ITCSimpleFindFiles* pFind = m_findStack.GetTail(); 
	return pFind->GetFileTitle(); 
} 
 
// @mfunc Call this method to get the name of the found file, 
// including the extension. You must call  
// at least once before calling this method. 
// 
// @rdesc The name of the found file. 
// 
// @xref   
//   
//  
LPCTSTR ITCFindFiles::GetFileName() const 
{ 
	ASSERT(!m_findStack.IsEmpty()); 
	ITCSimpleFindFiles* pFind = m_findStack.GetTail(); 
	return pFind->GetFileName(); 
} 
 
// @mfunc Call this method to get the folder containing the found file. 
// You must call  at least once before calling 
// this method. 
// 
// @rdesc The folder containing the found file. 
// 
// @xref   
//   
CString ITCFindFiles::GetFileFolder() const 
{ 
	ASSERT(!m_findStack.IsEmpty()); 
	ITCSimpleFindFiles* pFind = m_findStack.GetTail(); 
	return pFind->GetFileFolder(); 
} 
 
// @mfunc Returns the  structure of the found file. 
// You must call  at least once before 
// calling this method. 
// 
// @rdesc A pointer to the  of the found file. 
// 
// @xref  
const WIN32_FIND_DATA* ITCFindFiles::GetFindData() const 
{ 
	ASSERT(!m_findStack.IsEmpty()); 
	ITCSimpleFindFiles* pFind = m_findStack.GetTail(); 
	return pFind->GetFindData(); 
} 
 
// @mfunc Call this method to get the file pattern the search is based on. 
// For example, the pattern would be something like *.*, *.DAT, or MY*.TXT. 
// 
// @rdesc The file pattern of the search. 
// 
// @xref   
CString ITCFindFiles::GetFindPattern() const 
{ 
	ASSERT(!m_findStack.IsEmpty()); 
	ITCSimpleFindFiles* pFind = m_findStack.GetTail(); 
	return pFind->GetFindPattern(); 
} 
 
// @mfunc Call this method to get the complete search pattern of the search. 
// This is based on the find root, determined by  
// and the find pattern, determined by . 
// 
// @rdesc The complete search pattern the search is based on. 
// 
// @xref   
CString ITCFindFiles::GetFindFileName() const 
{ 
	ASSERT(!m_findStack.IsEmpty()); 
	ITCSimpleFindFiles* pFind = m_findStack.GetTail(); 
	return pFind->GetFindFileName(); 
} 
 
// @mfunc Call this method to get the file attributes the search is based on. 
// Only files that have the specified attributes will be returned in the 
// search. 
// 
// @parm Specifies file attributes that must be set. 
// @parm Specifies file attributes that must not be set. 
// 
// @xref   
void ITCFindFiles::GetFindAttributes(DWORD& dwAttribSet, DWORD& dwAttribClear) const 
{ 
	ASSERT(!m_findStack.IsEmpty()); 
	ITCSimpleFindFiles* pFind = m_findStack.GetTail(); 
	pFind->GetFindAttributes(dwAttribSet, dwAttribClear); 
} 
 
// @mfunc Sets the file attributes that are being used to filter the search. 
// Only files with attributes that include all of the 

// and none of the

file attributes will be returned. // // @parm Specifies file attributes that must be set; 0 to match all files. // @parm Specifies file attributes that must not be set; 0 to match all files. // // @ex | // // Search for compressed files. // SetAttributeFilter(FILE_ATTRIBUTE_COMPRESSED, FILE_ATTRIBUTE_DIRECTORY); // // // Search for compressed folders. // SetAttributeFilter(FILE_ATTRIBUTE_COMPRESSED|FILE_ATTRIBUTE_DIRECTORY, 0); // // // Search for compressed files and folders. // SetAttributeFilter(FILE_ATTRIBUTE_COMPRESSED, 0); // // // Search for everything. // SetAttributeFilter(0, 0); // // @xref void ITCFindFiles::SetFindAttributes(DWORD dwAttribSet, DWORD dwAttribClear) { ASSERT(!m_findStack.IsEmpty()); // This method affects all the searches currently in progress. // If you only change one of the search objects, there are // problems when multiple search values are specified in NewSearch. POSITION pos = m_findStack.GetHeadPosition(); while (pos) { ITCSimpleFindFiles* pFind = m_findStack.GetNext(pos); pFind->SetFindAttributes(dwAttribSet, dwAttribClear); } } // @mfunc Retrieve the string that describes the file's type. This is the same // description displayed in the Type column of the Windows Explorer. // You must call at least once before // calling this method. // // @rdesc The string that describes the file's type. // // @xref CString ITCFindFiles::GetTypeName() const { ASSERT(!m_findStack.IsEmpty()); ITCSimpleFindFiles* pFind = m_findStack.GetTail(); return pFind->GetTypeName(); } // @mfunc Retrieves shell information about the found file using the // Win32 function. You must call // at least once before calling this method. // // @parm Combination of one or more file attribute flags. // @parm Address of a structure to receive the file information. // @parm Flags that specify the file information to retrieve. // // @rdesc Returns a value whose meaning depends on the

parameter. // // @comm See the Win32 documentation on the function // for a more complete description of this method and its purpose. // // @xref 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 . Each call to this method // should be matched with a call to . // // @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 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

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

in the second version can only contain the pattern, // but multiple patterns can also be specified. // // When specifying the file attributes with the

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 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 when the search // is complete. // // @xref // 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 before calling this // method for the first time. // // @rdesc Nonzero if successful; otherwise 0. To get extended error // information, call the Win32 function . // // 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 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 // to begin a new search before // calling again. // // @xref void ITCFindFiles::CloseSearch() { ASSERT(!m_findStack.IsEmpty()); ITCSimpleFindFiles* pFind = m_findStack.GetTail(); pFind->Close(); delete pFind; m_findStack.RemoveTail(); } // @mfunc Appends to a the paths of files found by // the search. This is done by calling // in a loop and adding the full file path of the found file to the // list. You must call before calling this // method. // // @parm A reference to a to append the files to. // // @rdesc Nonzero if successful; otherwise 0. To get extended error // information, call the Win32 function . // This method will return success if the last error is // ERROR_FILE_NOT_FOUND or ERROR_NO_MORE_FILES. // // @xref 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 in a loop and // counting each file. You must call before // calling this method. // // @parm A reference to a to return number of files found. // // @rdesc Nonzero if successful; otherwise 0. To get extended error // information, call the Win32 function . // This method will return success if the last error is // ERROR_FILE_NOT_FOUND or ERROR_NO_MORE_FILES. // // @xref 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 . // // @xref 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 // or returns nonzero if no callback is set. // // @rdesc Return nonzero to continue the search; otherwise 0. // // @xref 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 // with the path returned by // . 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 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 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)