【发布时间】:2020-12-01 16:48:55
【问题描述】:
上下文:
我有一个应用程序,它使用QDirIterator 搜索目录中的文件,过滤和复制特定文件。
问题:
使用来自QDirIterator::next() 的结果,我使用有效的QFile::exists(QString) 确保文件存在(作为不必要的安全措施)。
但是,当尝试使用CopyFileExW 复制文件时,returns 0 表示文件复制失败。我完全不知道为什么。
文件位置:
C:/Users/CybeX/Documents/BLMS/Repo/BLMS-Work-Dev/Meeting 2 - Requirements Document Discussion & Dev/2020-05-19 11.22.30 Someone Person's Zoom Meeting 98661954658/zoom_0.mp4
健全性测试
我添加了一些健全性测试以通过从QString 的转换检查文件内容 -> LPCWSTR 因为FileCopyExW 需要LPCWSTR,建议转换QString -> LPCWSTR here。
关于转换,我也尝试过this,但结果相同。这也被建议为用户 c 样式转换的不良做法
健全性测试(在下面的应用程序代码中)全部通过,但 FileCopyExW 总是失败:
“错误0x80070002:系统找不到指定的文件。”
应用程序内的代码:
QString m_src = QString("C:/Users/CybeX/Documents/BLMS/Repo/BLMS-Work-Dev/Meeting 2 - Requirements Document Discussion & Dev/2020-05-19 11.22.30 Someone Person's Zoom Meeting 98661954658/zoom_0.mp4");
QString m_dst = QString("C:/Users/CybeX/Documents/BLMS/Repo/BLMS-Work-Dev/Meeting 2 - Requirements Document Discussion & Dev/2020-05-19 11.22.30 Someone Person's Zoom Meeting 98661954658/zoom_0.mp42");
// Hard coded test location attempting to match variables' content below
// QString srcLocation = QString("C:/Users/CybeX/Documents/BLMS/Repo/BLMS-Work-Dev/Meeting 2 - Requirements Document Discussion & Dev/2020-05-19 10.41.17 Someone Person's Zoom Meeting 96047275811/zoom_0.mp4");
// QString dstLocation = QString("C:/Users/CybeX/Documents/BLMS/Repo/BLMS-Work-Dev/Meeting 2 - Requirements Document Discussion & Dev/2020-05-19 10.41.17 Someone Person's Zoom Meeting 96047275811/zoom_0.mp44");
// std::wstring srcWString1 = srcLocation.toStdWString();
// std::wstring dstWString1 = dstLocation.toStdWString();
// const wchar_t* localC_src1 = srcLocation.toStdWString().c_str();
// const wchar_t* localC_dst1 = dstLocation.toStdWString().c_str();
//
// std::wstring srcWString = m_src.toStdWString();
// std::wstring dstWString = m_dst.toStdWString();
// Used inside copy function
const wchar_t* localC_src = m_src.toStdWString().c_str();
const wchar_t* localC_dst = m_dst.toStdWString().c_str();
// Sanity tests
if (m_src.contains("96047275811/zoom_0.mp4")) {
if (srcLocation != m_src) {
qDebug() << "Warning"; // Never gets hit
}
if (srcWString != srcWString1) {
qDebug() << "Warning"; // Never gets hit
}
if (*localC_src != *localC_src1) {
qDebug() << "Warning"; // Never gets hit
}
if (!QFile::exists(srcLocation)) {
qDebug() << "Warning"; // Never gets hit
}
}
auto rc = CopyFileExW(localC_src, localC_dst, &FileManager::copyProgress, this, &bStopBackup, 0);
if (rc == 0) {
printWarning(TAG, QString("File Copy Error: %1").arg(getLastErrorMsg()));
// copy failed
return FileResult::IOError; // This file always hits
}
// copy success
return FileResult::Success;
但是,在自定义测试应用程序中硬编码文件位置确实可以正常工作。
测试应用:
结果成功
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()
{
QString s = toString(HRESULT_FROM_WIN32(GetLastError()));
return s;
}
int main(int argc, char* argv[])
{
QCoreApplication a(argc, argv);
QString m_src = QString("C:/Users/CybeX/Documents/BLMS/Repo/BLMS-Work-Dev/Meeting 2 - Requirements Document Discussion & Dev/2020-05-19 11.22.30 Someone Person's Zoom Meeting 98661954658/zoom_0.mp4");
QString m_dst = QString("C:/Users/CybeX/Documents/BLMS/Repo/BLMS-Work-Dev/Meeting 2 - Requirements Document Discussion & Dev/2020-05-19 11.22.30 Someone Person's Zoom Meeting 98661954658/zoom_0.mp42");
auto rc = CopyFileExW(m_src.toStdWString().c_str(), m_dst.toStdWString().c_str(),
NULL, NULL, NULL, 0);
if (rc == 0) {
QString s = getLastErrorMsg();
// copy failed
qDebug() << "Failed";
}
else {
qDebug() << "Copied"; // Always gets hit
}
// copy success
return a.exec();
}
【问题讨论】:
-
将本机调试器(例如 windbg 或 cdb)附加到进程,并在
CopyFileExW上设置断点。当断点命中时,检查传递的参数,尤其是源路径和目标路径。在 x64 中,它们在寄存器 rcx 和 rdx 中传递——例如du @rcx打印源路径。 -
@ErykSun 感谢您的评论,请参阅我的回答。它根本与转换无关......令人惊讶。
标签: c++ windows qt winapi file-copying