Reputation: 39
I'm new in c++. I'm trying to list files in dir. I'm using unicode. The problem is not listing files but treat string and paths with wchar*, I'm going mad. Here's my test code:
#define UNICODE 1
#include <stdio.h>
#include <windows.h>
#include <wchar.h>
int wmain(int argc,wchar_t **argv){
if (argc > 1){
wchar_t* path=argv[1];
wchar_t* pwc;
int last_occurence;
pwc=wcsrchr(path,L'\\');
last_occurence = pwc-path+1;
int len = wcslen(path);
if (last_occurence == len){
//slash
}else{
//no slash
wcscat(path,L"\\");
}
wcscat(path,L"*");
WIN32_FIND_DATA FindData;
HANDLE hSearch;
hSearch = FindFirstFile(path , &FindData);
if(hSearch == INVALID_HANDLE_VALUE){
return -1;
}else{
// *** PROBLEM STARTS HERE
wchar_t* filePath=NULL;
do{
wcscpy(filePath,path);
wcscat(filePath,FindData.cFileName);
wprintf(L"Path %s\n",filePath);
memset(filePath, '\0', wcslen(filePath));
// *** PROBLEM ENDS HERE
}while( FindNextFile(hSearch, &FindData) > 0 );
int ret = FindClose(hSearch);
return 0;
}
}
}
When I run the compiled app, it stops responding. What I would like to do is print the path I pass to my app (c:\dir1\dir2) and append the files in it (file1,file2) as follows:
c:\dir1\dir2\file1
c:\dir1\dir2\file2
How to solve this problem? There are best methods to do something like this? I would remain with wchar not std string if possible
Upvotes: 0
Views: 338
Reputation: 597051
There are a few issues with your code.
you are concatenating "\\*"
to the memory that argv[1]
points to, which is bad. You need to change path
from a wchar_t*
pointer to an wchar_t[]
array, and then wcscpy
the argv[1]
data into it.
you are not allocating any memory for filePath
, so wcscpy()
and wcscat()
are writing to invalid memory. You need to change filePath
to a wchar_t[]
array as well, and then wcscpy
/wcscat
the path data into it.
you are also not ignoring the concatenated *
when combining the path
and cFileNames
values together.
you don't need the memset()
at all (especially since you are giving it the wrong byte count anyway).
Try something more like this instead:
#define UNICODE 1
#include <stdio.h>
#include <windows.h>
#include <wchar.h>
int wmain(int argc, wchar_t **argv)
{
if (argc < 2)
{
wprintf(L"Usage: \"%s\" path\n", argv[0]);
return -1;
}
int len = wcslen(argv[1]);
if (len >= MAX_PATH)
{
wprintf(L"Path is too long\n");
return -1;
}
wchar_t path[MAX_PATH+1] = {};
wcscpy(path, argv[1]);
if ((len > 0) && (path[len-1] != L'\\'))
wcscat(path, L"\\");
wchar_t searchMask[MAX_PATH+2] = {};
wcscpy(searchMask, path);
wcscat(searchMask, L"*");
WIN32_FIND_DATA FindData;
HANDLE hSearch = FindFirstFileW(searchMask, &FindData);
if (hSearch == INVALID_HANDLE_VALUE)
{
if (GetLastError() != ERROR_FILE_NOT_FOUND)
{
wprintf(L"Error looking for first file\n");
return -1;
}
wprintf(L"No files found\n");
}
else
{
wchar_t filePath[MAX_PATH*2];
do
{
wcscpy(filePath, path);
wcscat(filePath, FindData.cFileName);
wprintf(L"Path %s\n", filePath);
}
while (FindNextFileW(hSearch, &FindData));
if (GetLastError() != ERROR_NO_MORE_FILES)
{
FindClose(hSearch);
wprintf(L"Error looking for next file\n");
return -1;
}
FindClose(hSearch);
}
return 0;
}
Though, you really should be using the std::unique_ptr
and std::wstring
classes and let them manage memory/resources for you. Using C library functions is not helping you learn C++:
#define UNICODE 1
#include <windows.h>
#include <wchar.h>
#include <iostream>
#include <string>
#include <memory>
struct FindDeleter
{
typedef HANDLE pointer;
void operator()(HANDLE h)
{
if(h != INVALID_HANDLE_VALUE)
FindClose(h);
}
};
int wmain(int argc, wchar_t **argv)
{
if (argc < 2)
{
std::wcerr << L"Usage: \"" << argv[0] << L"\" path" << std::endl;
return -1;
}
std::wstring path = argv[1];
if ((!path.empty()) && (path[path.length()-1] != L'\\'))
path += L'\\';
WIN32_FIND_DATA FindData;
std::unique_ptr<HANDLE, FindDeleter> hSearch(FindFirstFileW((path + L"*").c_str(), &FindData));
if (hSearch.get() == INVALID_HANDLE_VALUE)
{
if (GetLastError() != ERROR_FILE_NOT_FOUND)
{
std::wcerr << L"Error looking for first file" << std::endl;
return -1;
}
std::wcout << L"No files found" << std::endl;
}
else
{
do
{
std::wstring filePath = path + FindData.cFileName;
std::wcout << L"Path " << filePath << std::endl;
}
while (FindNextFileW(hSearch.get(), &FindData));
if (GetLastError() != ERROR_NO_MORE_FILES)
{
std::wcerr << L"Error looking for next file" << std::endl;
return -1;
}
}
return 0;
}
Or, if you are not using a C++11 compiler:
#define UNICODE 1
#include <windows.h>
#include <wchar.h>
#include <iostream>
#include <string>
class FindHandle
{
private:
HANDLE m_hFind;
public:
FindHandle(HANDLE hFind) : m_hFind(hFind) {}
~FindHandle()
{
if (m_hFind != INVALID_HANDLE_VALUE)
FindClose(m_hFind);
}
HANDLE get() { return m_hFind; }
};
int wmain(int argc, wchar_t **argv)
{
if (argc < 2)
{
std::wcerr << L"Usage: \"" << argv[0] << L"\" path" << std::endl;
return -1;
}
std::wstring path = argv[1];
if ((!path.empty()) && (path[path.length()-1] != L'\\'))
path += L'\\';
WIN32_FIND_DATA FindData;
FindHandle hSearch(FindFirstFileW((path + L"*").c_str(), &FindData));
if (hSearch.get() == INVALID_HANDLE_VALUE)
{
if (GetLastError() != ERROR_FILE_NOT_FOUND)
{
std::wcerr << L"Error looking for first file" << std::endl;
return -1;
}
std::wcout << L"No files found" << std::endl;
}
else
{
do
{
std::wstring filePath = path + FindData.cFileName;
std::wcout << L"Path " << filePath << std::endl;
}
while (FindNextFileW(hSearch.get(), &FindData));
if (GetLastError() != ERROR_NO_MORE_FILES)
{
std::wcerr << L"Error looking for next file" << std::endl;
return -1;
}
}
return 0;
}
Upvotes: 1