【问题标题】:The problem in WinAPI when working with files and directories处理文件和目录时 WinAPI 中的问题
【发布时间】:2019-11-17 19:29:20
【问题描述】:

我正在使用 WinAPI 编写 C++ 控制台程序。该程序适用于文件和目录。程序启动如下:

app -R -1 "掩码"

(例如,"D: \ Work \*")。

-R是递归目录遍历,-1 - 输出有关文件的信息(创建日期、大小、属性)。

完整程序代码:

LIBSPEC BOOL ConsolePrompt(LPCTSTR, LPTSTR, DWORD, BOOL);
LIBSPEC BOOL PrintStrings(HANDLE, ...);
LIBSPEC BOOL PrintMsg(HANDLE, LPCTSTR);
LIBSPEC VOID ReportError(LPCTSTR, DWORD, BOOL);
BOOL TraverseDirectory(LPCTSTR, DWORD, LPBOOL);
DWORD FileType(LPWIN32_FIND_DATA);
BOOL ProcessItem(LPWIN32_FIND_DATA, DWORD, LPBOOL);

DWORD Options(int argc, LPCTSTR argv[], LPCTSTR OptStr, ...) {
    va_list pFlagList;
    LPBOOL pFlag;
    int iFlag = 0, iArg;
    va_start(pFlagList, OptStr);
    while ((pFlag = va_arg(pFlagList, LPBOOL)) != NULL && iFlag < (int)_tcslen(OptStr)) {
        *pFlag = FALSE;
        for (iArg = 1; !(*pFlag) && iArg < argc && argv[iArg][0] == '-'; iArg++)
            *pFlag = memchr(argv[iArg], OptStr[iFlag], _tcslen(argv[iArg])) != NULL;
        iFlag++;
    }
    va_end(pFlagList);
    for (iArg = 1; iArg < argc && argv[iArg][0] == '-'; iArg++);
    return iArg;
}

void pr_err(int code) {
    setlocale(LC_ALL, "Russian");
    if (code == 3) {
        printf("Файл с указанным названием по указанному пути не найден.");
    }
    else if (code == 5) {
        printf("Операция отклонена. Возможны следующие причины: \n");
        printf("Копируемый файл защищен от копирования, скрыт или используется операционной системой.\n");
        printf("В целевой директории стоит запрет на запись файлов.\n");
    }
    else if (code == 20) {
        printf("Устройство не найдено.\n");
    }
    else if (code == 123) {
        printf("Указано некорректное название для файла или директории. Возможно были использованы запрещенные символы.\n");
    }
}

static void PrintAttributes(DWORD Attrs)
{
    setlocale(LC_ALL, "Russian");
    if (Attrs == INVALID_FILE_ATTRIBUTES)
    {
        printf(" Ошибка чтения атрибутов\n");
    }
    else
    {
        printf(" \nАтрибуты: ");
        if (Attrs & FILE_ATTRIBUTE_ARCHIVE)
        {
            printf("A ");
        }
        if (Attrs & FILE_ATTRIBUTE_COMPRESSED)
        {
            printf("C ");
        }
        if (Attrs & FILE_ATTRIBUTE_DIRECTORY)
        {
            printf("D ");
        }
        if (Attrs & FILE_ATTRIBUTE_HIDDEN)
        {
            printf("H ");
        }
        if (Attrs & FILE_ATTRIBUTE_READONLY)
        {
            printf("R ");
        }
        printf("\n");
    }
}

int _tmain(int argc, LPCTSTR argv[]) {
    setlocale(LC_ALL, "Russian");
    BOOL Flags[MAX_OPTIONS], ok = TRUE;
    TCHAR PathName[buffsize + 1], CurrPath[buffsize + 1];
    LPCTSTR pFileName;
    int i, FileIndex;

    FileIndex = Options(argc, argv, _T("R1"), &Flags[0], &Flags[1], &Flags[2], NULL);

    GetCurrentDirectory(buffsize, CurrPath);
    printf("argc = %d Index = %d\n", argc, FileIndex);
    if (argc < FileIndex + 1) {
        printf("Поиск в текущей директории:\n (%s)\n", CurrPath);
        ok = TraverseDirectory(_T("*"), MAX_OPTIONS, Flags);
    }
    else {
        for (i = FileIndex; i < argc; i++) {
            pFileName = argv[i];
            /* Нужно из pFileName вытащить сабстринг по разделителю *  
            FileAddress = ... // тут получение адреса
            SetCurrentDirectory(FileAddress);
            */
            printf("DIR:  %s\n", pFileName);
            if (!SetCurrentDirectory(pFileName)) {
                printf("Ошибка установки директории %s как текущей...", pFileName);
                return 1;
            }
            else {
                ok = TraverseDirectory(pFileName, MAX_OPTIONS, Flags) && ok;
                SetCurrentDirectory(CurrPath);
            }
        }
    }
    return ok ? 0 : 1;
}

static BOOL TraverseDirectory(LPCTSTR PathName, DWORD NumFlags, LPBOOL Flags) { 
    HANDLE SearchHandle;
    WIN32_FIND_DATA FindData;
    BOOL Recursive = Flags[0];
    DWORD FType, iPass;
    TCHAR CurrPath[buffsize + 1];
    GetCurrentDirectory(buffsize, CurrPath);
    for (iPass = 1; iPass <= 2; iPass++) {
        SearchHandle = FindFirstFile(PathName, &FindData);
        if (SearchHandle == INVALID_HANDLE_VALUE) {
            pr_err(GetLastError());
            return 1;
        }
        do {
            FType = FileType(&FindData);
            if (iPass == 1)
                ProcessItem(&FindData, MAX_OPTIONS, Flags);

            if (FType == TYPE_DIR && iPass == 2 && Recursive) {
                _tprintf(_T("%s\\%s:\n"), CurrPath, FindData.cFileName);
                if (!SetCurrentDirectory(FindData.cFileName))
                {
                    printf("Ошибка установки %s как текущей директории...", FindData.cFileName);
                }
                else {
                    TraverseDirectory(_T("*"), NumFlags, Flags);
                    SetCurrentDirectory(_T(".."));  
                }
            }
        } while (FindNextFile(SearchHandle, &FindData));
        FindClose(SearchHandle);
    }
    return TRUE;
}

static BOOL ProcessItem(LPWIN32_FIND_DATA pFileData, DWORD NumFlags, LPBOOL Flags)
{
    const TCHAR FileTypeChar[] = { 'c', 'd' };
    DWORD FType = FileType(pFileData);

    BOOL Long = Flags[1];
    SYSTEMTIME LastWrite;

    if (FType != TYPE_FILE && FType != TYPE_DIR)
        return FALSE;
    _tprintf(_T("\n"));
    if (Long) {
        _tprintf(_T("%c"), FileTypeChar[FType - 1]); 
        _tprintf(_T("%10d"), pFileData->nFileSizeLow);
        FileTimeToSystemTime(&(pFileData->ftLastWriteTime), &LastWrite);
        _tprintf(_T(" %02d/%02d/%04d %02d:%02d:%02d "), LastWrite.wMonth, LastWrite.wDay,
            LastWrite.wYear, LastWrite.wHour, LastWrite.wMinute, LastWrite.wSecond);
    }
    _tprintf(_T("%s"), pFileData->cFileName);
    PrintAttributes(GetFileAttributesA(pFileData->cFileName));
    return TRUE;
}
static DWORD FileType(LPWIN32_FIND_DATA pFileData) {
    BOOL IsDir;
    DWORD FType;
    FType = TYPE_FILE;
    IsDir = (pFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
    if (IsDir)
        if (lstrcmp(pFileData->cFileName, _T(".")) == 0 ||
            lstrcmp(pFileData->cFileName, _T("..")) == 0)
            FType = TYPE_DOT;
        else
            FType = TYPE_DIR;
    return FType;
}

问题是切换到指定路径不起作用。我该如何解决这个问题?

【问题讨论】:

  • 我们不知道代码的作用。它使用通用文本映射,由我们看不到的外部环境控制。无论如何,我们需要minimal reproducible example

标签: c++ winapi


【解决方案1】:

SetCurrentDirectory 不接受通配符。 您应该指定一个有效的路径,例如"D:\\work\\"。 然后,您应该调用GetFileAttributes 来决定是否在文件名后添加通配符。

TCHAR file[MAX_PATH] = {0};
_stprintf(file, _T("%s\\*"), pFileName);
ok = TraverseDirectory(file, MAX_PATH, Flags) && ok;

【讨论】:

    猜你喜欢
    • 2020-03-19
    • 1970-01-01
    • 2010-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-11
    • 2020-05-24
    • 2020-06-26
    相关资源
    最近更新 更多