Windows API help with CopyFileExA() and Callback to show Progress

Dang … I made my own little example to prove the REAL worked.

Note this is only for a LARGE_INTEGER passed by Value, that I think would be rare,
and not passed by address P LARGE_INTEGER e.g. see GetDiskFreeSpaceExA()


!CopyFileEx with Callback test by Carl Barnes - Copyright 2022 - Released under the MIT License
  PROGRAM

LARGE_INTEGER_In  EQUATE(REAL)  !64 bit INT passed by value Prototype as REAL

  MAP
TestCopy  PROCEDURE()  

CopyFileEx_PPROGRESS    PROCEDURE( |      !DWORD WINAPI *LPPROGRESS_ROUTINE(
    LARGE_INTEGER_In   R_TotalFileSize           , |  !_In_ LARGE_INTEGER TotalFileSize
    LARGE_INTEGER_In   R_TotalBytesTransferred   , |  !_In_ LARGE_INTEGER TotalBytesTransferred
    LARGE_INTEGER_In   R_StreamSize              , |  !_In_ LARGE_INTEGER StreamSize
    LARGE_INTEGER_In   R_StreamBytesTransferred  , |  !_In_ LARGE_INTEGER StreamBytesTransferred
    UNSIGNED           dwStreamNumber            , |  !_In_ DWORD dwStreamNumber
    UNSIGNED           dwCallbackReason          , |  !_In_ DWORD dwCallbackReason
    SIGNED             hSourceFile               , |  !_In_ HANDLE hSourceFile
    SIGNED             hDestinationFile          , |  !_In_ HANDLE hDestinationFile
    <UNSIGNED          lpData>                     |  !_In_opt_ LPVOID lpData
    ),UNSIGNED,PASCAL
  
      MODULE('api')
        OutputDebugString(*CSTRING cMsg),PASCAL,DLL(1),RAW,NAME('OutputDebugStringA')
        GetLastError(),LONG,PASCAL,DLL(1) 

CopyFileEx    PROCEDURE( |                            !BOOL WINAPI CopyFileExA(
    *CSTRING   lpExistingFileName   , |  !_In_ LPCSTR lpExistingFileName
    *CSTRING   lpNewFileName        , |  !_In_ LPCSTR lpNewFileName
    LONG       lpProgressRoutine=0  , |  !_In_opt_ LPPROGRESS_ROUTINE lpProgressRoutine  Address(CallBack) 
    UNSIGNED   lpData=0             , |  !_In_opt_ LPVOID lpData
    <*BOOL     pbCancel>            , |  !_Inout_opt_ LPBOOL pbCancel
    UNSIGNED   dwCopyFlags            |  !_In_ DWORD dwCopyFlags
    ),BOOL ,RAW,PASCAL,DLL(1),PROC,name('CopyFileExA')   !If the function succeeds, the return value is nonzero.
      END  !Module API
      
  END

!https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-copyfileexa
COPY_FILE_FAIL_IF_EXISTS    EQUATE(00000001h)   !The copy operation fails immediately if the target file already exists.
COPY_FILE_NO_BUFFERING      EQUATE(00001000h)   !The copy operation is performed using unbuffered I/O, bypassing system I/O cache resources. Recommended for very large file transfers.
PROGRESS_CANCEL     EQUATE(1)   !Cancel the copy operation and delete the destination file.
PROGRESS_CONTINUE   EQUATE(0)   !Continue the copy operation.
PROGRESS_QUIET      EQUATE(3)   !Continue the copy operation, but stop invoking CopyProgressRoutine to report progress.
PROGRESS_STOP       EQUATE(2)   !Stop the copy operation. It can be restarted at a later time.

  CODE
  TestCopy()
  
TestCopy  PROCEDURE() 
ExistingFileName    CSTRING('XXX.txt') 
NewFileName         CSTRING('XXX_Copy.txt')
ProgressRoutine     LONG 
lpData              LONG 
boolCancel          BOOL 
CopyFlags           LONG 
RetCopy             BOOL 
    CODE
    IF ~EXISTS(ExistingFileName) THEN COPY('CopyFileExTest.clw',ExistingFileName).
    IF ~EXISTS(ExistingFileName) THEN 
        Message('You need to make a file to test copy named: ' & ExistingFileName, 'CopyFileEx Test File')
        RETURN
    END
    REMOVE(NewFileName)
    lpData=8312022
    ProgressRoutine = ADDRESS( CopyFileEx_PPROGRESS )
    RetCopy = CopyFileEx( |         
            ExistingFileName , |    !  *CSTRING   lpExistingFileName   , |  !_In_ LPCSTR lpExistingFileName
            NewFileName      , |    !  *CSTRING   lpNewFileName        , |  !_In_ LPCSTR lpNewFileName
            ProgressRoutine  , |    !  LONG       lpProgressRoutine=0  , |  !_In_opt_ LPPROGRESS_ROUTINE lpProgressRoutine  Address(CallBack) 
            lpData     , |          !  UNSIGNED   lpData=0             , |  !_In_opt_ LPVOID lpData
            boolCancel , |          ! <*BOOL     pbCancel>            , |  !_Inout_opt_ LPBOOL pbCancel
            CopyFlags  )            !  UNSIGNED   dwCopyFlags            |  !_In_ DWORD dwCopyFlags

    Message('CopyFileEx return='& RetCopy & CHOOSE(~RetCopy,'  FAILED','  Success!') & |
            '  <9>LastError='& GetLastError() &|
           '||Copy From: <9>'& ExistingFileName & |
            '|Copy To:    <9>'& NewFileName & |
            '','CopyFileEx Test')
    RETURN

!================= 
! https://docs.microsoft.com/en-us/windows/win32/api/winbase/nc-winbase-lpprogress_routine 

CopyFileEx_PPROGRESS    PROCEDURE( |      !DWORD WINAPI *LPPROGRESS_ROUTINE(
    LARGE_INTEGER_In   R_TotalFileSize           , |  !_In_ LARGE_INTEGER TotalFileSize
    LARGE_INTEGER_In   R_TotalBytesTransferred   , |  !_In_ LARGE_INTEGER TotalBytesTransferred
    LARGE_INTEGER_In   R_StreamSize              , |  !_In_ LARGE_INTEGER StreamSize
    LARGE_INTEGER_In   R_StreamBytesTransferred  , |  !_In_ LARGE_INTEGER StreamBytesTransferred
    UNSIGNED           dwStreamNumber            , |  !_In_ DWORD dwStreamNumber
    UNSIGNED           dwCallbackReason          , |  !_In_ DWORD dwCallbackReason
    SIGNED             hSourceFile               , |  !_In_ HANDLE hSourceFile
    SIGNED             hDestinationFile          , |  !_In_ HANDLE hDestinationFile
    <UNSIGNED          lpData>                   )    !_In_opt_ LPVOID lpData       ) !,UNSIGNED ,RAW,PASCAL

!Note: LARGE_INTEGER_In  EQUATE(REAL)  !64 bit INT passed by value Prototype as REAL
TotalFileSize           LIKE(INT64),OVER(R_TotalFileSize)       !Passed REAL but its really 64 bit INT
TotalBytesTransferred   LIKE(INT64),OVER(R_TotalBytesTransferred) 
StreamSize              LIKE(INT64),OVER(R_StreamSize)   
StreamBytesTransferred  LIKE(INT64),OVER(R_StreamBytesTransferred)   
ReturnProgress  LONG 
    CODE
    CASE Message('In callback lpData=' & lpData  & |
            '||TotalFileSize = '          & TotalFileSize.lo & |
            ' <9>TotalBytesTransferred = '& TotalBytesTransferred.lo & |
            '|StreamSize = '                & StreamSize.lo & |
            ' <9>StreamBytesTransferred = ' & StreamBytesTransferred.lo & |
            '||dwStreamNumber = ' & dwStreamNumber & |
            '|dwCallbackReason = '& dwCallbackReason & |
            '|hSourceFile = '& hSourceFile & |
            ' <9>hDestinationFile = '& hDestinationFile & |
            '','CopyFileEx_PPROGRESS',ICON:Copy,'Continue|Quite|Cancel Copy')
    OF 1 ; ReturnProgress = PROGRESS_CONTINUE          
    OF 2 ; ReturnProgress = PROGRESS_QUIET           
    OF 3 ; ReturnProgress = PROGRESS_CANCEL 
    END 
    RETURN ReturnProgress

CopyFileExTestProject.zip (2.5 KB)

3 Likes