Listing the Files in a Directory
The following example calls FindFirstFile, FindNextFile, and FindClose to list files in a specified directory.
#include <windows.h> #include <tchar.h> #include <stdio.h> #include <strsafe.h> #pragma comment(lib, "User32.lib") void DisplayErrorBox(LPTSTR lpszFunction); int _tmain(int argc, TCHAR *argv[]) { WIN32_FIND_DATA ffd; LARGE_INTEGER filesize; TCHAR szDir[MAX_PATH]; size_t length_of_arg; HANDLE hFind = INVALID_HANDLE_VALUE; DWORD dwError=0; // If the directory is not specified as a command-line argument, // print usage. if(argc != 2) { _tprintf(TEXT("\nUsage: %s <directory name>\n"), argv[0]); return (-1); } // Check that the input path plus 3 is not longer than MAX_PATH. // Three characters are for the "\*" plus NULL appended below. StringCchLength(argv[1], MAX_PATH, &length_of_arg); if (length_of_arg > (MAX_PATH - 3)) { _tprintf(TEXT("\nDirectory path is too long.\n")); return (-1); } _tprintf(TEXT("\nTarget directory is %s\n\n"), argv[1]); // Prepare string for use with FindFile functions. First, copy the // string to a buffer, then append '\*' to the directory name. StringCchCopy(szDir, MAX_PATH, argv[1]); StringCchCat(szDir, MAX_PATH, TEXT("\\*")); // Find the first file in the directory. hFind = FindFirstFile(szDir, &ffd); if (INVALID_HANDLE_VALUE == hFind) { DisplayErrorBox(TEXT("FindFirstFile")); return dwError; } // List all the files in the directory with some info about them. do { if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { _tprintf(TEXT(" %s <DIR>\n"), ffd.cFileName); } else { filesize.LowPart = ffd.nFileSizeLow; filesize.HighPart = ffd.nFileSizeHigh; _tprintf(TEXT(" %s %ld bytes\n"), ffd.cFileName, filesize.QuadPart); } } while (FindNextFile(hFind, &ffd) != 0); dwError = GetLastError(); if (dwError != ERROR_NO_MORE_FILES) { DisplayErrorBox(TEXT("FindFirstFile")); } FindClose(hFind); return dwError; } void DisplayErrorBox(LPTSTR lpszFunction) { // Retrieve the system error message for the last-error code LPVOID lpMsgBuf; LPVOID lpDisplayBuf; DWORD dw = GetLastError(); FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); // Display the error message and clean up lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, (lstrlen((LPCTSTR)lpMsgBuf)+lstrlen((LPCTSTR)lpszFunction)+40)*sizeof(TCHAR)); StringCchPrintf((LPTSTR)lpDisplayBuf, LocalSize(lpDisplayBuf) / sizeof(TCHAR), TEXT("%s failed with error %d: %s"), lpszFunction, dw, lpMsgBuf); MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK); LocalFree(lpMsgBuf); LocalFree(lpDisplayBuf); }
Send comments about this topic to Microsoft
Build date: 4/17/2012
If a directory contains characters outside of the current codepage, be it ANSI or OEM then you will get this behaviour, so it is expected. If a directory contains a character which isn't in the current codepage then it will be converted to either a fallback character or the substitute character. Example of fallback characters is fullwidth Latin characters from East Asian codepages get converted to the standard Latin characters in western codepages. If there is no fallback character in the current codepage then it will convert the character to the substitute character, which is a ?. These are basics that you should know, especially after dealing with MultiByteToWideChar and WideCharToMultiByte.
Whats more, directories going in will be converted based on the input codepage. So again, these will be converted to ?s or the fallback character. Which is why it will fail with either error 3 (file not found) or error 123 (incorrect syntax).
This is why using Unicode builds isn't a work around, it is the recommended way. You also don't have the conversion overhead that using the non Unicode version has and it also does no conversion on the input parameters so you get what you type in. Whats more, the output is dependent on the font installed on your system, so if you have a font which supports the correct character ranges then the output will be properly.
- 11/25/2010
- crescens2k
- 6/4/2010
- AceAmit
Note: The above example when compiled for 8-bit strings (LPCSTR) will display incorrectly if a file's name contains characters outside of the 7-bit ASCII character set. And FindFirstFile will fail if argv[1] contains such characters. Console applications use the OEM codepage, not the ANSI codepage. The workaround is to build the example with UNICODE (LPCWSTR). Or call SetFileApisToOem() and use CharToOem(argv[i]) for each argv argument
Ditto the use of the global array __argv. See also setlocale(LC_ALL, ".OCP")
Update for East-Asian Users: After I posted the above information my Chinese friends have informed me that the OEM code page might not be used by the console window in certain East-Asian language encodings provided in the MUI edition of Windows XP. If (for example) the user switches to MUI=Chinese Simplified, the console switches to the Chinese ANSI code page 936 (simplified Chinese GBK encoding). In this case the console is using the ANSI code page, not the OEM code page 437, so the above code will work as designed (ironically enough).