UpFileCopyExW 在现有文件上报告 ERROR_FILE_NOT_FOUND 为 0

UpFileCopyExW reports 0 with ERROR_FILE_NOT_FOUND on an existing file

上下文:

我有一个应用程序可以使用 QDirIterator、过滤器和复制特定文件来搜索目录中的文件。

问题:

使用有效的 QDirIterator::next(), I ensure the file exists (as a unnecessary safe measure) using QFile::exists(QString) 结果。

GetLastError() reports ERROR_FILE_NOT_FOUND 错误:

ERROR_FILE_NOT_FOUND

2 (0x2)

The system cannot find the file specified.

核心代码:(详见底部)

     // QString src (src file location), dst (destination file location)

     QFileInfo fi(m_src);
     QString dir = fi.dir().path();
     const wchar_t* dirC = toLPCWSTR(dir);
     QString src = QString(m_src).replace("/", "\");
     QString dst = QString(m_src).replace("/", "\");
     const wchar_t* localC_src = toLPCWSTR(src);
     const wchar_t* localC_dst = toLPCWSTR(dst);

     auto rc = CopyFileExW(localC_src, localC_dst, &BackupManager::copyProgress, this, &bStopBackup, 0);
     if (rc == 0) {

          DWORD lastError = GetLastError(); // Error = 0x32
          bool dirExist = DirExists(dirC); // true
          bool fileExists = FileExists(localC_src); // true

          printWarning(TAG, QString("File Copy Error: %1").arg(getLastErrorMsg()));
#ifdef QT_DEBUG
          if (FileExists(localC_src)) {
               qDebug() << "#FailedCopy: Windows file exists but copy failed" << src;  // this gets hit using the implemented c-style cast 
          }
          else {
               if (QFile::exists(src)) {
                    // =================================================
                    // < ------------------------------------- This is gets triggered
                    // =================================================

                    qDebug() << "#FailedCopy: Windows is really being full of shit! " << src;   // this always gets triggered when using QString::toStdWString.c_str()
               }
               else {
                    qDebug() << "#FailedCopy: Windows file copy failed outright" << src; 
               }
          }
          // ...
    } else {
          // success
    }

问题:

对我来说没有意义的是为什么QFile::exists(String)报告FileCopyExW找到的文件说系统找不到指定的文件。我错过了什么?


调试器图片:

完整代码实现:

static QString toString(HRESULT hr)
{
     _com_error err{hr};
     const TCHAR* lastError = err.ErrorMessage();
     return QStringLiteral("Error 0x%1: %2").arg((quint32)hr, 8, 16, QLatin1Char('0'))
            .arg(lastError);
}

static QString getLastErrorMsg()
{
     DWORD lastError = GetLastError();
     QString s = toString(HRESULT_FROM_WIN32(lastError));
     return s;
}

BOOL FileExists(LPCWSTR szPath)
{
     DWORD dwAttrib = GetFileAttributes(szPath);

     return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
             !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
}

// not used
static const wchar_t* toLPCWSTR(QString s)
{
     std::wstring dstWString = s.toStdWString();
     const wchar_t* localC_src = dstWString.c_str();
     return localC_src;
}

static bool DirExists(LPCWSTR szPath)
{
     DWORD ftyp = GetFileAttributes(szPath);
     if (ftyp == INVALID_FILE_ATTRIBUTES)
          return false;  //something is wrong with your path!

     if (ftyp & FILE_ATTRIBUTE_DIRECTORY)
          return true;   // this is a directory!

     return false;    // this is not a directory!
}

BackupResult BackupManager::copyFile(QString m_src, QString m_dst)
{
     QFileInfo fi(m_src);
     QString dir = fi.dir().path();
     const wchar_t* dirC = toLPCWSTR(dir);
     QString src = QString(m_src).replace("/", "\");
     QString dst = QString(m_src).replace("/", "\");
     const wchar_t* localC_src = toLPCWSTR(src);
     const wchar_t* localC_dst = toLPCWSTR(dst);

// c-style casts
//     LPCWSTR localC_src = (LPCWSTR) src.utf16();
//     LPCWSTR localC_dst = (LPCWSTR) dst.utf16();
//     LPCWSTR dirC = (LPCWSTR) dir.utf16();

     auto rc = CopyFileExW(localC_src, localC_dst, &BackupManager::copyProgress, this, &bStopBackup, 0);
     if (rc == 0) {

          DWORD lastError = GetLastError(); // Error = 0x2 (2)
          bool dirExist = DirExists(dirC); // false
          bool fileExists = FileExists(localC_src); // false

          printWarning(TAG, QString("File Copy Error: %1").arg(getLastErrorMsg()));
#ifdef QT_DEBUG
          if (FileExists(localC_src)) {
               qDebug() << "#FailedCopy: Windows file exists but copy failed" << src; // this gets hit using the implemented c-style cast 
          }
          else {
               if (QFile::exists(src)) {
                    qDebug() << "#FailedCopy: Windows is really being full of shit! " << src;   // this always gets triggered when using QString::toStdWString.c_str()
               }
               else {
                    qDebug() << "#FailedCopy: Windows file copy failed outright" << src;
               }
          }
#endif
          // copy failed
          return BackupResult::IOError;
     }

     // copy success
     return BackupResult::Success;
}

更新:

正如@john 的评论中提到的,我在指向源文件的目标文件方面遇到了问题,这显然不能正常工作。

解决了这个问题后,这突出显示了另一个错误 ERROR_INVALID_NAME:

ERROR_INVALID_NAME

123 (0x7B)

The filename, directory name, or volume label syntax is incorrect.

我通过发布的解决方案解决了这个问题。

这个函数有问题:

// not used
static const wchar_t* toLPCWSTR(QString s)
{
     std::wstring dstWString = s.toStdWString();
     const wchar_t* localC_src = dstWString.c_str();
     return localC_src;
}

您正在返回一个已被解构的字符串的原始指针。

因此,这两行:

 const wchar_t* localC_src = toLPCWSTR(src);
 const wchar_t* localC_dst = toLPCWSTR(dst);

是未定义的行为,但最可能的结果是 localC_srclocalC_dst 指向释放的内存。

最好保留你用 around 转换的 std::wstring,同时仍然引用里面的指针

std::wstring strSrc = src.toStdWString();
std::wstring strDst = dst.toStdWString();

const wchar_t* localC_src = strSrc.c_str();
const wchar_t* localC_dst = strDst.c_str();