wordexp_t fails when folder contains a space - c++

My code:
QString clsDebugService::strGetUserFolder(QString strFolder) {
QString strCopy(strFolder);
if ( strCopy.isEmpty() ) {
strCopy = "~";
}
const QChar cqcSeperator(QDir::separator());
QString strFullPath;
//Ensure path is correct before use, this will handle translation of ~ if used!
const char* cpszFolder = strCopy.toLatin1().data();
wordexp_t exp_result;
if ( wordexp(cpszFolder, &exp_result, 0) == 0 ) {
char** ppszFullPath = exp_result.we_wordv;
if ( ppszFullPath != nullptr ) {
strFullPath = *ppszFullPath;
QFileInfo info(strFullPath);
if ( info.isDir() == true && strFullPath.endsWith(cqcSeperator) != true ) {
strFullPath += cqcSeperator;
}
}
}
return strFullPath;
}
If strFolder contains:
~/XMLMPAM/config/form.xml
Then the function works and ~ is replaced with the actual user folder location, however is strFolder contains:
~/XMLMPAM 2/config/form.xml
Which also exists, the function fails and I can see when debugging that:
char** ppszFullPath = exp_result.we_wordv;
Points to:
/Users/sy/XMLMPAM
Which is my user profile folder but with the wrong folder name. Why?

The actually fix for this:
QString clsDebugService::strGetUserFolder(QString strFolder) {
QString strCopy(strFolder);
if ( strCopy.indexOf(" ") != -1 ) {
//Ensure any spaces in the path are escaped
strCopy.replace(" ", "\\ ");
} else if ( strCopy.isEmpty() ) {
strCopy = "~";
}
const QChar cqcSeperator(QDir::separator());
QString strFullPath;
//Ensure path is correct before use, this will handle translation of ~ if used!
const char* cpszFolder = strCopy.toLatin1().data();
wordexp_t exp_result;
if ( wordexp(cpszFolder, &exp_result, 0) == 0 ) {
char** ppszFullPath = exp_result.we_wordv;
if ( ppszFullPath != nullptr ) {
strFullPath = *ppszFullPath;
QFileInfo info(strFullPath);
if ( info.isDir() == true && strFullPath.endsWith(cqcSeperator) != true ) {
strFullPath += cqcSeperator;
}
}
}
return strFullPath;
}

Related

zlib minizip unpacked executables are corrupted

I'm trying to use miniunzip to extract some files. It works on Linux. On Windows, it throws no errors, but if the file is executable, the resulting binary doesn't work. I get a message window with a message about incompatibility with 64-bit Windows. If I use another utility, such as 7-zip, to unpack it, everything works fine, so the problem is here in my code. Here is the class method that does all the work.
bool FileHandler::unzip( string inputFile, string outputDirectory )
{
if (!fileExists(inputFile)) {
this->errorMessage = "Can't find file at " + inputFile;
return false;
}
unzFile zipFile = unzOpen(inputFile.c_str());
if( zipFile == nullptr ){
this->errorMessage = "FileHandler::unzip failed to open input file";
return false;
}
vector<string> files;
vector<string> folders;
unz_global_info globalInfo;
int err = unzGetGlobalInfo( zipFile, &globalInfo );
if (unzGoToFirstFile(zipFile) != UNZ_OK) {
this->errorMessage = "FileHandler::unzip failed calling unzGoToFirstFile";
return false;
}
for ( unsigned long i=0; i < globalInfo.number_entry && err == UNZ_OK; i++ ){
char filename[FILENAME_MAX];
unz_file_info subFileInfo;
err = unzGetCurrentFileInfo( zipFile, &subFileInfo, filename,
sizeof(filename), NULL, 0, NULL, 0);
if ( err == UNZ_OK )
{
char nLast = filename[subFileInfo.size_filename-1];
if ( nLast =='/' || nLast == '\\' )
{
folders.push_back(filename);
}
else
{
files.push_back(filename);
}
err = unzGoToNextFile(zipFile);
}
}
for ( string & folder : folders ){
string strippedFolder = folder.substr(0, folder.length()-1);
string dirPath = normalizePath(outputDirectory+"/"+strippedFolder);
if( ! makeDirectory( dirPath ) ){
this->errorMessage = "FileHandler::unzip Failed to create directory "+dirPath;
return false;
}
}
for ( auto it = files.begin(); it != files.end(); it++ ){
if( zipFile == 0 ){
this->errorMessage = "FileHandler::unzip invalid unzFile object at position 1";
return false;
}
string filename = *it;
//string filepath = outputDirectory + "/" + *it;
string filepath = normalizePath( outputDirectory + "/" + *it );
const char * cFile = filename.c_str();
const char * cPath = filepath.c_str();
int err = unzLocateFile( zipFile, cFile, 0 );
if ( err != UNZ_OK ){
this->errorMessage = "FileHandler::unzip error locating sub-file.";
return false;
}
err = unzOpenCurrentFile( zipFile );
if( err != UNZ_OK ){
this->errorMessage = "FileHandler::unzip error opening current file";
return false;
}
ofstream fileStream{ cPath };
// Need an ostream object here.
if( fileStream.fail() ){
this->errorMessage = "FileHandler::unzip error opening file stream at "+string(cPath);
return false;
}
unz_file_info curFileInfo;
err = unzGetCurrentFileInfo( zipFile, &curFileInfo, 0, 0, 0, 0, 0, 0);
if ( err != UNZ_OK )
{
this->errorMessage = "FileHandler::unzip failed to read size of file";
return false;
}
unsigned int size = (unsigned int)curFileInfo.uncompressed_size;
char * buf = new char[size];
size = unzReadCurrentFile( zipFile, buf, size );
if ( size < 0 ){
this->errorMessage = "FileHandler::unzip unzReadCurrentFile returned an error. ";
return false;
}
fileStream.write( buf, size );
fileStream.flush();
delete [] buf;
fileStream.close();
#ifndef _WIN32
vector<string> parts = splitString(filename, ".");
if( parts.size() == 1 ){ // In linux, assume file without extension is executable
mode_t old_mask = umask( 000 );
chmod( cPath, S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH );
umask( old_mask );
}
#endif
unzCloseCurrentFile( zipFile );
}
unzClose(zipFile);
return true;
}
std::ostream opens files in text mode by default, you need to make it use binary mode instead.
On Linux there doesn't seem to be any difference between text and binary modes. But on Windows, attempting to write \n into a text file produces \r\n, currupting your data.
You need to change this line
ofstream fileStream{ cPath };
to
ofstream fileStream{ cPath, ostream::out | ostream::binary };

Cannot read to file(exist) with UNICODE

I have a project which need to read path of SysData file.I want to move SysData file which contains "ç","ş","ğ" path way but cannot read this char.I have to read with UNICODE(like that utf-8).
There is code;
bool TSimTextFileStream::ReadLine ( mstring * str )
{
*str = "";
char c = ' ';
bool first = true;
// while ( read ( hFile, &c, 1 ) )
while ( fread ( &c, 1, 1, hFile ) )
{
if (first) first = false;
#ifdef __linux__
if ( c == 13 )
continue;
else
if ( c == 10 )
break;
else
*str += c;
#else
if( c == 13 || c == 10)
break;
else
*str += c;
#endif
}
return !first;
}
And there is code, calling this method;
mstring GetSysDataDirectory ( )
{
static mstring sysDataDir = "";
if ( sysDataDir == "" )
{
if (mIsEnvironmentVarExist("SYSDATAPATH"))
{
mstring folder = mGetEnvVar("SYSDATAPATH");
if (folder.size() == 0)
{
folder = mGetCurrentDir ( ) + "/SysData";
}
sysDataDir = folder;
}
else if ( mIsFileExist ( "SysDataPath.dat" ) )
{
TSimTextFileStream txtfile;
txtfile.OpenFileForRead( "SysDataPath.dat" );
mstring folder;
if ( txtfile.ReadLine( &folder ) )
{
sysDataDir = folder;
}
else
{
sysDataDir = mGetCurrentDir ( ) + "/SysData";
}
}
else
{
sysDataDir = mGetCurrentDir ( ) + "/SysData";
}
}
return sysDataDir;
}
I search and find some solution but not work, like that;
bool TSimTextFileStream::OpenFileForRead(mstring fname)
{
if (hFile != NULL) CloseFile();
hFile = fopen(fname.c_str(), "r,ccs=UNICODE");
if (hFile == NULL) return false; else return true;
}
and tried this;
hFile = fopen(fname.c_str(), "r,ccs=UTF-8");
But not work again. Can you help me please?
enter image description here
This situation is my problem :((
Windows does not support UTF-8 encoded path names for fopen:
The fopen function opens the file that is specified by filename. By
default, a narrow filename string is interpreted using the ANSI
codepage (CP_ACP).
Source.
Instead, a second function, called _wfopen is provided, which accepts a wide-character string as path argument.
Similar restrictions apply when using the C++ fstreams for File I/O.
So the only way for you to solve this is by converting your UTF-8 encoded pathname either to the system codepage or to a wide character string.
fopen usually reads unicode chars. try to change the files encoding

Programmatically modify/create vcproj files

I have a visual c++ project file (vcproj) and i want to programmatically modify it in order to add additional include directories or link libraries.
One solution could be to parse the vcproj as an XML file and modify it. There is any other API to make this easier?
Here is some code I wrote for fetching from a Visual Studio solution (.sln) all the projects it contains, and from each project, all the file (including full paths) it contain.
static strList parseSolution( const char * solName )
{
strList result;
static char drive[_MAX_DRIVE];
static char somepath[_MAX_PATH];
static char buffer[_MAX_PATH];
static char path[_MAX_PATH];
static char ext[_MAX_EXT];
_splitpath( solName, drive, somepath, buffer, ext );
FILE * f = fopen( solName, "r" );
if( NULL == f )
{
printf("ERROR: Solution %s is missing or unavailable.\n", solName );
exit(1);
}
while( !feof(f) )
{
char * res = fgets( buffer, sizeof(buffer), f );
if( NULL == res )
continue;
if( NULL != strstr(buffer, "Project(") )
{
char * ptrName = strchr( buffer, '=' );
char * ptrFile = strchr( ptrName, ',' );
*ptrFile++ = 0;
char * ptrEnd = strchr( ptrFile, ',' );
*ptrEnd++ = 0;
while( ('=' == *ptrName)
||(' ' == *ptrName)
||('"' == *ptrName) ) ptrName++;
if( '"' == ptrName[strlen(ptrName)-1] )
ptrName[strlen(ptrName)-1] = 0;
while( (' ' == *ptrFile)
||('"' == *ptrFile) ) ptrFile++;
if( '"' == ptrFile[strlen(ptrFile)-1] )
ptrFile[strlen(ptrFile)-1] = 0;
_makepath( path, drive, somepath, ptrFile, NULL );
result.push_back( std::string(path) );
}
}
fclose(f);
return result;
}
/**
* Parse project and extract fullpath source filename from project.
*/
static strList parseProject( const char * projName )
{
strList result;
static char drive[_MAX_DRIVE];
static char somepath[_MAX_PATH];
static char buffer[_MAX_PATH];
static char path[_MAX_PATH];
static char ext[_MAX_EXT];
_splitpath( projName, drive, somepath, buffer, ext );
FILE * f = fopen( projName, "r" );
if( NULL == f )
{
printf("ERROR: Project %s is missing or unavailable.\n", projName );
exit(1);
}
while( !feof(f) )
{
char * res = fgets( buffer, sizeof(buffer), f );
if( NULL == res )
continue;
if( (NULL != strstr(buffer, "<ClInclude Include="))
||(NULL != strstr(buffer, "<ClCompile Include=")) )
{
char * ptrName = strchr( buffer, '=' );
char * ptrName1 = strstr( buffer, "/>" );
if( NULL != ptrName1 ) *ptrName1 = 0;
while( ('=' == *ptrName)
||(' ' == *ptrName)
||('"' == *ptrName) ) ptrName++;
while( ('"' == ptrName[strlen(ptrName)-1])
||(' ' == ptrName[strlen(ptrName)-1])
||('\n' == ptrName[strlen(ptrName)-1]))
ptrName[strlen(ptrName)-1] = 0;
_makepath( path, drive, somepath, ptrName, NULL );
result.push_back( std::string(path) );
}
}
fclose(f);
return result;
}
/**
* Recoding source file.
*/
Using these functions you can work on each file, or work on the projects themselves.
strList projectList = parseSolution( argv[1] );
strList::iterator itProj = projectList.begin();
while( itProj != projectList.end() )
{
printf("Project: %s\n", itProj->c_str());
strList fileName = parseProject( itProj->c_str() );
strList::iterator itFile = fileName.begin();
while( itFile != fileName.end() )
{
printf(" File %s\n", itFile->c_str());
// do something with the project file
itFile++;
}
fileName.clear();
itProj++;
}

Stack overflow in recursive function

I am writing a simple app that outputs all files in some directory to console. To achieve this I dynamically allocate memory in function PathCreator() and return a pointer to this memory. I don't know how to correctly free this memory segment in GetAllFiles(). When I use the code below I get a stack overflow exception. How can I fix this? Please don't offer me to use something that doesn't need dynamically allocated memory, I just want to fix my code.
#include "stdafx.h"
#include <windows.h>
#include <iostream>
wchar_t *PathCreator(wchar_t *dir, wchar_t *fileName);
int is_directory(wchar_t *p)
{
wchar_t *t = PathCreator(p,L"\\");
WIN32_FIND_DATA file;
HANDLE search_hendle = FindFirstFile(t, &file);
long error = GetLastError();
if(error == 267)
{
return 0;
}
else
{
return 1;
}
}
wchar_t *PathCreator(wchar_t *dir, wchar_t *fileName)
{
wchar_t* path = 0;
int size = 0;
wchar_t *d = dir;
wchar_t *f = fileName;
while(*d != '\0')
{
d++;
size++;
}
while(*f != '\0')
{
f++;
size++;
}
path = new wchar_t[(size+=3) * sizeof(wchar_t)];
int j = 0;
while(j < size)
{
path[j] = '\0';
j++;
}
int i;
i = 0;
while(*dir != '\0')
{
path[i] = *dir;
i++;
dir++;
}
path[i++] = '\\';
wchar_t *t = fileName;
while(*t != '\0')
{
path[i] = *t;
i++;
t++;
}
path[i] = '\0';
return path;
}
void GetAllFiles(wchar_t* dir)
{
wchar_t *p = 0;
int i = 0;
WIN32_FIND_DATA file;
wchar_t *t = PathCreator(dir, L"*");
HANDLE search_hendle = FindFirstFile(t, &file);
if(search_hendle)
{
do
{
p = PathCreator(dir,file.cFileName);
if(!is_directory(p))
{
std::wcout << p << std::endl;
}
else
{
GetAllFiles(p);
}
delete [] p;
}
while(FindNextFile(search_hendle, &file));
}
delete [] t;
FindClose(search_hendle);
}
int _tmain(int argc, _TCHAR* argv[])
{
GetAllFiles(L"C:\\Users");
}
So, you have "." and ".." in your directory search.
The first entry is ".", so:
p = PathCreator(dir, file.cFilename)
yields:
"C:\Users\."
Then the next line:
if (!is_directory(p))
Is ALWAYS false, so it just keeps recursing into:
GetAllFiles(p)
forever ... or until your stack blows up, whichever comes first ;-)
I would recommend explicitly checking for "." and ".." and skipping those entries (also MFC and Qt, etc. have nice directory handling classes, but I think you want to do it this way).
My modification:
do
{
// I added this - guess I can't embolden code text
if (wcscmp(file.cFileName,L".") == 0 || wcscmp(file.cFileName,L"..")==0)
continue;
p = PathCreator(dir,file.cFileName);
if(!is_directory(p))
{
std::wcout << p << std::endl;
}
else
{
GetAllFiles(p);
}
delete [] p;
}
while(FindNextFile(search_hendle, &file));
Again you try to use C in place of C++ and you still using wcout?! no problem you are a programmer and I'm sure you have a reason for this! but memory management in C is much much harder than C++ and you should have some skills to use it. Here is a fully working code but as you see it is really harder to manage, use and understand than its C++ version using standard containers and string, so if you are allowed to use C++(as you use wcout) then use its C++ version for ease:
#include <Windows.h>
/*! \brief Merge \a folder and \a filename into a newly allocate memory and
* return it to the caller. Use free to free returned memory!
*/
wchar_t* PathCreator( wchar_t const* folder, wchar_t const* filename )
{
wchar_t* res;
size_t i, len, folderLen = wcslen( folder ), filenameLen = wcslen( filename );
len = folderLen + filenameLen;
if( folder[folderLen - 1] != '\\' ) ++len;
++len; // for \0
res = (wchar_t*) malloc( sizeof(wchar_t) * len );
if( !res ) return NULL;
wcscpy_s( res, len, folder );
/* Remove possible wide card at end of folder */
for( i = folderLen; i--; ) {
if( res[i] == '*' || res[i] == '?' ) {
res[i] = 0;
--folderLen;
} else {
break;
}
}
if( res[folderLen - 1] != '\\' ) wcscat_s( res, len, L"\\" );
wcscat_s( res, len, filename );
return res;
}
/*! \brief Free memory that returned by \ref GetAllFiles
*/
void FreeAllFilesMemory( wchar_t** p )
{
wchar_t** tmp = p;
if( !p ) return ;
while( *tmp ) free( *tmp++ );
free( p );
}
wchar_t** AddToArray( wchar_t** p, size_t* pAllocated, size_t* pUsed, wchar_t* s )
{
if( *pUsed >= *pAllocated ) {
size_t newAlloc = *pAllocated * 3 / 2; // Grow by 1.5
if( newAlloc < 16 ) newAlloc = 16;
p = (wchar_t**) realloc( p, newAlloc * sizeof(wchar_t*) );
if( !p ) return NULL;
*pAllocated = newAlloc;
}
p[*pUsed] = s;
++*pUsed;
return p;
}
wchar_t** GetAllFilesImpl( wchar_t const* folder, wchar_t** res, size_t* pAllocated, size_t* pUsed )
{
HANDLE hSearch;
WIN32_FIND_DATAW fileinfo;
size_t allocatedMemory = 0;
hSearch = FindFirstFileW( folder, &fileinfo );
if( hSearch != INVALID_HANDLE_VALUE ) {
do {
wchar_t* sFileName, ** tmp, sTmp[ 1024 ];
/* ignore ., .. */
if( !wcscmp(fileinfo.cFileName, L".") ||
!wcscmp(fileinfo.cFileName, L"..") )
continue;
sFileName = PathCreator( folder, fileinfo.cFileName );
wprintf( L"%s\n", sFileName ); /* Print result */
tmp = AddToArray( res, pAllocated, pUsed, sFileName );
if( !tmp ) return FreeAllFilesMemory(res), NULL;
res = tmp;
if( fileinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
wcscpy_s( sTmp, sFileName );
wcscat_s( sTmp, L"\\*" );
tmp = GetAllFilesImpl( sTmp, res, pAllocated, pUsed );
if( !tmp ) return NULL;
res = tmp;
}
} while( FindNextFileW(hSearch, &fileinfo) );
FindClose( hSearch );
}
return res;
}
/*! \brief List all files that match a pattern and return it as an array of
* wide strings, free result using \ref FreeAllFilesMemory
*/
wchar_t** GetAllFiles( wchar_t const* folder )
{
size_t nAllocated = 0, nUsed = 0;
wchar_t** res = GetAllFilesImpl( folder, NULL, &nAllocated, &nUsed );
if( res ) {
/* to indicate end of result add a NULL string */
wchar_t** tmp = AddToArray( res, &nAllocated, &nUsed, NULL );
if( !tmp ) return FreeAllFilesMemory(res), NULL;
res = tmp;
}
return res;
}

recursive file search

I'm trying to figure out how to work this thing out .. For some reason, it ends at a certain point.. I'm not very good at recursion and I'm sure the problem lies somewhere there..
Also, even if I checked for cFileName != "..", it still shows up at the end, not sure why but the "." doesn't show up anymore..
void find_files( wstring wrkdir )
{
wstring temp;
temp = wrkdir + L"\\" + L"*";
fHandle = FindFirstFile( temp.c_str(), &file_data );
if( fHandle == INVALID_HANDLE_VALUE )
{
return;
}
else
{
while( FindNextFile( fHandle, &file_data ) )
{
if( file_data.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY &&
wcscmp(file_data.cFileName, L".") != 0 &&
wcscmp(file_data.cFileName, L"..") != 0 )
{
find_files( wrkdir + L"\\" + file_data.cFileName );
}
else if( file_data.dwFileAttributes != FILE_ATTRIBUTE_HIDDEN &&
file_data.dwFileAttributes != FILE_ATTRIBUTE_SYSTEM )
{
results << wrkdir << "\\" << file_data.cFileName << endl;
}
}
}
}
After changing those, the program doesn't enumerate the remaining files left..
For example, if there is a sub folder named test, it enumerates everything inside test but doesn't finish enumerating the files inside the original directory specified.
From the FindFirstFile documentation:
If the function fails or fails to
locate files from the search string in
the lpFileName parameter, the return
value is INVALID_HANDLE_VALUE and the
contents of lpFindFileData are
indeterminate.
You should only exit from the one iteration not the whole program:
if( fHandle == INVALID_HANDLE_VALUE )
{
return;
}
And this may solve your other problem:
else if( file_data.dwFileAttributes != FILE_ATTRIBUTE_HIDDEN &&
file_data.dwFileAttributes != FILE_ATTRIBUTE_SYSTEM &&
wcscmp(file_data.cFileName, L".") != 0 &&
wcscmp(file_data.cFileName, L"..") != 0
)
{
results << wrkdir << "\\" << file_data.cFileName << endl;
}
Also see #fretje's answer as well. It gives another problem that your code has.
Updated new: You need to use fHandle as a local variable as well, not global variable.
Change to:
HANDLE fHandle = FindFirstFile( temp.c_str(), &file_data );
You are changing the value of your local wrkdir variable:
wrkdir = wrkdir + L"\\" + file_data.cFileName;
find_files( wrkdir );
I think you have to call find_files there like this:
find_files( wrkdir + L"\\" + file_data.cFileName );
and not change the value of wrkdir.
There are still several bugs in your code. Try this instead:
void find_files( wstring wrkdir )
{
wstring wrkdirtemp = wrkdir;
if( !wrkdirtemp.empty() && (wrkdirtemp[wrkdirtemp.length()-1] != L'\\') )
{
wrkdirtemp += L"\\";
}
WIN32_FIND_DATA file_data = {0};
HANDLE hFile = FindFirstFile( (wrkdirtemp + L"*").c_str(), &file_data );
if( hFile == INVALID_HANDLE_VALUE )
{
return;
}
do
{
if( file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
{
if( (wcscmp(file_data.cFileName, L".") != 0) &&
(wcscmp(file_data.cFileName, L"..") != 0) )
{
find_files( wrkdirtemp + file_data.cFileName );
}
}
else
{
if( (file_data.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) == 0 )
{
results << wrkdirtemp << file_data.cFileName << endl;
}
}
}
while( FindNextFile( hFile, &file_data );
FindClose( hFile );
}
Recursive file search with dirent.h
#include <iostream>
#include <dirent.h>
#include <string.h>
bool isUpDirecory(const char* directory) {
if (strcmp(directory, "..") == 0 || strcmp(directory, ".") == 0)
return true;
else
return false;
}
bool findFile(const std::string& fileName, const std::string& path,
std::string& resultPath) {
dirent* entry;
DIR* dir = opendir(path.c_str());
if (dir == NULL)
return false;
while ((entry = readdir(dir)) != NULL) {
if (entry->d_type == DT_REG) {
if (fileName.compare(entry->d_name) == 0) {
resultPath = path + "/" + entry->d_name;
closedir(dir);
return true;
}
}
}
rewinddir(dir);
while ((entry = readdir(dir)) != NULL) {
if (entry->d_type == DT_DIR) {
if (!isUpDirecory(entry->d_name)) {
std::string nextDirectoryPath = path + "/" + entry->d_name;
bool result = findFile(fileName, nextDirectoryPath, resultPath);
if (result == true) {
closedir(dir);
return true;
}
}
}
}
closedir(dir);
return false;
}
int main() {
std::string path;
bool result = findFile("text.txt", "/home/lamerman/", path);
std::cout << path << std::endl;
return 0;
}
Also, check out the implementation of the CFileFind MFC class.
You still have errors in your code:
you ignore the results of the first search. you call FindFirstFile and handle if it fails. But if it succeeds you do not process already fetched file_data and overwrite it with FindNextFile.
You don't close the search handle. Use FindClose for that.
From your existing code it seems that fHandle is global - it shouldn't. It would break your recursion.
Also I think that you can resolve all the issues in your code by paying more attention to MSDN sample provided in FindFirstFile documentation.