2

This is part of an application aimed at handling files & backups. My aim is to implement this function to allow the system to copy files faster.

I came across this very useful answer on SO suggesting how to implement the CopyFileExW / CopyFile2 in Qt.

The problem

using the code as posted runs perfectly, however attempting to modify it to fit into my application causes the following problem:

path\to\project\...\libs\backupmanager.cpp:2806: error: cannot convert 'DWORD (BackupManager::*)(LARGE_INTEGER, LARGE_INTEGER, LARGE_INTEGER, LARGE_INTEGER, DWORD, DWORD, HANDLE, HANDLE, LPVOID) {aka long unsigned int (BackupManager::*)(_LARGE_INTEGER, _LARGE_INTEGER, _LARGE_INTEGER, _LARGE_INTEGER, long unsigned int, long unsigned int, void*, void*, void*)}' to 'LPPROGRESS_ROUTINE {aka long unsigned int (__attribute__((__stdcall__)) *)(_LARGE_INTEGER, _LARGE_INTEGER, _LARGE_INTEGER, _LARGE_INTEGER, long unsigned int, long unsigned int, void*, void*, void*)}' for argument '3' to 'WINBOOL CopyFileExW(LPCWSTR, LPCWSTR, LPPROGRESS_ROUTINE, LPVOID, LPBOOL, DWORD)'
                            &BackupManager::copyProgress, this, &bStopBackup, 0);
                                                                           ^

I did not see any mention of a requirement for the LPPROGRESS_ROUTINE callback to be static, but I changed it to static (and commented out those offending lines), yet this problem persists (which I almost expected).

It appears the signatures match according, where DWORD === unsigned int, LPVOID & HANDLE === *void and where LPPROGRESS_ROUTINE suggests its definition can return a DWORD.

LPPROGRESS_ROUTINE LpprogressRoutine;

DWORD LpprogressRoutine( LARGE_INTEGER TotalFileSize,
LARGE_INTEGER TotalBytesTransferred, LARGE_INTEGER StreamSize,
LARGE_INTEGER StreamBytesTransferred, DWORD dwStreamNumber, DWORD dwCallbackReason, HANDLE hSourceFile, HANDLE hDestinationFile,
LPVOID lpData ) {...}

How can I resolve this as I have absolutely no idea?


Summary of change(s):

  • changed to non-static method
DWORD CALLBACK copyProgress(
      LARGE_INTEGER totalSize, LARGE_INTEGER totalTransferred,
      LARGE_INTEGER streamSize, LARGE_INTEGER streamTransferred,
      DWORD streamNo, DWORD callbackReason, HANDLE src, HANDLE dst,
      LPVOID data);
  • header change of copy method
void copyFile(QString m_src, QString m_dst);

Full (minimal) Code below:

class BackupManager : public QObject {
     Q_OBJECT

 private:
 QWaitCondition pauseThreadCondition;
 QMutex backupPauseLock;
 bool bPauseBackup = false, bStopBackup = false;

 static DWORD CALLBACK copyProgress(
      LARGE_INTEGER totalSize, LARGE_INTEGER totalTransferred,
      LARGE_INTEGER streamSize, LARGE_INTEGER streamTransferred,
      DWORD streamNo, DWORD callbackReason, HANDLE src, HANDLE dst,
      LPVOID data);

     void copyFile(QString m_src, QString m_dst);

  //...

  signals:
     void fileCopyFinished();
     void fileCopyFailed(QString error);
     void fileCopyProgress(qint64 progress, qint64 total);
  //...
}

and source

void BackupManager::copyFile(QString m_src, QString m_dst)
{
     auto rc = CopyFileExW((LPCWSTR)m_src.utf16(), (LPCWSTR)m_dst.utf16(),
                           &BackupManager::copyProgress, this, &bStopBackup, 0);
     if (!rc)
          emit fileCopyFailed(getLastErrorMsg());
     emit fileCopyFinished();
}
DWORD CALLBACK BackupManager::copyProgress(
     const LARGE_INTEGER totalSize, const LARGE_INTEGER totalTransferred,
     LARGE_INTEGER, LARGE_INTEGER, DWORD,
     DWORD, HANDLE, HANDLE,
     LPVOID data)
{
     emit fileCopyProgress(totalTransferred.QuadPart, totalSize.QuadPart);
     if (bPauseBackup) {
          backupPauseLock.lock();
          pauseThreadCondition.wait(&backupPauseLock);
          backupPauseLock.unlock();
     }
     return PROGRESS_CONTINUE;
}

Image (if it helps at all)

enter image description here


UPDATE

As per @RbMm's request, see below for 'static' impl and corresponding error.

Qt Compile Error:

path\to\project\...\libs\backupmanager.cpp:2806: error: cannot convert 'bool*' to 'LPBOOL {aka int*}' for argument '5' to 'WINBOOL CopyFileExW(LPCWSTR, LPCWSTR, LPPROGRESS_ROUTINE, LPVOID, LPBOOL, DWORD)'
                            &BackupManager::copyProgress, this, &bStopBackup, 0);
                                                                               ^

enter image description here

Full Code Example:

 class BackupManager : public QObject {
     Q_OBJECT

 private:
 QWaitCondition pauseThreadCondition;
 QMutex backupPauseLock;
 bool bPauseBackup = false, bStopBackup = false;

 static DWORD CALLBACK copyProgress(
      LARGE_INTEGER totalSize, LARGE_INTEGER totalTransferred,
      LARGE_INTEGER streamSize, LARGE_INTEGER streamTransferred,
      DWORD streamNo, DWORD callbackReason, HANDLE src, HANDLE dst,
      LPVOID data);

     void copyFile(QString m_src, QString m_dst);

  //...

  signals:
     void fileCopyFinished();
     void fileCopyFailed(QString error);
     void fileCopyProgress(qint64 progress, qint64 total);
  //...
}

and source

void BackupManager::copyFile(QString m_src, QString m_dst)
{
     auto rc = CopyFileExW((LPCWSTR)m_src.utf16(), (LPCWSTR)m_dst.utf16(),
                           &BackupManager::copyProgress, this, &bStopBackup, 0);
     if (!rc)
          emit fileCopyFailed(getLastErrorMsg());
     emit fileCopyFinished();
}
DWORD CALLBACK BackupManager::copyProgress(
     const LARGE_INTEGER totalSize, const LARGE_INTEGER totalTransferred,
     LARGE_INTEGER, LARGE_INTEGER, DWORD,
     DWORD, HANDLE, HANDLE,
     LPVOID data)
{
//     emit fileCopyProgress(totalTransferred.QuadPart, totalSize.QuadPart);
//     if (bPauseBackup) {
//          backupPauseLock.lock();
//          pauseThreadCondition.wait(&backupPauseLock);
//          backupPauseLock.unlock();
//     }
     return PROGRESS_CONTINUE;
}

Taking a look at the error, it appears to require an int type (for the LPBOOL). Is it possible for me to use a bool in any way?


UPDATE 2

A quick search helped me with this using the BOOL datatype for bStopBackup which can be found in minwindef.h.

It compiles now

CybeX
  • 2,060
  • 3
  • 48
  • 115
  • of course callback must be static member. and unclear what errors you got when/if you make it static – RbMm Aug 07 '20 at 11:39
  • @RbMm hmm, I searched for the "static" keyword on the LPROUTINE & CopyFileExW page, but didn't find anything. How do you know it should be static? Also, see update – CybeX Aug 07 '20 at 12:16
  • 1
    because any callback must exactly match signature. not static member not mach. so only static can be of course. for this not need any documentation – RbMm Aug 07 '20 at 12:18
  • and are you understand different between *bool* and *BOOL* - compiler say you all. not understand in what problem – RbMm Aug 07 '20 at 12:20
  • 1
    `BOOL bStopBackup = false;` must be – RbMm Aug 07 '20 at 12:22
  • @RbMm thank you for the help, much appreciated! – CybeX Aug 07 '20 at 12:24
  • Instead of _Update 2_, post an answer to your question. – scopchanov Aug 07 '20 at 13:28

0 Answers0