How to get the list of all drives in C - c

Is there any method using which i can list down all the available drives and their folder content. ie i want to access all the drives and then the folders in each drive and then the sub-folders of each folder and so on till the last possible level in each drive.
C language .. Windows platform .. i have tried using alphabetic array with system() but am unable to get the names of files and folders .

This is not "standard C" (ie: ANSI, C89, C99, etc), but it makes minimal use of operating-system specific calls (ie: just "windows.h", not MS .NET or MFC technologies). This is the minimalist approach to what you are attempting to do. Once you have a list of all drive letters, you need to query each drive recursively for its directory listings.
This is a mix of C and C++, but you'll likely be using a free version of Visual Studio to build this anyways.
Code Listing - Get drive letters
#include <windows.h>
#include <stdio.h>
int main()
{
char buf[255];
// get the drive letters as a set of strings
int sz = GetLogicalDriveStrings(sizeof(buf), buf);
if( sz > 0)
{
// buf now contains a list of all the drive letters. Each drive letter is
// terminated with '\0' and the last one is terminated by two consecutive '\0' bytes.
char* p1 = buf;
char* p2;
while( *p1 != '\0' && (p2 = strchr(p1,'\0')) != NULL )
{
printf("%s\n", p1);
p1 = p2+1;
}
}
else
{
// Oops! something went wrong so display the error message
DWORD dwError = GetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, dwError, 0, buf, sizeof(buf), 0);
printf("%s\n", buf);
}
}
Code Listing - Directory listing
#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);
}
References
List Windows Logical Drive Letters, Accessed 2014-08-01, <http://www.daniweb.com/software-development/c/code/237803/list-windows-logical-drive-letters>
Listing the Files in a Directory, Accessed 2014-08-01, <http://msdn.microsoft.com/en-us/library/windows/desktop/aa365200%28v=vs.85%29.aspx>

Standard C has no way to directly address the drive, or, for that matter, even know what a drive is.
Generally, each C compiler vendor will include a library which handles those things for the specific platform the compiler is written for. But these are all specific to the vendor.
Boost has cross-platform library for C++, including one for dealing with the file system.

Related

How can I list all files in a directory on Windows without using dirent.h in C?

I can't find any way to list all files without using dirent.h. Does anyone have an idea or suggestions?
I can't work with dirent.h because my compiler doesn't work with it, so this is why I am searching for another option
I run and write the program on Windows 10.
You want to use FindFirstFile, FindNextFile, and FindClose. Microsoft provides an example on MSDN:
Listing the Files in a 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);
}

A function works when I use gcc, but when I use Microsoft Visual Studio's compiler it does nothing

When I run this with gcc using code:blocks, it creates the registration.txt on F if it doesn't exist and writes the password and username, but when I use this in my project using Microsoft Visual Studio's compiler it does nothing.
For example if I call this function such as: Write("JohnDoe", "password123"),
in the file registration.txt should appear in a line: JohnDoe, password123.
const char *FILEPATH = "F:\\registration.txt";
int Write(char *username, char *password) {
if (username == NULL || password == NULL) {
return -1;
}
BOOL error = TRUE;
size_t lengthUsername = strlen(username);
size_t lengthPassword = strlen(password);
LPDWORD bytesUsernameWritten = 0;
char comma[2] = ",";
char newLine[3] = "\r\n";
LPDWORD bytesPasswordWritten = 0;
LPDWORD bytesWrittenComma = 0;
//if the file doesn't exist, we create it
HANDLE file = CreateFile((LPCWSTR)FILEPATH, FILE_APPEND_DATA, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
if (file == INVALID_HANDLE_VALUE) {
if (GetLastError() != ERROR_FILE_EXISTS) {
printf("0x%x", GetLastError());
CloseHandle(file);
return -1;
} //the file exist, we try to create it
file = CreateFile((LPCWSTR)FILEPATH, FILE_APPEND_DATA, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (file == INVALID_HANDLE_VALUE) {
printf("Couldn't open the file. Error : 0x%x", GetLastError());
CloseHandle(file);
return -1;
}
}
//We try to write the username and the password in file, each combination on each line, in this format: username, password
error = WriteFile(file, username, (DWORD)lengthUsername, bytesUsernameWritten, NULL);
if (error == FALSE) {
printf("The username couldn't have been written. Error 0x%x\n", GetLastError());
CloseHandle(file);
return -1;
}
error = WriteFile(file, comma, 1, bytesWrittenComma, NULL);
if (error == FALSE) {
printf("The comma couldn't have been written. Error 0x%x\n", GetLastError());
CloseHandle(file);
return -1;
}
error = WriteFile(file, password, (DWORD)lengthPassword, bytesPasswordWritten, NULL);
if (error == FALSE) {
printf("The password couldn't have been written. Error 0x%x\n", GetLastError());
CloseHandle(file);
return -1;
}
error = WriteFile(file, newLine, 2, bytesPasswordWritten, NULL);
if (error == FALSE) {
printf("The endline couldn't have been written. Error 0x%x\n", GetLastError());
CloseHandle(file);
return -1;
}
CloseHandle(file);
return 0;
}
Your main problem is confusion between using Unicode and ASCII.
All windows API functions that take string parameters have two versions:
One that works with LPCSTR and one that works with LPCWSTR.
You can cast char * to LPCSTR and use the ASCII version CreateFileA, but you can not cast it to LPCWSTR and use the CreateFileW - the Unicode version of CreateFile as it expects strings in UCS-16 encoding where each character takes 2 bytes.
Which version of the function is called depends on a compiler flag. For CodeBlocks on Windows the default is to use ASCII versions, so your function works.
For VS the default is Unicode, so the file path string gets messed up and the file is not created.
Also, you have two other erros:
You are using WriteFile incorrectly.
The 4th parameter is a pointer, where WriteFile stores number of bytes written.
You are passing a NULL pointer, because you set variables such as bytesUsernameWritten to 0. But according to MS documentation, you can only use NULL there if the last parameter, lpOverlapped is not NULL.
What you should do, is declare bytesUsernameWritten to be DWORD and pass its address using & operator.
Otherwise, even if the function creates the file successfully, you will not get the number of bytes that were written.
You are trying to close INVALID_HANDLE_VALUE
This is unnecessary, but fortunately it should not crash you program.
Finally, there is no reason to try to call CreateFile twice.
Just use one call with OPEN_ALWAYS parameter.
This will open an existing file, but if the file does not exist it will create it automatically instead of failing.

Compile winapi with cygwin

I have tried compiling a windows executable using the win32api, however I have encountered many road blocks.
First thing to try was gcc -mno-cygwin [...] which results in gcc: error: unrecognized command line option '-mno-cygwin' which is strange since man gcc|grep -e '-mno-cygwin' is successful and mingw is installed.
No matter what other header files I try to include I always end up with unsatisfied circular include dependencies (a.h requires b.h requires a.h). What set of header files are required to properly compile an executable based on the win32 api?
header files I have tried:
w32api/winnt.h
w32api/ddk/ntddk.h
w32api/Windows.h
w32api/ntdef.h
source code:
$ cat source.c
#include <w32api/winnt.h>
#include <w32api/ddk/ntddk.h>
int main(int argc, char **argv) {
PHANDLE hProcess;
CLIENT_ID processId;
processId.UniqueProcess = (HANDLE) 1000;
processId.UniqueThread = 0;
NtOpenProcess(&hProcess, PROCESS_VM_READ|PROCESS_VM_WRITE, 0, &processId);
return 0;
}
$ gcc -o a.exe -I/usr/include/w32api -I/usr/include/w32api/ddk source.c
In file included from memoryEdit.c:1:0:
/usr/include/w32api/winnt.h:291:11: error: unknown type name 'CONST'
typedef CONST WCHAR *LPCWCH,*PCWCH;
^
[...]
$ gcc --version
gcc (GCC) 5.4.0
$ uname -a
CYGWIN_NT-6.1 HOST_NAME 2.5.2(0.297/5/3) 2016-06-23 14:29 x86_64 Cygwin
gcc -mno-cygwin has been removed ages ago.
If you want to compile a windows program you need to use not the gcc compiler, that is cygwin to cygwin, but the cross compilers cygwin to windows.
There are 2 package variants depending on the arch:
mingw64-i686-gcc
mingw64-x86_64-gcc
I had no troubles just now with a compilation in Eclipse/gcc. Here's my testfile:
/*
============================================================================
Name : win32gcctest.c
Author : Clark Thomborson
Version : 1.0
Copyright : Copyleft
Description : Testing winapi synchronous file access within Cygwin
============================================================================
*/
#include <stdio.h>
#include <windows.h>
#include <stdlib.h>
#include <fileapi.h>
void my_write(char* fname) {
HANDLE hFile;
char DataBuffer[] = "This is some test data to write to the file.";
DWORD dwBytesToWrite = (DWORD) strlen(DataBuffer);
DWORD dwBytesWritten = 0;
BOOL bErrorFlag = FALSE;
hFile = CreateFile(fname, // name of the write
GENERIC_WRITE, // open for writing
0, // do not share
NULL, // default security
CREATE_ALWAYS, // overwrite any existing file
FILE_ATTRIBUTE_NORMAL, // normal file
NULL); // no attr. template
if (hFile == INVALID_HANDLE_VALUE) {
DWORD last_err = GetLastError();
printf("Error code %d: unable to open file \"%s\" for write.\n", last_err, fname);
exit( last_err );
}
printf("Writing %d bytes to %s.\n", dwBytesToWrite, fname);
bErrorFlag = WriteFile(hFile,
DataBuffer, // start of data to write
dwBytesToWrite, // number of bytes to write
&dwBytesWritten, // number of bytes that were written
NULL); // no overlapped structure
if (FALSE == bErrorFlag) {
DWORD last_err = GetLastError();
printf("Error code %d: unable to write to file \"%s\".\n", last_err, fname);
exit( GetLastError() );
exit( last_err );
} else {
if (dwBytesWritten != dwBytesToWrite) {
// This is an error because a synchronous write that results in
// success (WriteFile returns TRUE) should write all data as
// requested. This would not necessarily be the case for
// asynchronous writes.
printf("Error: dwBytesWritten != dwBytesToWrite\n" );
exit( EXIT_FAILURE );
} else {
printf("Wrote %d bytes to %s successfully.\n", dwBytesWritten, fname);
}
}
CloseHandle(hFile);
}
HANDLE my_open_for_read(char* fname) {
HANDLE hFile;
hFile = CreateFile(
fname,
GENERIC_READ,
FILE_SHARE_DELETE, // another process may delete this file while this handle is open
NULL, // no security attributes
OPEN_EXISTING, // returns error if file not found
FILE_ATTRIBUTE_NORMAL, // no special attributes, so can't do async IO
NULL // no attributes will be copied from another file
);
if (hFile == INVALID_HANDLE_VALUE) {
DWORD last_err = GetLastError();
printf("Error code %d: unable to open file \"%s\" for read.\n", last_err, fname);
exit( last_err );
}
return hFile;
}
ssize_t my_read(HANDLE hFile, void *buffer, size_t bytes_to_read) {
DWORD bytes_read;
if (ReadFile(hFile, buffer, bytes_to_read, &bytes_read, NULL)) {
return (ssize_t) bytes_read;
} else {
DWORD last_err = GetLastError();
printf("Error code %d: unable to read file.\n", last_err );
exit( last_err );
}
}
int main(void) {
char fname[32] = "test.txt";
my_write( fname );
printf("Reading %s.\n", fname);
char buff[1024];
HANDLE hFile = my_open_for_read( fname );
ssize_t nc = my_read( hFile, buff, 1023 ); // allow room for terminating byte
if( nc >= 0 ) {
buff[nc] = 0; // terminate string
printf("Read %d characters: %s", (int) nc, buff);
return EXIT_SUCCESS;
} else { // buggy my_read()
printf("Error %d", (int) nc );
return nc;
}
}

WIndow CreateFile ReadFile WriteFile

I am a student so I apologize up front for not using the correct forum protocols. I am new to C, and really new to Win32 API. My assignment is to write a small C program that copies the contents of an existing file to a new file, using only Win32 I/O system calls: CreateFile(), ReadFile(), WriteFile(), etc... File names are to be specified on the command line. Right now I'm just trying to get the basics functions in place, I will then focus on error handling. This code compiles, creates a new file, but the data does not get copied to it. Any advice? thanks for taking a look!
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
int main(int argc, char *argv[])
{
char buff[4096];
DWORD dwBytesRead, dwBytesWritten;
DWORD dwBytesToWrite = (DWORD)strlen(buff);
//open source file and read it
HANDLE source;
// Create a handle for the source file
source=CreateFile(argv[1], GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
// Check for errors
if ( source == INVALID_HANDLE_VALUE ){
printf("Error, source file not opened.");
exit(EXIT_FAILURE);
}
else printf("The source file is %s\n", argv[1]);
//create a new file
HANDLE target;
target = CreateFile(argv[2], GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if ( target == INVALID_HANDLE_VALUE ){
printf("Error, target file not created.");
exit(EXIT_FAILURE);
}
else printf("The source file is %s\n", argv[2]);
//copy contents
ReadFile(source, buff, 4096, &dwBytesRead, NULL);
WriteFile(target, buff, dwBytesToWrite, &dwBytesWritten, NULL);
//copy complete
CloseHandle(source);
CloseHandle(target);
return 0;
}
As mentioned in comments, your code has a few mistakes in it. Try something more like this instead:
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
int main(int argc, char *argv[])
{
char buff[4096];
DWORD dwBytesRead, dwBytesWritten;
// Open the source file
HANDLE source = CreateFileA(argv[1], GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
// Check for error
if (source == INVALID_HANDLE_VALUE) {
printf("Source file not opened. Error %u", GetLastError());
return EXIT_FAILURE;
}
printf("The source file is %s\n", argv[1]);
// Create a new file
HANDLE target = CreateFileA(argv[2], GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
// Check for error
if (target == INVALID_HANDLE_VALUE) {
printf("Target file not created. Error %u", GetLastError());
CloseHandle(source);
return EXIT_FAILURE;
}
printf("The target file is %s\n", argv[2]);
// Copy contents
bool ok = true;
do {
// Read file, check for error
if (!ReadFile(source, buff, sizeof(buff), &dwBytesRead, NULL)) {
printf("Source file not read from. Error %u", GetLastError());
ok = false;
break;
}
// Check for EOF reached
if (dwBytesRead == 0) {
break;
}
// Write file, check for error
if (!WriteFile(target, buff, dwBytesRead, &dwBytesWritten, NULL)) {
printf("Target file not written to. Error %u", GetLastError());
ok = false;
break;
}
}
while (true);
// Copy complete
CloseHandle(source);
CloseHandle(target);
// Check for error
if (!ok) {
DeleteFileA(argv[2]);
return EXIT_FAILURE;
}
// all OK
return 0;
}

print all files and subdirectories in a give path

So, im writing a program to recursively print the directories/sub-directories and files in a given path. im able to go in the first sub-directory and print all the files in it. my problem right now is i need find a way to step back one directory level and continue from where i left off reading. Until the condition occurs at the original directory level.
#include "Everything.h"
#include "Strsafe.h"
WIN32_FIND_DATA ffd;
HANDLE hFind = INVALID_HANDLE_VALUE;
LARGE_INTEGER fileSize;
DWORD dwError;
void showdir(TCHAR *szDir);
int _tmain(int argc, LPCTSTR argv[])
{
TCHAR szDir[MAX_PATH];
size_t lengthOfArg;
// verify number of parameters
if (argc != 2)
{
ReportError(_T("Error: Incorrect number of arguments"), 1, FALSE);
}
// get the length of the entered directory
StringCchLength(argv[1], MAX_PATH, &lengthOfArg);
// verify that the directory path is not too long
if (lengthOfArg > MAX_PATH - 2)
{
ReportError(_T("Error: Directory too long"), 2, FALSE);
}
// attach an asterisk (wildcard search char) to end of directory path
StringCchCopy(szDir, MAX_PATH, argv[1]);
StringCchCat(szDir, MAX_PATH, _T("*"));
showdir(szDir);
}
void showdir(TCHAR *szDir)
{
// begin the search; find the first file in the directory
hFind = FindFirstFile(szDir, &ffd);
if (hFind == INVALID_HANDLE_VALUE)
{
ReportError(_T("Error in searching"), 3, TRUE);
}
//hFind = FindFirstFile(szDir, &ffd);
while (FindNextFile(hFind, &ffd) != 0)
{
if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
{
fileSize.LowPart = ffd.nFileSizeLow;
fileSize.HighPart = ffd.nFileSizeHigh;
_tprintf(_T("%s %ld\n"), ffd.cFileName, fileSize.QuadPart);
}
// did we find a directory?
// ffd.dwFileAttributes says this is a directory (FILE_ATTRIBUTE_DIRECTORY)
if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
&& (_tcscmp(ffd.cFileName, _T(".")) != 0 && (_tcscmp(ffd.cFileName, _T("..")) != 0)))
{
TCHAR fullpath[MAX_PATH];
StringCchCopy(fullpath, strlen(szDir) - 0, szDir);
StringCchCat(fullpath, MAX_PATH, ffd.cFileName);
StringCchCat(fullpath, MAX_PATH, "\\");
_tprintf(_T("<DIR> %s \n"), fullpath);
StringCchCat(fullpath, MAX_PATH, _T("*"));
showdir(fullpath);
}
// continue the search; try to find more files
}
// figure out if we encountered an error other than "no more files"
dwError = GetLastError();
if (dwError != ERROR_NO_MORE_FILES)
{
ReportError(_T("Error in searching"), 4, TRUE);
}
FindClose(hFind);
}
Your global variables
WIN32_FIND_DATA ffd;
HANDLE hFind = INVALID_HANDLE_VALUE;
LARGE_INTEGER fileSize;
DWORD dwError;
should all be local variables of showdir().
Then each recursion level has its own search handle, and when a nested showdir()
returns, the calling showdir() can simply continue enumerating its directory.
Note also that your code ignores the first file in each directory (the result
of FindFirstFile()). You could it rewrite as (error checking omitted for brevity):
hFind = FindFirstFile(szDir, &ffd);
do {
// ... handle ffd ...
} while (FindNextFile(hFind, &ffd))

Resources