| . | . |
| . | ![]() |
. | . |
| . | . |
| . |
Logging a directory, part 2.As an exercise, change the pathname in the program in such a way as that FindFirstFile() will not find anything. I changed it to look for "C:\\Windows\\*.exx", (there were no .exx files, I checked!), I got this...
... not pretty, and unlikely to be much help to your program. In part 1 of the tutorial, I told you FindFirstFile() returns a search handle if there are no errors. If there is an error, and the routine includes the case where no files match the specification as an error, it returns the constant value INVALID_HANDLE_VALUE. Rather than assume FindFirstFile() is returning a valid handle, we must check it. We also need to know if the reason INVALID_HANDLE_VALUE was because there were no files found, or that some other error has occurred. To do that, we will use the GetLastError() routine which is often used to get more information about the reason an API routine returned an error status, it is a routine you will come to call a friend! I have modified part of the original program to implement these checks...
hFind = FindFirstFile("C:\\Windows\\*.exe", &FindData);
if(hFind == INVALID_HANDLE_VALUE)
{
ErrorCode = GetLastError();
if (ErrorCode == ERROR_FILE_NOT_FOUND)
{
cout << "There are no files matching that path/mask\n" << endl;
}
else
{
cout << "FindFirstFile() returned error code " << ErrorCode << endl;
}
}
else
{
cout << FindData.cFileName << endl;
}
... I also added this line to the variable declarations...
int ErrorCode;
... now searching for .exx files I get this...
... slightly better. Why do I say "slightly better", are we not finished? No, we're not. We appear to be getting the right output, but in fact, the reason is because the call to FindNextFile() is failing, the search handle is invalid. In actual fact, if there are no files, we don't even need to call FindNextFile(), or FindClose() for that matter as a search has never been "opened". Now I've added this line to the declarations...
boolean Continue = TRUE;
... and changed the "if" block in the code above such that if the call to FindFirstFile() returned INVALID_HANDLE_VALUE the boolean variable "Continue" is set to FALSE...
if(hFind == INVALID_HANDLE_VALUE)
{
ErrorCode = GetLastError();
if (ErrorCode == ERROR_FILE_NOT_FOUND)
{
cout << "There are no files matching that path/mask\n" << endl;
}
else
{
cout << "FindFirstFile() returned error code " << ErrorCode << endl;
}
Continue = FALSE;
}
else
{
cout << FindData.cFileName << endl;
}
... now when we get to the second part of the program, we can test "Continue" to see if we need to call the other routines or not, thus...
if (Continue)
{
while (FindNextFile(hFind, &FindData))
{
cout << FindData.cFileName << endl;
}
FindClose(hFind);
}
... so now are we finished? Er, strictly speaking, no. From the first part of the tutorial, you may remember that FindNextFile() returns FALSE when there are no more files, or if an error occurs. Now realistically, it is unlikely that the FALSE return would mean anything else, so in the vast majority of cases, what we have now is good enough, if you really want to make a more professional job, you should check the return of both FindNextFile() and FindClose() which also returns FALSE if it encounters an error. Both of these checks are made in this program...
#include <windows.h>
#include <iostream>
using namespace std;
int main()
{
HANDLE hFind;
WIN32_FIND_DATA FindData;
int ErrorCode;
BOOL Continue = TRUE;
cout << "A decent FindFirst/Next demo." << endl << endl;
hFind = FindFirstFile("C:\\Windows\\*.exe", &FindData);
if(hFind == INVALID_HANDLE_VALUE)
{
ErrorCode = GetLastError();
if (ErrorCode == ERROR_FILE_NOT_FOUND)
{
cout << "There are no files matching that path/mask\n" << endl;
}
else
{
cout << "FindFirstFile() returned error code " << ErrorCode << endl;
}
Continue = FALSE;
}
else
{
cout << FindData.cFileName << endl;
}
if (Continue)
{
while (FindNextFile(hFind, &FindData))
{
cout << FindData.cFileName << endl;
}
ErrorCode = GetLastError();
if (ErrorCode == ERROR_NO_MORE_FILES)
{
cout << endl << "All files logged." << endl;
}
else
{
cout << "FindNextFile() returned error code " << ErrorCode << endl;
}
if (!FindClose(hFind))
{
ErrorCode = GetLastError();
cout << "FindClose() returned error code " << ErrorCode << endl;
}
}
return 0;
}
... now we have logged a directory! If you specify "*.*" as your file mask, you will get everything in the directory. There are 2 "files" that may suprise you when you do this, one called "." and another called "..". The first is a self reference to the directory being scanned, the second, one to the directory's parent directory. The best advice I can give you is to ignore these "files", and do not try to do any processing with them. Is there any more to say? Actually, enough people have asked questions concerning this tutorial that I have added a third page dealing with these additional topics which you may like to read, or at least skip through. |
. |
| . | . |
| . | . |
| . | . |