Thread: FindFirstFile and FindNextFile

  1. #1
    Registered User
    Join Date
    Mar 2007
    Posts
    416

    FindFirstFile and FindNextFile

    Before I ask my question, yes I have done searches. I've gone through this board, google, MSDN, and still don't know what is happening.

    I have part of my code checking to see if the program is in fact getting the file name, and it is not. I know this directory has only files, and no other directories. If I use FindFirstFile("*.*",&ffData) it will always return a directory for dwFileAttributes, and never give me a filename. If I use FindNextFile(".txt",&ffData) or something, it will then give me a file name. Why does "*.*" never return a file name?

    Code:
            _chdir("C:\\aaMyFiles"); //this is further up in the code
    
            //from here down is all together
            if((buffer = _getdcwd(3,lBuffer,MAX_PATH)) == NULL)
                perror("_getcwd error");
    
            hFind = FindFirstFile("*.*",&ffData);
    
            if(ffData.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY)
                SetDlgItemText(Hwnd,TESTING,ffData.cFileName);  //i never get the file name
    
            else if(hFind == INVALID_HANDLE_VALUE)
                SetDlgItemText(Hwnd,TESTING,"invalid handle"); //hasn't been a problem yet
    
            else if (ffData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY)
                SetDlgItemText(Hwnd,TESTING,buffer); //ALWAYS COMES TO THIS ONE
    
            else
                SetDlgItemText(Hwnd,TESTING,ffData.cFileName); //just in case, but still doesnt show a file name

  2. #2
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    dwFileAttributes is a bit-mask. You need to use bit operations to see if are particular flag is set or not.

    Code:
    #define IsBitSet(v, m) (((v) & (m)) == (m))
    ...
    if (IsBitSet(ffData.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY))
       ...

  3. #3
    Registered User
    Join Date
    Mar 2007
    Posts
    416
    Thank you for the help, but I do not see how that answers my question. I want to know why FindFirstFile() is not finding any files with "*.*" specified as the first argument. Shouldn't the wild card *.* mean find any file with any extension?

    I tried your IsBitSet() and it works the exact same as before. Like I said, there are no directories or folders in C:\Music folder. There is only one file, and it cannot even retrieve the name.

  4. #4
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    There is something wrong with your code.

    http://www.adrianxw.dk/SoftwareSite/...irstFile1.html

    gg

  5. #5
    Registered User
    Join Date
    Mar 2007
    Posts
    142
    So you just call FindFirstFile and stop there? I see no FindNext call in your code.

    I think you should look at that fist item recieved from FindFirstFile in debugger and see if it's maybe "." or ".." quasi / virtual folder.

  6. #6
    Ex scientia vera
    Join Date
    Sep 2007
    Posts
    477
    There is an error in your 'debugging logic', so to speak.

    Don't use any criteria to display the retrieved file - what does it display if you remove all the if statements and just print the file retrieved regardless of what it is ?

    If that gives you some results, try doing a printf("0x%08x\n", ffData.dwFileAttributes); for every file it retrieves too, and then see the difference. As in, what does that variable hold when you get a directory as opposed to when you get a file?

  7. #7
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    Quote Originally Posted by scwizzo View Post
    Like I said, there are no directories or folders in C:\Music folder. There is only one file, and it cannot even retrieve the name.
    Actually there are two directories in that folder, as in all folders. They are "." and ".."

    Know why?
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

  8. #8
    Registered User
    Join Date
    Mar 2007
    Posts
    416
    Quote Originally Posted by novacain View Post
    Actually there are two directories in that folder, as in all folders. They are "." and ".."

    Know why?
    Is one the directory itself and the other is the parent directory? That's my understanding of it, but when I said there were no other directories I meant no other folders to look in.

    I'm starting to get some progress. Like idelovski and IceDane said, i was not seeing anything since I was not calling FindNextFile(). Now I am able to get through a directory, but I am getting stuck on switching directories correctly. If I cannot figure something out tonight I will post my code.

  9. #9
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    Quote Originally Posted by novacain View Post
    Actually there are two directories in that folder, as in all folders. They are "." and ".."

    Know why?
    The dot notation is a directory structure placemarker originating in DOS/UNIX. The single dot refers to the current directory and the double dot refers to the parent directory

  10. #10
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    Yes.

    FindFirstFile() first finds the '.' folder, then the '..' folder, then the first item in the folder.

    This only happens if you use '*.*' filter

    I'm starting to get some progress. Like idelovski and IceDane said, i was not seeing anything since I was not calling FindNextFile(). Now I am able to get through a directory, but I am getting stuck on switching directories correctly. If I cannot figure something out tonight I will post my code.
    Send the folder in as a param. Each time the FindFirstFile() finds a folder call it again (recursive).
    Last edited by novacain; 03-11-2008 at 01:06 AM.
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

  11. #11
    Registered User
    Join Date
    Mar 2007
    Posts
    416
    I got a couple new problem.

    1) I am able to read files, and go through directories just fine now. However, it will only back up one directory, and does not move down to the next directory, and will just search the same directory over and over. (ie. starts at c:\\ then goes to aaaTEST directory, and inside aaaTEST there are two folders but it will never back out and go to the second folder, always backs up to aaaTEST then back to the first folder).

    2) It does not catch the name of a file on the first time through a folder. It will catch it on the second time through. I have no idea why this happens.

    *braces self for severe critism*

    Code:
    case SCAN:
                {
                    //if the scan was stopped, restart it
                    if(!ContinueScan)
                        ContinueScan = true;
                    //initialize the scan for the first time
                    //(only changes drives once)
                    if(initScan == false){
                        _chdir("C:\\");
                        if((hFind = FindFirstFile("*.*",&ffData)) == INVALID_HANDLE_VALUE){
                            SetDlgItemText(Hwnd,TEST2,"INVALID_HANDLE_VALUE (complete failure)");
                        }
                        else
                            initScan = true;
                    }
                    //checks if hThread has an assignment, prevents multiple
                    //threads from being made
                    if((StartScan && hThread == NULL) || ContinueScan)
                        hThread = _beginthread(&SystemScan,0,NULL);
    
                    StartScan = false;
    
                }
                    break;
    
    
    /* on down to the called thread */
    
    void SystemScan(void* pArgv)
    {
        while(ContinueScan || StartScan)
        {
            buffer = _getcwd(lBuffer,MAX_PATH); //gets current directory
    
            //if cFileName is '.' or '..' get the next file
            if((strcmp(ffData.cFileName, ".") == 0 || strcmp(ffData.cFileName, "..") == 0))
                FindNextFile(hFind,&ffData);
    
            //if cFileName != '.' or '..' then check if it's directory or not
            if(!(strcmp(ffData.cFileName, ".") == 0 || strcmp(ffData.cFileName, "..") == 0)){
                if(ffData.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY){
    
                    /* THIS IS WHERE FILE CHECKING WILL OCCUR */
                    if(strncmp(ffData.cFileName,"test.dll",MAX_PATH) == 0){
                        SetDlgItemText(Hwnd,TEST2,"FILE FOUND!"); //file found
                        SetDlgItemText(Hwnd,TESTING,ffData.cFileName); //show the file found
                        ContinueScan = false; //stop scanning
                        break; //break so "FILE FOUND" appears
                    }
    
                    SetDlgItemText(Hwnd,TESTING,ffData.cFileName); //show current file
                    SetDlgItemText(Hwnd,TEST2,buffer); //show current directory
                    FindNextFile(hFind,&ffData); //move on to the next file
                }
                if(ffData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY){
                    pbuffer = _getcwd(lBuffer,MAX_PATH); //get new parent
                    //at time of execution this is the current directory, becomes parent after
    
                    SetDlgItemText(Hwnd,TEST2,pbuffer); //display current parent
                    strcat(buffer,"\\"); //get read to open next directory
                    strcat(buffer,ffData.cFileName); //next child path
                    _chdir(buffer); //change to next child directory
                    hFind = FindFirstFile("*.*",&ffData); //get the first file
                }
            }
            else
                SetDlgItemText(Hwnd,TESTING,"strcmp returned 0 (complete failure)");
    
            if(FindNextFile(hFind,&ffData) == 0){
                if(GetLastError() == ERROR_NO_MORE_FILES){
                    if(_chdir("..") == 0) //go back to parent
                    {
                        pbuffer = _getcwd(lBuffer,MAX_PATH); //get parent
                        SetDlgItemText(Hwnd,TEST2,pbuffer); //show parent
    
                        /* THIS IS WRONG WITH THE WAY IT CHOOSES THE NEXT DIRECTORY*/
                        n = 0; //reset count down the list
                        hFind = FindFirstFile("*.*",&ffData);
                        while(n < pass){
                            while(strcmp(ffData.cFileName, ".") == 0 || strcmp(ffData.cFileName, "..") == 0){
                                FindNextFile(hFind,&ffData);
                            }
                            FindNextFile(hFind,&ffData);
                            n++;
                        }
                    }
                    else
                        SetDlgItemText(Hwnd,TEST2,"change directory failure");
                }
                else
                    SetDlgItemText(Hwnd,TEST2,"unkown ERROR");
            }
        }
        FindClose(hFind);
    }

  12. #12
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    As some have noted before, the best way is recursion. The other problem I see in the code is that you have multiple paths for the same code or situation. It's like, is it a directory, do this, but if it isn't, do this and then if it's a directroy... etc.
    That means multiple code paths to maintain, which isn't always preferable.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  13. #13
    Registered User
    Join Date
    Mar 2007
    Posts
    416
    I see what you mean. I might make a rough copy of what I'd like to happen instead of trying to do all the details all at once.

  14. #14
    Registered User
    Join Date
    Mar 2007
    Posts
    416
    I went back and did about half a dozen different approaches to scanning directories and files, and eventually came up with one that worked correctly. I set it up to display the current folder, and file the program is scanning. However, I noticed after making some test files and test folders I made an error. I set my test folders up like 'aaTESTFOLDER' (in c:\ ) so it would be the first folder accessed just for the ease of testing. Then I took an image file and named it 'aaaa.jpg' (also in c:\ ). When I go to My Computer and open the explorer, folders are always placed on top in alphabetical order, then files, also in order. But I noticed FindNextFile() gets the first file OR directory according to alphabetical order. So my aaaa.jpg file was found first, skipped, then aaTESTFOLDER was found, accessed, and it become recursive from that point on. Here is where the problem comes in. I based my assumption of directory changing/file reading on the fact that the computer sees exactly what i see (directories first, then files, obviously not the case). I wanted to expand the file search/scan to virtually the same as the feature "Search..." under the start menu so it would search an entire drive. I am lost on how to approach changing back to a parent directory, then down to the next directory (so it does not back up, then go back to the same directory it was just in).

    Here is my search that I got working up until it hits a dead end (does not go back to the parent).

    Code:
            if(data.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY){
                isdir = true; //the file was a directory
                if(strcmp(data.cFileName,".") == 0||strcmp(data.cFileName,"..") == 0){
                    FindNextFile(hFind,&data); //move to next file
                }
                else {
                    pbuffer = _getcwd(lBuffer,MAX_PATH); //get current directory (will become parent)
                    buffer = _getcwd(lBuffer,MAX_PATH); //get current directory
                    strcat(buffer,"\\"); //prepare buffer for changing directory
                    strcat(buffer,data.cFileName); //new directory path
                    _chdir(buffer); //change to new directory
                    hFind = FindFirstFile("*.*",&data); //find first file in new directory
                }
            }
            else if(data.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY){
                isfile = true; // (NOT USED)
                sofar++; //this is equal to percent for now
            }
    
            SetDlgItemText(Hwnd,TESTING,data.cFileName); //display current file name
            SetDlgItemText(Hwnd,TEST2,buffer); //display current directory
    
            if(!isdir){
                if(FindNextFile(hFind,&data) == 0){
                    if(GetLastError() == ERROR_NO_MORE_FILES){
                        //WORK ON CHANGING BACK TO DIRECTORIES
                        sofar = 100; //set to 100&#37; for now
                    }
                    else {
                        SetDlgItemText(Hwnd,TEST2,"Unknown Error");
                    }
                }
                else {
                    //DO NOTHING FOR NOW
                }
            }
            else {
                //still working on something here
                //SetDlgItemText(Hwnd,TEST2,"FindNextFile() NOT CALLED; isdir = true");
            }
    
            isdir = false;
            isfile = false;
    
            //repeats loop

  15. #15
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    No, no, no. You didn't grasp the concept people were telling you about, I think.
    However, I think code may say more than a thousand words, so I'll post my code for file scanning. Your objective is to read the code and see how it is structured and how its layout is working. Not copy n' paste.
    Note that the copy will not compiler as-is and is always a draft; some things may not be what they should be and the code may have some bad practices left.

    Code:
    bool FindFilesInternal(pp<FindFilesInternalStruct> pArgs, pp< vector<CString> > s_vFiles, UINT64& rCurrentCount, UINT64& rTotalCount)
    {
    	WIN32_FIND_DATA fDataDirs, fDataFiles;
    	HANDLE hFileDirs = NULL, hFileFiles = NULL;
    
    	if (pArgs->strFolder.Right(1) == _T("\\")) pArgs->strFolder.Delete(pArgs->strFolder.GetLength());
    
    	hFileDirs = FindFirstFile(pArgs->strFolder + _T("\\*.*"), &fDataDirs);
    	if (hFileDirs == (HANDLE)-1) return false; // Apparently we couldn't search this directory...
    	hFileFiles = FindFirstFile(pArgs->strFolder + _T("\\") + pArgs->strPattern, &fDataFiles);
    	
    	if (hFileFiles != (HANDLE)-1)
    	{
    		while (FindNextFile(hFileFiles, &fDataFiles) && GetLastError() == ERROR_NO_MORE_FILES) // Search for files in local directory
    		{
    			if (pArgs->pCancel && *pArgs->pCancel) return true;
    			if ( !(fDataFiles.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
    			{
    				rCurrentCount++;
    				rTotalCount++;
    				if (*pArgs->p_bRequest) // Due to thread safety, data has to be requested. Local copies of everything is kept. This avoids expensive locking.
    				{
    					if (pArgs->p_nCurrentFile) *pArgs->p_nCurrentFile = rCurrentCount;
    					if (pArgs->p_strCurrentFile) *pArgs->p_strCurrentFile = pArgs->strFolder + _T("\\") + fDataFiles.cFileName;
    					if (pArgs->pTotalFiles) *pArgs->pTotalFiles = rTotalCount;
    					*pArgs->p_bRequest = false;
    					SetEvent(pArgs->hRequestDataEvent);
    				}
    				if (!pArgs->bCount)
    					s_vFiles->push_back(pArgs->strFolder + _T("\\") + (CString)fDataFiles.cFileName);
    			}
    		}
    	}
    
    	if (pArgs->bSearchSubFolders)
    	{
    		while (FindNextFile(hFileDirs, &fDataDirs) && GetLastError() == ERROR_NO_MORE_FILES) // Search for directories
    		{
    			if (pArgs->pCancel && *pArgs->pCancel) return true;
    			if ((fDataDirs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && _tcscmp(fDataDirs.cFileName, _T(".")) != 0 && _tcscmp(fDataDirs.cFileName, _T("..")) != 0)
    			{
    				ppnew<FindFilesInternalStruct> pArgs2;
    				*pArgs2 = *pArgs;
    				pArgs2->strFolder = pArgs->strFolder + _T("\\") + fDataDirs.cFileName;
    				FindFilesInternal(pArgs2, s_vFiles, rCurrentCount, rTotalCount);
    			}
    		}
    	}
    
    	return true;
    }
    Last edited by Elysia; 03-12-2008 at 05:01 PM.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. FindFirstFile
    By Coding in forum C# Programming
    Replies: 8
    Last Post: 02-13-2008, 04:49 AM
  2. Msdn example code (FindFirstFile, FindNextFile
    By Probose in forum Windows Programming
    Replies: 2
    Last Post: 09-22-2006, 04:16 PM
  3. FindFirstFile problem
    By XX@nnX in forum Windows Programming
    Replies: 7
    Last Post: 08-23-2006, 07:02 AM
  4. directories, lccwin32 and findnextfile
    By ggs in forum Windows Programming
    Replies: 6
    Last Post: 07-23-2002, 10:00 PM
  5. how do i use FindFirstFile()
    By knight543 in forum C++ Programming
    Replies: 1
    Last Post: 02-15-2002, 08:00 PM