Как использовать вызов FindNextFile в Windows для просмотра содержимого каталога? - PullRequest
0 голосов
/ 12 июня 2019

У меня есть небольшой фрагмент кода, предназначенный для перечисления содержимого каталога с помощью Windows API.

КОД:

#include <iostream>
#include <Windows.h>

int wmain() {

    WIN32_FIND_DATA data;
    std::string dir = "c:\\* "; 
    HANDLE hFind = FindFirstFileA(dir.c_str(), &data);      // DIRECTORY

    if (hFind != INVALID_HANDLE_VALUE) {
        do {
            std::cout << data.cFileName << std::endl;
        } while (FindNextFileW(hFind, &data));
        FindClose(hFind);
    }
    return 0;
}

Ошибка:

Error C2664 'HANDLE FindFirstFileA(LPCSTR,LPWIN32_FIND_DATAA)': cannot convert argument 2 from 'WIN32_FIND_DATA *' to 'LPWIN32_FIND_DATAA'

Ошибки меняются в зависимости от моих попыток исправить. Я пробовал следующее:

  • Пытался изменить FindFirstFile на FindFirstFileW / FindNextFileA
  • Попытка поставить L перед строкой каталога L"C:\\*"

Я посмотрел на следующие связанные вопросы:

Но не удалось успешно отобразить содержимое. Самый близкий у меня есть этот код, который компилируется без ошибок:

#include <windows.h>
#include <iostream>

int main()
{
    WIN32_FIND_DATA data;
    HANDLE hFind = FindFirstFileW(L"C:\\*", &data);

    if (hFind != INVALID_HANDLE_VALUE) {
        do {
            std::cout << data.cFileName << std::endl;
        } while (FindNextFileW(hFind, &data));
        FindClose(hFind);
    }
}

Это компилируется, но когда я запускаю двоичный файл, он выводит это:

0000009A9DBAF32C 0000009A9DBAF32C 0000009A9DBAF32C 0000009A9DBAF32C 0000009A9DBAF32C 0000009A9DBAF32C 0000009A9DBAF32C 0000009A9DBAF32C 0000009A9DBAF32C 0000009A9DBAF32C 0000009A9DBAF32C 0000009A9DBAF32C 0000009A9DBAF32C 0000009A9DBAF32C 0000009A9DBAF32C

Пока мы занимаемся этим, в чем разница между FindNextFile, FindNextFileA и FindNextFileW? Я чувствую, что проблема как-то связана с этим?

Ответы [ 2 ]

4 голосов
/ 12 июня 2019

FindNextFile - это макрос, который разрешается в FindNextFileA (ANSI) или FindNextFileW (Unicode UTF16-LE) в зависимости от того, определено UNICODE_UNICODE).

Таким образом, вы меняете WIN32_FIND_DATA на WIN32_FIND_DATAA, поскольку FindFirstFileA требуется версия параметра в формате ANSI.

См. https://devblogs.microsoft.com/oldnewthing/20040212-00/?p=40643 для объяснения различий между определениями UNICODE и _UNICODE

3 голосов
/ 12 июня 2019

В своем первом фрагменте кода вы четко компилируете свой проект с определением UNICODE (что очевидно из вашей способности передать WIN32_FIND_DATA в FindNextFileW() без ошибок).Когда определено UNICODE, WIN32_FIND_DATA отображается на WIN32_FIND_DATAW.Но FindFirstFileA() хочет вместо WIN32_FIND_DATAA.Таким образом, самое простое решение этой ошибки - просто изменить WIN32_FIND_DATA на WIN32_FIND_DATAA, чтобы удовлетворить вызов к FindFirstFileA().Но тогда у вас будет новая ошибка, потому что вы будете передавать WIN32_FIND_DATAA в FindNextFileW(), который вместо этого хочет WIN32_FIND_DATAW.Поэтому вам нужно будет вызвать FindNextFileA() вместо этого, чтобы исправить эту ошибку:

#include <iostream>
#include <string>
#include <Windows.h>

int wmain() {

    WIN32_FIND_DATAA data;
    std::string dir = "c:\\* "; 
    HANDLE hFind = FindFirstFileA(dir.c_str(), &data);      // DIRECTORY

    if (hFind != INVALID_HANDLE_VALUE) {
        do {
            std::cout << data.cFileName << std::endl;
        } while (FindNextFileA(hFind, &data));
        FindClose(hFind);
    }
    return 0;
}

Во втором фрагменте кода std::cout не содержит перегруженных operator<< для wchar_t данных, но этоимеют перегрузку на void*.Поле WIN32_FIND_DATAW::cFileName представляет собой массив wchar_t[], который распадается в wchar_t* указатель на 1-й символ, и все указатели неявно преобразуются в void*.Вот почему вы видите печатные адреса памяти.Вместо этого вам нужно использовать std::wcout:

#include <iostream>
#include <string>
#include <windows.h>

int wmain()
{
    WIN32_FIND_DATAW data;
    std::wstring dir = L"c:\\*";
    HANDLE hFind = FindFirstFileW(dir.c_str(), &data);

    if (hFind != INVALID_HANDLE_VALUE) {
        do {
            std::wcout << data.cFileName << std::endl;
        } while (FindNextFileW(hFind, &data));
        FindClose(hFind);
    }
}

Большинство Win32 API, которые работают со строковыми данными, имеют разновидности A (ANSI) и W (Wide, Unicode) и предоставляют общие TCHARмакросы на основе для сопоставления с одним или другим условием UNICODE.В этом случае FindFirstFile() сопоставляется с FindFirstFileA() или FindFirstFileW(), FindNextFile() сопоставляется либо с FindNextFileA() или FindNextFileW(), WIN32_FIND_DATA сопоставляется с WIN32_FIND_DATAA или WIN32_FIND_DATAW и т. Д.

Таким образом, общее правило заключается в том, что суффикс, который вы явно указываете (или опускаете) при вызове функции API, должен также повторяться в любых связанных объявлениях переменных по мере необходимости.Если вы вызываете API-функцию A явно, явно используйте соответствующие типы переменных A.Если вы вызываете API-функцию W явно, явно используйте соответствующие типы переменных W.Если вы опустите A / W в вызове функции API, опустите его в объявлениях переменных (или замените на T для TCHAR, если необходимо).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...