std::vector content change when read inside the main()

126 Views Asked by At

I was writing this function to search a file inside the computer but i encountered a problem: When I read the files that have been found during the search(using the for cycle inside the main() ) the directory are broken. With some debugging I saw that when pushed inside the file_found vector,they are intact,but when i read the vector in the main they're like overlapped and with a "*" at the end.How can i fix this?

    #include <stdio.h>
    #include <vector>
    #include <Windows.h>

    int SearchForFileW(WCHAR * fileName,LPWSTR dir,std::vector<LPWSTR>& file_found)
    {
        WIN32_FIND_DATAW winFindDataFirst;

        HANDLE hFile = FindFirstFileW(dir,&winFindDataFirst);

        if (!wcscmp(winFindDataFirst.cFileName,fileName))
        {
            wchar_t tmp[MAX_PATH] = { 0 };
            _snwprintf(tmp, wcslen(dir) - wcslen(L"*"), dir);
            wcscpy(dir, tmp);
            wcscat(dir, winFindDataFirst.cFileName);
            file_found.push_back(dir);
        }

        while (true)
        {
            if (FindNextFileW(hFile, &winFindDataFirst) == 0)
            {
                if (GetLastError() == ERROR_NO_MORE_FILES)
                {
                    return 0;
                }
                else
                { 
                    return -1;
                }
            }

            if (!wcscmp(winFindDataFirst.cFileName, L".") ||
                !wcscmp(winFindDataFirst.cFileName, L".."))
            {
                continue;
            }
            else if(!wcscmp(winFindDataFirst.cFileName,fileName))
            {
                wchar_t tmp[MAX_PATH] = { 0 };
                _snwprintf(tmp, wcslen(dir) - wcslen(L"*"), dir);
                wcscpy(dir, tmp);
                wcscat(dir, winFindDataFirst.cFileName);
                file_found.push_back(dir);
            }

            if ((winFindDataFirst.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
            {   
                wchar_t tmp[MAX_PATH] = { 0 };
                _snwprintf(tmp, wcslen(dir) - wcslen(L"*"), dir);
                wcscpy(dir, tmp);
                wcscat(dir, winFindDataFirst.cFileName);
                wcscat(dir, L"\\*");
                SearchForFileW(fileName, dir,file_found);
                _snwprintf(tmp, wcslen(dir) - (wcslen(winFindDataFirst.cFileName) + wcslen(L"\\*")), dir);
                wcscpy(dir, tmp);
                wcscat(dir, L"*");
            }
            else
            {
                printf("File:-------%S\n\n", winFindDataFirst.cFileName);
            }
        }

        return 0;
    }

int main()
{
    std::vector<LPWSTR> file;
    WCHAR dirBuff[MAX_PATH] = {0};

    wcscpy(dirBuff,L"c:\\*");
    SearchForFileW(L"MyFile.txt", dirBuff,file);
    if (file.size() == 0)
    {
        printf("No file found");
    }
    else
    {
        for (int i = 0; i < file.size(); i++)
        {
            printf("File found at: %S\n", file.at(i));
        }
    }
}
2

There are 2 best solutions below

1
On BEST ANSWER

A std::vector<LPWSTR> is a std::vector<wchar_t*> (since LPWSTR is a typedef for wchar_t*).

Now, having a vector of raw owning pointers is very fragile. You can have a vector of raw observing pointers, and you must be sure that the strings pointed to are still allocated (kind of "live") when you refer them using those pointers. And that is not your case.

The simplest thing to do is to just use C++ string classes like std::wstring instead of the raw wchar_t* pointers.
So, you can substitute your vector<LPWSTR> with a vector<wstring>. In this case, the lifetime of the strings will be automatically managed by the C++ compiler and the STL implementation: you can focus on the core of your algorithm, not on bug-prone string memory management implementation details.

2
On

LPWSTR is just sugar coating for someKindOfChar* Which means it is a pointer. Which means that vector<LPWSTR> is a vector of pointers. And every time, you use the same buffer to save your file name in (dir). So you every time copy your filename in this, and push its address to your vector.

To fix, either use a std::vector<std::wstring>.

Or do it the hard way: use malloc(strlen(tmp)+1) for every found file to allocate data for your string. Note however, that LPWSTR stands for, i believe long pointer wide string. This means that normal strlenmight not work, since it could contain special non-ascii characters