On Windows QDir::mkpath and QFile::rename report success despite failing - c++

I'm trying to add auto-update functionality to the app I'm working on. My solution works well on Linux, but I'm running into weird problems on Windows.
After unpacking the update package I'm trying to move it to the destination directory using the following function:
inline void recursiveMoveOrCopy(QDir source, QDir dest, bool move)
{
auto files = source.entryInfoList(QDir::Files);
auto dirs = source.entryInfoList(QDir::Dirs|QDir::NoDotAndDotDot);
// move / copy files
bool success = QDir{}.mkpath(dest.path());
if (!success){
throw std::runtime_error(qs("Could not crate directory %1")
.arg(dest.path()).toStdString());
}
qDebug()<<"created directory"<<dest.path();
dumpvar(QDir{}.exists(dest.path()));
for (auto& file: files){
QString sourcePath = file.filePath();
QString fileName = file.fileName();
QString destPath = dest.filePath(fileName);
QString backupPath = destPath + "_bck";
bool success;
bool backup = false;
if (QFile::exists(destPath))
backup = QFile::rename(destPath, backupPath);
ON_EXIT{
if (backup) {
QFile::remove(destPath);
QFile::rename(backupPath, destPath);
}
};
if (move) success = QFile::rename(sourcePath, destPath);
else success = QFile::copy(sourcePath, destPath);
qDebug()<<qs("move from %1 to %2 was %3").arg(sourcePath, destPath, success?"successful":"not sucessful");
if (success && backup){
QFile::remove(backupPath);
backup = false;
}
if (!success){
throw std::runtime_error(qs("Failed to %1 file %2 to %3")
.arg(move?"move":"copy")
.arg(sourcePath)
.arg(destPath)
.toStdString());
}
}
// recursively move/copy dirs
for (auto &dir: dirs) recursiveMoveOrCopy(dir.filePath(), dest.filePath(dir.fileName()), move);
}
I made a small package for testing with just 2 files and 1 directory:
$ tree .
.
├── katalog
│   └── plik
└── plik2
When I try to install this "update" the following is written to debug output by the move function:
"moving C:/Users/piotrek/AppData/Local/Temp/dres-update-image to C:/Program Files (x86)/DRES"
created directory "C:/Program Files (x86)/DRES"
QDir{}.exists(dest.path()) = true
"move from C:/Users/piotrek/AppData/Local/Temp/dres-update-image/plik2 to C:/Program Files (x86)/DRES/plik2 was successful"
created directory "C:/Program Files (x86)/DRES/katalog"
QDir{}.exists(dest.path()) = true
"move from C:/Users/piotrek/AppData/Local/Temp/dres-update-image/katalog/plik to C:/Program Files (x86)/DRES/katalog/plik was successful"
As in: every single operation succeeded. But when I look into the target directory, the directory katalog doesn't exist (the file plik2 does however).
Note that even though the directory does NOT exist, QDir::exists reports that it does.
It's not a permission problem, when I was testing this I modified C:/Program Files (x86)/DRES to give Everyone full access.
Please tell me I'm not crazy. What the hell is going on here?
EDIT: Thanks to Rudolfs' suggestion to use Process Monitor I discovered the the files are actually being written to C:\Users\piotrek\AppData\Local\VirtualStore\Program Files (x86)\DRES. What exactly is going on here and how do I fix this?

Ok, I figured it out.
I had to use the following code to disable VirtualStore virtualization for the whole app:
#ifdef Q_OS_WIN32
#include <windows.h>
QString getWinError()
{
DWORD dw = GetLastError();
LPWSTR lpMsgBuf = NULL;
FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR) &lpMsgBuf,
0, NULL );
QString str = QString::fromWCharArray(lpMsgBuf);
LocalFree(lpMsgBuf);
return str;
}
bool disableVirtualStore()
{
HANDLE token;
DWORD tokenInformation = 0;
if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token)){
qWarning()<<getWinError();
return FALSE;
}
ON_EXIT{
CloseHandle(token);
};
if(!SetTokenInformation(token, TokenVirtualizationEnabled,
&tokenInformation, sizeof(tokenInformation))) {
qWarning()<<getWinError();
return FALSE;
}
return TRUE;
}
#endif
Now I can normally write to all folders that I have write access to, and since Windows no longer lies to me about having write access, I can start an elevated helper app to move files to folders where I don't have write permission.

Related

How to get the directory of the current DLL

I will build c-shared in golang -o config.dll.
Let's say the directory is c:\test\config.dll
In mail.dll, I'm going to open a configuration file.
This file is in the directory of config.dll.
c:\test\config.json
I'm calling it in c++ c:\test\c++.dll.
In c++ I use
{ // NB: XP+ solution!
HMODULE hModule = NULL;
GetModuleHandleEx(
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
(LPCTSTR)GetCurrentModule,
&hModule);
return hModule;
}
WCHAR path3[MAX_PATH + 1] = { 0 };
HMODULE hm = GetCurrentModule();
::GetModuleFileName(hm, path3, MAX_PATH);
PathRemoveFileSpec(path3);
// path3 c:\test\c++.dll
What is the equivalent of this in Go?
I try to use
os.Getwd()
runtime.Caller(1)
os.Args[0]
os.Executable()
I want to get directory c:\test\
You can use cgo to call the same function in whatever library it exists.

/usr/bin/env: node: No such file or directory , c++

i am writing some functions on c++ for compiler less to css.
i installed nodejs, less.
i created a less file test.less
#color: red;
a{color:#color;}
when i run command on terminal:
lessc test.less test.css
it created a files css with name is test.css, but when i run this command via c++, it return a error. please help me. this is my c++ function:
std::string shell_exec( std::string cmd )
{
std::string result = "";
FILE* pipe = popen(cmd.c_str(), "r");
if (pipe == NULL)
{
return result;
}
char buffer[128];
while(!feof(pipe))
{
if(fgets(buffer, 128, pipe) != NULL)
{
result += buffer;
}
}
pclose(pipe);
return result;
}
shell_exec("lessc test.less test.css");
i got a error:
/usr/bin/env: node: No such file or directory
/usr/bin/node is existed.
================ UPDATE: Fixed==================
Thank you #Bass Jobsen , #Lightness Races in Orbit
i fixed by add absolute path to lessc and nodejs
shell_exec("/usr/bin/node /usr/bin/lessc test.less test.css");
From: https://unix.stackexchange.com/a/29620
The advantage of #!/usr/bin/env python is that it will use whatever
python executable appears first in the user's $PATH.
So you should add node to the $PATH of the user that runs your script, see: https://stackoverflow.com/a/13210246/1596547
Notice that i can not compile your code, but i can when using the following code:
int main()
{
std::string r = shell_exec("lessc test.less test.css");
}
Probably also use using namespace std and string instead of std:string.

C++ Rename File # C:\Windows\System32\Drivers

SOLVED: have a look on the later posts
TASK: rename a file called TabletFilter.sys ( its my graphic tablet driver ) because windows 8 (my OS) apps needs an other driver then photoshop for the pin pressure. And I want to write a c++ program that just rename all driver files to .old
The code based on the rename example from cplusplus.com
#include <stdio.h>
int main ()
{
int result;
char oldname[] ="TabletFilter.sys";
char newname[] ="TabletFilter.sys.old";
result= rename( oldname , newname );
if ( result == 0 )
puts ( "File successfully renamed" );
else{
result= rename( newname , oldname );
if( result == 0)
puts ( "File successfully renamed" );
else
perror( "Error renaming file" );
}
return 0;
}
I tried "run as Admin" as well, but I still get
Error renaming file: No such file or directory
what can I do?
EDIT:
The file is definitly in the same folder ... i copyed them both there... even at c:\windows\ i tryed it ... and i use a manifest
Executable: TabletRenameDriver.exe
Manifest: TabletRenameDriver.exe.manifest
Sample application manifest file:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="1.0.0.0"
processorArchitecture="X86"
name="TabletRenameDriver"
type="win32"/>
<description>Description of your application</description>
<!-- Identify the application security requirements. -->
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges>
<requestedExecutionLevel
level="requireAdministrator"
uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>
i tryed uiAccess true and false.
Yes I have a problem with the rights
The driver is loaded but iam still able to change his name ... dont know why, but its possbile. I tryed it. I want to solve this problem with c++ so pls dont tell me that there are many script languages out there that can handle the problem very well ;-) I know this
The error message
No such file or directory
Means that the current directory does not contain files names "TabletFilter.sys" or "TabletFilter.sys.old".
What you can do is either:
Specify the full path to the file.
Ensure that the current directory, when your code executes, is the directory that contains your file.
However, even when you do this, your program may very well fail. You may not have sufficient rights to modify the contents of that folder. And the file you are trying to rename may well be locked if the OS has loaded the driver.
And as #Hans points out, the file system redirector could very well be confounding matters for you. The best way to avoid that is to us a 64 bit process.
I see no reason for using a C++ program here. Renaming files is a task best suited to a scripting language.
Many of those drivers are needed by Windows to startup. If you did succeed in renaming them, bad things will happen to your machine when you restart - namely your machine would not boot.
As a general rule, leave all of the stuff in C:\Windows alone, but this advice is ten-fold more important for the C:\Windows\drivers directory. Touch this folder and anything in it at your peril.
Thanks for all your help
I finished my programm and it works perfectly now
note: added "requireAdministrator" uiAccess="false" via VS2012 Settings
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
void main ()
{
bool success = false;
bool somethingWentWrong = false;
PVOID OldValue = NULL;
if( Wow64DisableWow64FsRedirection(&OldValue) )
{
success = MoveFile("C:\\Windows\\System32\\Drivers\\TabletFilter.sys", "C:\\Windows\\System32\\Drivers\\TabletFilter.sys.old");
if(success){
puts("from .sys to .sys.old");
success = MoveFile("C:\\Windows\\System32\\DriverStore\\FileRepository\\tabletfilter.inf_amd64_e7d03235d8288d3b\\TabletFilter.sys", "C:\\Windows\\System32\\DriverStore\\FileRepository\\tabletfilter.inf_amd64_e7d03235d8288d3b\\TabletFilter.sys.old");
if(!success){ puts("ERROR: C:\\Windows\\System32\\DriverStore\\FileRepository\\tabletfilter.inf_amd64_e7d03235d8288d3b\\TabletFilter.sys not found"); somethingWentWrong = true;}
success = MoveFile("C:\\Windows\\System32\\DriverStore\\FileRepository\\tabletfilter.inf_amd64_e7d03235d8288d3b\\TabletFilter.inf", "C:\\Windows\\System32\\DriverStore\\FileRepository\\tabletfilter.inf_amd64_e7d03235d8288d3b\\TabletFilter.inf.old");
if(!success){ puts("ERROR: C:\\Windows\\System32\\DriverStore\\FileRepository\\tabletfilter.inf_amd64_e7d03235d8288d3b\\TabletFilter.inf not found"); somethingWentWrong = true;}
success = MoveFile("C:\\Windows\\System32\\DriverStore\\FileRepository\\tabletfilter.inf_amd64_e7d03235d8288d3b\\TabletFilter.cat", "C:\\Windows\\System32\\DriverStore\\FileRepository\\tabletfilter.inf_amd64_e7d03235d8288d3b\\TabletFilter.cat.old");
if(!success){ puts("ERROR: C:\\Windows\\System32\\DriverStore\\FileRepository\\tabletfilter.inf_amd64_e7d03235d8288d3b\\TabletFilter.cat not found"); somethingWentWrong = true;}
}else{
puts("from .sys.old to .sys");
success = MoveFile("C:\\Windows\\System32\\Drivers\\TabletFilter.sys.old", "C:\\Windows\\System32\\Drivers\\TabletFilter.sys");
if(!success){ puts("ERROR: C:\\Windows\\System32\\Drivers\\TabletFilter.sys.old not found"); somethingWentWrong = true;}
success = MoveFile("C:\\Windows\\System32\\DriverStore\\FileRepository\\tabletfilter.inf_amd64_e7d03235d8288d3b\\TabletFilter.sys.old", "C:\\Windows\\System32\\DriverStore\\FileRepository\\tabletfilter.inf_amd64_e7d03235d8288d3b\\TabletFilter.sys");
if(!success){ puts("ERROR: C:\\Windows\\System32\\DriverStore\\FileRepository\\tabletfilter.inf_amd64_e7d03235d8288d3b\\TabletFilter.sys.old not found"); somethingWentWrong = true;}
success = MoveFile("C:\\Windows\\System32\\DriverStore\\FileRepository\\tabletfilter.inf_amd64_e7d03235d8288d3b\\TabletFilter.inf.old", "C:\\Windows\\System32\\DriverStore\\FileRepository\\tabletfilter.inf_amd64_e7d03235d8288d3b\\TabletFilter.inf");
if(!success){ puts("ERROR: C:\\Windows\\System32\\DriverStore\\FileRepository\\tabletfilter.inf_amd64_e7d03235d8288d3b\\TabletFilter.inf.old not found"); somethingWentWrong = true;}
success = MoveFile("C:\\Windows\\System32\\DriverStore\\FileRepository\\tabletfilter.inf_amd64_e7d03235d8288d3b\\TabletFilter.cat.old", "C:\\Windows\\System32\\DriverStore\\FileRepository\\tabletfilter.inf_amd64_e7d03235d8288d3b\\TabletFilter.cat");
if(!success){ puts("ERROR: C:\\Windows\\System32\\DriverStore\\FileRepository\\tabletfilter.inf_amd64_e7d03235d8288d3b\\TabletFilter.cat.old not found"); somethingWentWrong = true;}
}
if(somethingWentWrong){
puts ( "ERROR: File were set to standart!" );
success = MoveFile("C:\\Windows\\System32\\Drivers\\TabletFilter.sys.old", "C:\\Windows\\System32\\Drivers\\TabletFilter.sys");
if(!success){ puts("ERROR: C:\\Windows\\System32\\Drivers\\TabletFilter.sys.old not found"); somethingWentWrong = true;}
success = MoveFile("C:\\Windows\\System32\\DriverStore\\FileRepository\\tabletfilter.inf_amd64_e7d03235d8288d3b\\TabletFilter.sys.old", "C:\\Windows\\System32\\DriverStore\\FileRepository\\tabletfilter.inf_amd64_e7d03235d8288d3b\\TabletFilter.sys");
if(!success){ puts("ERROR: C:\\Windows\\System32\\DriverStore\\FileRepository\\tabletfilter.inf_amd64_e7d03235d8288d3b\\TabletFilter.sys.old not found"); somethingWentWrong = true;}
success = MoveFile("C:\\Windows\\System32\\DriverStore\\FileRepository\\tabletfilter.inf_amd64_e7d03235d8288d3b\\TabletFilter.inf.old", "C:\\Windows\\System32\\DriverStore\\FileRepository\\tabletfilter.inf_amd64_e7d03235d8288d3b\\TabletFilter.inf");
if(!success){ puts("ERROR: C:\\Windows\\System32\\DriverStore\\FileRepository\\tabletfilter.inf_amd64_e7d03235d8288d3b\\TabletFilter.inf.old not found"); somethingWentWrong = true;}
success = MoveFile("C:\\Windows\\System32\\DriverStore\\FileRepository\\tabletfilter.inf_amd64_e7d03235d8288d3b\\TabletFilter.cat.old", "C:\\Windows\\System32\\DriverStore\\FileRepository\\tabletfilter.inf_amd64_e7d03235d8288d3b\\TabletFilter.cat");
if(!success){ puts("ERROR: C:\\Windows\\System32\\DriverStore\\FileRepository\\tabletfilter.inf_amd64_e7d03235d8288d3b\\TabletFilter.cat.old not found"); somethingWentWrong = true;}
}else
puts ( "File successfully renamed" );
Wow64RevertWow64FsRedirection(OldValue);
}
for(unsigned long tick = GetTickCount() / 1000; tick + 2 > GetTickCount() / 1000;){
}
}
With only 48 lines of code ... can a script be shorter?
PS: Revisiting this post after some time, I think there are quite a few ways to approach this issue differently. However, the main point still stands: If you want to do something like this, you have to run with admin permissions ... and maybe use loops, lists/vectors and some proper string manipulation :-P

How to delete all files in a folder, but not delete the folder using NIX standard libraries?

I am trying to create a program that deletes the contents of the /tmp folder, I am using C/C++ on linux.
system("exec rm -r /tmp")
deletes everything in the folder but it deletes the folder too which I dont want.
Is there any way to do this by some sort of bash script, called via system(); or is there a direct way i can do this in C/C++?
My question is similar to this one, but im not on OS X... how to delete all files in a folder, but not the folder itself?
#include <stdio.h>
#include <dirent.h>
int main()
{
// These are data types defined in the "dirent" header
DIR *theFolder = opendir("path/of/folder");
struct dirent *next_file;
char filepath[256];
while ( (next_file = readdir(theFolder)) != NULL )
{
// build the path for each file in the folder
sprintf(filepath, "%s/%s", "path/of/folder", next_file->d_name);
remove(filepath);
}
closedir(theFolder);
return 0;
}
You don't want to spawn a new shell via system() or something like that - that's a lot of overhead to do something very simple and it makes unnecessary assumptions (and dependencies) about what's available on the system.
In C/C++, you could do:
system("exec rm -r /tmp/*")
In Bash, you could do:
rm -r /tmp/*
This will delete everything inside /tmp, but not /tmp itself.
you can do
system("exec find /tmp -mindepth 1 -exec rm {} ';'");
by using use the wildcard * character you can delete all the files with any type of extension.
system("exec rm -r /tmp/*")
In C/C++ you can use (including hidden directories):
system("rm -r /tmp/* /tmp/.*");
system("find /tmp -mindepth 1 -delete");
But what if 'rm' or 'find' utilities are not availabe to sh?, better go 'ftw' and 'remove':
#define _XOPEN_SOURCE 500
#include <ftw.h>
static int remove_cb(const char *fpath, const struct stat *sb, int typeFlag, struct FTW *ftwbuf)
{
if (ftwbuf->level)
remove(fpath);
return 0;
}
int main(void)
{
nftw("./dir", remove_cb, 10, FTW_DEPTH);
return 0;
}
I realize this is very old question, but building on Demitri's great answer I created a function that will recursively delete files in subfolders if desired
It also does some error handling, in that it passes back errno. The function header is written for parsing by doxygen. This function works in the simple example cases I used, and deletes hidden folders and hidden files.
I hope this helps someone else in the future
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#define SUCCESS_STAT 0
/**
* checks if a specific directory exists
* #param dir_path the path to check
* #return if the path exists
*/
bool dirExists(std::string dir_path)
{
struct stat sb;
if (stat(dir_path.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode))
return true;
else
return false;
}
/**
* deletes all the files in a folder (but not the folder itself). optionally
* this can traverse subfolders and delete all contents when recursive is true
* #param dirpath the directory to delete the contents of (can be full or
* relative path)
* #param recursive true = delete all files/folders in all subfolders
* false = delete only files in toplevel dir
* #return SUCCESS_STAT on success
* errno on failure, values can be from unlink or rmdir
* #note this does NOT delete the named directory, only its contents
*/
int DeleteFilesInDirectory(std::string dirpath, bool recursive)
{
if (dirpath.empty())
return SUCCESS_STAT;
DIR *theFolder = opendir(dirpath.c_str());
struct dirent *next_file;
char filepath[1024];
int ret_val;
if (theFolder == NULL)
return errno;
while ( (next_file = readdir(theFolder)) != NULL )
{
// build the path for each file in the folder
sprintf(filepath, "%s/%s", dirpath.c_str(), next_file->d_name);
//we don't want to process the pointer to "this" or "parent" directory
if ((strcmp(next_file->d_name,"..") == 0) ||
(strcmp(next_file->d_name,"." ) == 0) )
{
continue;
}
//dirExists will check if the "filepath" is a directory
if (dirExists(filepath))
{
if (!recursive)
//if we aren't recursively deleting in subfolders, skip this dir
continue;
ret_val = DeleteFilesInDirectory(filepath, recursive);
if (ret_val != SUCCESS_STAT)
{
closedir(theFolder);
return ret_val;
}
}
ret_val = remove(filepath);
//ENOENT occurs when i folder is empty, or is a dangling link, in
//which case we will say it was a success because the file is gone
if (ret_val != SUCCESS_STAT && ret_val != ENOENT)
{
closedir(theFolder);
return ret_val;
}
}
closedir(theFolder);
return SUCCESS_STAT;
}
You could use nftw(3). First, make a pass to collect the set of file paths to remove. Then use unlink (for non-directories) and rmdir(2) in a second pass
From C++17 onwards you can use std::filesystem. The code below will use directory_iterator to list all the files and subdirectories in a directory and call remove_all to delete them:
#include <filesystem>
namespace fs = std::filesystem;
void delete_dir_content(const fs::path& dir_path) {
for (auto& path: fs::directory_iterator(dir_path)) {
fs::remove_all(path);
}
}
Note that this will throw a filesystem_error exception on underlying OS API errors. You can avoid this with:
void delete_dir_content(const fs::path& dir_path) {
for (auto& path: fs::directory_iterator(dir_path)) {
std::error_code err;
std::uintmax_t n = fs::remove_all(path, err);
if (static_cast<std::uintmax_t>(-1) == n) {
std::cout << "Failed to remove_all(" << path << ") with error: " << err.message() << std::endl;
}
}
}

how to search the computer for files and folders

i need a way to search the computer for files like Windows Explorer. i want my program to search lets say hard drive c:. i need it to search C:\ for folders and files (just the ones you could see in c:\ then if the user clicks on a file on the list like the folder test (C:\test) it would search test and let the user see what files/folders are in it.
Since you mentioned windows, the most straight forward winapi way to do it is with FindFirstFile and FindNextFile functions.
edit: Here's an example that shows you how to enumerate all files/folders in a directory.
#include <Windows.h>
#include <iostream>
int main()
{
WIN32_FIND_DATA file;
HANDLE search_handle=FindFirstFile(L"C:\\*",&file);
if (search_handle)
{
do
{
std::wcout << file.cFileName << std::endl;
}while(FindNextFile(search_handle,&file));
FindClose(search_handle);
}
}
This will be OS dependent. The SO question
How can I get a list of files in a directory using C or C++?
handles this problem well. You can download DIRENT here.
Now that you have this, I'd recommend recursively searching for a file with a DFS/BFS algorithm. You can assume the whole directory structure is a tree where each file is a leaf node and each subdirectory is an internal node.
So all you have to do is,
Get the list of files/folders in a directory with a function such as:
void getFilesFolders(vector<string> & dir_list, const string & folder_name)
If it's a directory, go to 1 with the directory name
If it's a file, terminate if it's the file you're looking for, else move on to the next file.
boost::filesystem can be a cross-platform solution for that (check out for such functions in it).
You can use Directory class members to do this with C# or managed C++. See the following MSDN article:
http://support.microsoft.com/kb/307009
If you wish to use C++ with MFC you can use CFileFind
http://msdn.microsoft.com/en-us/library/f33e1618%28v=VS.80%29.aspx
You'll have to supply your own browse window to present the file system tree.
Or you can use one of the directory/file controls to do both for you.
#include <Windows.h>
#include <iostream>
int FindF(char* pDirectory)
{
char szFindPath[MAX_PATH] = {0};
strcpy(szFindPath, pDirectory);
strcat(szFindPath, "\\*");
WIN32_FIND_DATA file;
HANDLE search_handle=FindFirstFile(szFindPath,&file);
if (search_handle)
{
do
{
if(file.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY)
{
strcpy(szFindPath, pDirectory);
strcat(szFindPath, "\\");
strcat(szFindPath, file.cFileName);
FindF(szFindPath);
}
std::wcout << file.cFileName << std::endl;
}while(FindNextFile(search_handle,&file));
CloseHandle(search_handle);
}
}
There really is no need to use 3rd party library to accomplish this. This is a short, independent function which lists all files (with their paths) in a directory, including subdiretories' files. std::string folderName has to finish with \, and if you want to list all files on computer, just create a loop in calling function along with GetLogicalDriveStrings (It returns strings with \, so it couldn't be more convenient in this case).
void FindAllFiles(std::string folderName)
{
WIN32_FIND_DATA FileData;
std::string folderNameWithSt = folderName + "*";
HANDLE FirstFile = FindFirstFile(folderNameWithSt.c_str(), &FileData);
if (FirstFile != INVALID_HANDLE_VALUE) {
do {
if (strcmp(FileData.cFileName, ".") != 0 && strcmp(FileData.cFileName, "..") != 0)
{
if(FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
std::string NewPath = folderName + FileData.cFileName;
NewPath = NewPath + "\\";
FindAllFiles(NewPath);
}
else
{
std::cout /*<< folderName*/ << FileData.cFileName << std::endl;
}
}
} while(FindNextFile(FirstFile, &FileData));
}
}
This is ASCII version, remember that files and folders can be named in Unicode