2

Context:

I need to scan for, gather information and copy some media files from specific directories.

I have been having quite some trouble with some files not being detected, etc

Problem:

Warning to reader: As seen on the screenshot and noted in a comment, the title and premise of this question are possible moot, as the error was more likely to be dec 32 (== 0x20) == ERROR_SHARING_VIOLATION, which has an "easy" explantion in the answer to this question.

In the code below, I use a c-style cast to convert my QString into a LPCWSTR for the CopyFileExW which I found in this SO post. I have tried many different conversions, but non of them seems to work correctly - which for now is besides the point.

The problem this 'conversion' technique gives is the error ERROR_NOT_SUPPORTED

ERROR_NOT_SUPPORTED

50 (0x32)

The request is not supported.

Frankly, this makes absolutely no sense to me in this context. I am copying from NTFS -> NTFS (same hard drive for testing), with destination file length < 200 characters (see image, 192 to be exact).

The core code: (see bottom for full details)

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

     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 = 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)) {
                    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
    }

What does this error mean in the FileCopyExW context?

(also, if anyone has the source for windows.h implementation to allow me to trace the error further, please post it as a comment)

Image of debugger, etc enter image description here

Full Code Implemenation:

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);
     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 = 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)) {
                    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;
}
Martin Ba
  • 37,187
  • 33
  • 183
  • 337
CybeX
  • 2,060
  • 3
  • 48
  • 115
  • 3
    In your screenshot it looks like the error code is '32' = ERROR_SHARING_VIOLATION, not '0x32' = ERROR_NOT_SUPPORTED. – Luke Aug 12 '20 at 04:24

1 Answers1

2

I suggest you check whether the copied file handle is opened in another process.

I created a simple sample, the code is as follows:

#include <iostream>
#include <Windows.h>
using namespace std;

int main(int argc, const char* argv[])
{
    CopyFileEx(L"D:\\test\\test.txt", L"D:\\test\\test2.txt", NULL, NULL, 0, 0);
    int e = GetLastError();
    cout << "error code is :" << e << endl;
    return 0;
}

This sample of course successfully copied the file.But if I add the code to open the handle of this file, it will return error code 32.

#include <iostream>
#include <Windows.h>
using namespace std;

int main(int argc, const char* argv[])
{
    CreateFileW(L"D:\\test\\test.txt", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,NULL);
    CopyFileEx(L"D:\\test\\test.txt", L"D:\\test\\test2.txt", NULL, NULL, 0, 0);
    int e = GetLastError();
    cout << "error code is :" << e << endl;
    return 0;
}

Outout: enter image description here

So I think you did not close it properly after opening the handle in other locations. If you need to copy files while the handle is open, you can modify the dwShareMode parameter to FILE_SHARE_READ. In this way, the file copy operation can be performed when the handle is opened.

Here is the sample:

#include <iostream>
#include <Windows.h>
using namespace std;

int main(int argc, const char* argv[])
{
    CreateFileW(L"D:\\test\\test.txt", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,NULL);
    CopyFileEx(L"D:\\test\\test.txt", L"D:\\test\\test2.txt", NULL, NULL, 0, 0);
    int e = GetLastError();
    cout << "error code is :" << e << endl;
    return 0;
}

Output:

enter image description here

More reference:CreateFileW and CopyFileExA

Zeus
  • 3,703
  • 3
  • 7
  • 20
  • `FILE_SHARE_READ` may or may not produce a sharing violation. That solely depends on the desired access, the desired access of the already opened file handles as well as their share mode. – IInspectable Aug 12 '20 at 07:46
  • Hi,if this answer did help to you, please feel free to mark it to help people with the same issue, and let me know if you have any problem.Thanks. – Zeus Sep 04 '20 at 06:35