FindFirstFile Always Returning Invalid Handle - c++

My aim is to list the textfiles in a specific directory and let the user load one of the files.
I'm using Windows, Unicode is predefined in my compiler.
Question: FileHandle has always INVALID_HANDLE_VALUE. What's the cause of this and how can I correct it?
My last code looks like this:
ListAllTxtFiles(L"C:\\Users\\Tnc\Desktop\\Yazılım Çalışmaları\\Projects\\Oyun Projem\\data\\SaveFiles\\");
void ListAllTxtFiles(const wchar_t *Directory)
{
TCHAR Buffer[2048];
wsprintf(Buffer, L"s%*.txt", Directory);//there are security considerations about this function
WIN32_FIND_DATAW FindData;
HANDLE FileHandle = FindFirstFileW(Buffer, &FindData);
if (FileHandle == INVALID_HANDLE_VALUE)
{
printf("Could not find any files..\n");
}
else
{
do
{
printf("Found %s\\%s\n", Directory, FindData.cFileName);
} while (FindNextFile(FileHandle, &FindData));
CloseHandle(FileHandle);
}
}

wsprintf(Buffer, L"s%*.txt", Directory);
should be
wsprintf(Buffer, L"%s*.txt", Directory);
You just got your wsprintf format string wrong.

Related

Using built in Windows Methods to get Contents of Folder

My goal is to only use built in methods of C++/Windows (I don't think std::filesystem is supported on my version of C++) to get the filenames within a folder.
right now I have this:
HANDLE hFind;
WIN32_FIND_DATA data;
hFind = FindFirstFile("C:\\Folder\\*", &data);
if (hFind != INVALID_HANDLE_VALUE) {
do {
//Process File Name
std::wstring ws(data.cFileName);
} while (FindNextFile(hFind, &data));
FindClose(hFind);
}
Which seems to be returning blank names and not the names of the files in the folder.
Am I using this FindFirstFile function correctly? Is there a better way to do this?
Your code can't compile as shown. You are calling the ANSI version of FindFirstFile() (by virtue of you passing it a narrow ANSI string literal instead of a wide Unicode string literal), and std::wstring does not have a constructor that accepts a char[] as input.
Baring that mistake, you are also ignoring the data.dwFileAttributes field to distinguish between files and subfolders, and in the case of subfolders you are not checking the contents of data.cFileName to ignore the "." and ".." special folder names.
Try this:
WIN32_FIND_DATAW data;
HANDLE hFind = FindFirstFileW(L"C:\\Folder\\*", &data);
if (hFind != INVALID_HANDLE_VALUE)
{
do
{
if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
{
// Process File Name
std::wstring ws(data.cFileName);
...
}
else
{
if ((lstrcmpW(data.cFileName, L".") != 0) &&
(lstrcmpW(data.cFileName, L"..") != 0))
{
// Process Folder Name
std::wstring ws(data.cFileName);
...
}
}
}
while (FindNextFileW(hFind, &data));
FindClose(hFind);
}

windows.h How to use FindFirstFile() and FindNextFile() to list all files in a directory?

I'm writing an app in Qt and trying to use the windows functions FindFirstFile and FindNextFile in order to speed up counting large numbers of files in several directories. I've copied this code almost verbatum off the microsoft site in order to list files, but debugging it shows that it's only listing one file when I trigger the function;
QStringList Manager::returnDirectoryFileData(QString ChangedDirectory)
{
QStringList DirectoryFiles;
WIN32_FIND_DATA FindFileData;
LARGE_INTEGER filesize;
HANDLE hFind = INVALID_HANDLE_VALUE;
DWORD dwError = 0;
//string directorySearch = "E:\\My Documents\\Visual Studio 2010\\Projects\\SEP-Asignment-One\\Debug\\*";
// Find the first file in the directory.
LPCWSTR ConvertedDir = (const wchar_t*)ChangedDirectory.utf16();
PVOID OldValue = NULL;
if (Wow64DisableWow64FsRedirection(&OldValue))
{
hFind = FindFirstFile(ConvertedDir, &FindFileData);
if (hFind == INVALID_HANDLE_VALUE)
{
printf("Invalid file handle. Error is %u.\n", GetLastError());
}
do
{
QString Newname = "Want to do stuff here";
DirectoryFiles.append(Newname);
printf(" %s <DIR>\n", FindFileData.cFileName);
} while (FindNextFile(hFind, &FindFileData) != 0);
dwError = GetLastError();
if (dwError != ERROR_NO_MORE_FILES)
{
DisplayErrorBox(TEXT("FindFirstFile"));
}
FindClose(hFind);
}
Wow64RevertWow64FsRedirection(&OldValue);
return DirectoryFiles;
}
This is a 32 bit program running on 64 bit windows 10, so the Wow64DisableWow64fsredirection is supposed to be called before these functions are used. Anyone know what I'm doing wrong? Thanks!

CopyFile error code 2

I have to create console application, which finds all .txt files in directory and makes copies of them to .copytxt format in the same directory. Program returns me error code 2 from CopyFile function. I really dont know where is the problem. I tried to use this reference: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365522(v=vs.85).aspx
Here is my code:
#include "stdafx.h"
#include "windows.h"
#define SOURCE_PATH _T(R"(C:\Users\XXXXX\Documents\4.semester\PB173\Ukol1\text\)")
int _tmain(int argc, _TCHAR* argv[])
{
WIN32_FIND_DATA findData;
HANDLE findHandle;
BOOL fFinished = FALSE;
TCHAR oldPath[MAX_PATH];
TCHAR newPath[MAX_PATH];
DWORD attrs;
_tcscpy_s(oldPath, _T("\\?\)"));
_tcscpy_s(oldPath, SOURCE_PATH);
_tcscat_s(oldPath, _T("*.txt"));
_tprintf(_T("%s\n"), oldPath);
findHandle = FindFirstFile(oldPath, &findData);
if (findHandle != INVALID_HANDLE_VALUE)
{
_tprintf(_T("The first file found is %s\n"), findData.cFileName);
while (!fFinished)
{
_tcscpy_s(newPath, _T("\\?\)"));
_tcscpy_s(newPath, SOURCE_PATH);
TCHAR* pChar;
TCHAR* savePtr;
pChar = _tcstok_s(findData.cFileName, _T("."), &savePtr);
_tcscat_s(newPath, pChar);
_tcscat_s(newPath, _T(".copytxt"));
_tprintf(_T("%s\n"), newPath);
//StringCchPrintf(newPath, sizeof(newPath) / sizeof(newPath[0]), TEXT("%s\\%s"), oldPath, findData.cFileName);
if (CopyFile(findData.cFileName, newPath, FALSE))
{
attrs = GetFileAttributes(findData.cFileName);
if (attrs == INVALID_FILE_ATTRIBUTES) break;
SetFileAttributes(newPath, attrs);
_tprintf(_T("File %s copied successfully.\n"), findData.cFileName);
}
else
{
_tprintf(_T("Could not copy file %s.\n"), findData.cFileName);
_tprintf(_T("%d\n"), GetLastError());
break;
}
if (!FindNextFile(findHandle, &findData))
{
if (GetLastError() == ERROR_NO_MORE_FILES)
{
_tprintf(_T("All files *.txt were copied.\n"));
fFinished = TRUE;
}
else
{
_tprintf(_T("Could not find next file.\n"));
break;
}
}
}
FindClose(findHandle);
}
else
{
_tprintf(TEXT("FindFirstFile failed (%d)\n"), GetLastError());
}
return 0;
}
You need to strcat the cFileName to the end of the the source path before attempting the copyfile, else the file will not be found.
From MSDN:
The cFileName field in this structure will not include a path, even if
a path was used in the call to FindFirstFile/FindNextFile. So if you
call FindFirstFile("C:\Windows\System32*", &finddata), finddata may
contain e.g. "drivers" or "cmd.exe" but not
"C:\Windows\System32\drivers" or "C:\Windows\System32\cmd.exe".
You need to escape \ as \\ when you want to use an actual \ character in literals.
You are also putting parenthesis characters inside your literal values. You need to remove them.
Change
#define SOURCE_PATH _T(R"(C:\Users\XXXXX\Documents\4.semester\PB173\Ukol1\text\)")
To
#define SOURCE_PATH _T("C:\\Users\\XXXXX\\Documents\\4.semester\\PB173\\Ukol1\\text\\")
And
_T("\\?\)")
To
_T("\\\\?\\")

LPCTSTR to LPCSTR conversion

I am trying to get information of existing file using GetFileInformationByHandle(). My function that performs the required task receives LPCTSTR Filename as argument. Here is the code:
getfileinfo(LPCTSTR Filename)
{
OFSTRUCT oo;
BY_HANDLE_FILE_INFORMATION lpFileInformation;
HFILE hfile=OpenFile((LPCSTR)Filename,&oo,OF_READ);
int err=GetLastError();
GetFileInfomationByHandle((HANDLE)hfile,&lpFileInformation);
}
Above code works fine if I declare Filename as LPCSTR but as per requirement of my function I receive the filename in LPCTSTR so if I use typecasting then openfile() cannot find the specified file and returns -1.
Can anyone tell me how to get file information if filename is LPCTSTR? Or how to convert LPCTSTR to LPCSTR.
Why is this typecasting not working? I believe this should work.
Just casting the pointer doesn't change the actual data (ie filename) that is being pointed to into eight-bit characters.
Reading the docs at MSDN suggests using CreateFile instead, which handles LPCTSTR filenames.
The solution to your immediate problem is to replace OpenFile() with CreateFile(), just like the OpenFile() documentation says to do:
Note This function has limited capabilities and is not recommended. For new application development, use the CreateFile function.
For example:
getfileinfo(LPCTSTR Filename)
{
HANDLE hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
int err = GetLastError();
// handle error as needed ...
}
else
{
BY_HANDLE_FILE_INFORMATION FileInfo = {0};
BOOL ok = GetFileInformationByHandle(hFile, &FileInfo);
int err = GetLastError();
CloseHandle(hFile);
if (!ok)
{
// handle error as needed ...
}
else
{
// use FileInfo as needed...
}
}
}
That being said, a better solution is to not open the file at all. Most of the information that GetFileInformationByHandle() returns can be obtained using FindFirstFile() instead:
getfileinfo(LPCTSTR Filename)
{
WIN32_FIND_DATA FileData = {0};
HANDLE hFile = FindFirstFile(Filename, &FileData);
if (hFile == INVALID_HANDLE_VALUE)
{
int err = GetLastError();
// handle error as needed ...
}
else
{
FindClose(hFile);
// use FileData as needed ...
}
}
Have a look at Project Properties/Configuration Properties/General/Character Set. This is normally set to UNICODE. It can be changed to MBCS.
If it is set to MBCS, then the code does not need to be modified.
If it is set to Unicode, which I suspect it is otherwise you won't be asking this question, use widechartomultibyte to convert it from LPCTSTR (const wchar_t*) to LPSTR (const char*).

How to get list of folders in this folder?

How to get list of folders in this folder?
FindFirstFileEx+FindExSearchLimitToDirectories.
WIN32_FIND_DATA fi;
HANDLE h = FindFirstFileEx(
dir,
FindExInfoStandard,
&fi,
FindExSearchLimitToDirectories,
NULL,
0);
if (h != INVALID_HANDLE_VALUE) {
do {
if (fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
printf("%s\n", fi.cFileName);
} while (FindNextFile(h, &fi));
FindClose(h);
}
If you can't use .NET & Managed code, you can go through the win32 api's
Here is an example that you can modify to only get Folders.
(Basically the following check:)
...
TCHAR szDir = _T("c:\\"); // or wherever.
HANDLE hFind = FindFirstFile(szDir, &ffd);
...
do {
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
// your code on 'ffd'
}
} while (FindNextFile(hFind, &ffd) != 0);
You can use Boost
Or, if you don't want Boost you can check out this thread where alternative options are discussed.
http://www.gamedev.net/community/forums/topic.asp?topic_id=523375
For best portability, use the boost filesystem library. Use opendir()/readdir() and friends for UNIX based systems.