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

My goal is to copy files and display the progress of the copy action with a progress bar.

Note: The files could be quite large.

I found an API that returns the progress to the address of LpprogressRoutine.

What I don’t know is how to code this within the Clarion context.

I’m open to ideas if there’s an easier way to do this.

BOOL CopyFileExA(

[in] LPCSTR lpExistingFileName,
[in] LPCSTR lpNewFileName,
[in, optional] LPPROGRESS_ROUTINE lpProgressRoutine,
[in, optional] LPVOID lpData,
[in, optional] LPBOOL pbCancel,
[in] DWORD dwCopyFlags
);

Callback Routine

LPPROGRESS_ROUTINE LpprogressRoutine;

DWORD LpprogressRoutine(
[in] LARGE_INTEGER TotalFileSize,
[in] LARGE_INTEGER TotalBytesTransferred,
[in] LARGE_INTEGER StreamSize,
[in] LARGE_INTEGER StreamBytesTransferred,
[in] DWORD dwStreamNumber,
[in] DWORD dwCallbackReason,
[in] HANDLE hSourceFile,
[in] HANDLE hDestinationFile,
[in, optional] LPVOID lpData
)

I have this inside a Class CLW:

MAP
    MODULE('WinApi')
        drCopyFileExA(STRING lpExistingFileName,STRING lpNewFileName,ULONG lpProgressRoutine,Long lpData,Byte pbCancel,Long dwCopyFlags),byte,PASCAL,name('CopyFileExA')
        !drLpprogressRoutine(Long TotalFileSize,Long TotalBytesTransferred,Long StreamSize,Long StreamBytesTransferred,ULONG dwStreamNumber,ULONG dwCallbackReason,Long hSourceFile,Long hDestinationFile,Long lpData),ULONG,PASCAL,name('LpprogressRoutine')
    End
END

Any words of wisdom would be greatly appreciated!

1 Like

I’m running out, suggest look at SHFileOperationA that will show its own Progress Window using FOF_SIMPLEPROGRESS. I thnik you can pass Wnd Hnd as Zero.

Here are some translations. These are partly automated and not tested. You have to read MSDN for details.

SHFileOperation    PROCEDURE(       |    !int SHFileOperationA(
      LONG AddressLPSHFILEOPSTRUCTA |    !inout LPSHFILEOPSTRUCTA lpFileOp
    ),SIGNED ,RAW,PASCAL,DLL(1),PROC,name('SHFileOperationA')

SHFILEOPSTRUCTAtype GROUP,TYPE !,PRE()    !typedef struct _SHFILEOPSTRUCTA {
hwnd                      SIGNED               !HWND hwnd
wFunc                     UNSIGNED             !UINT wFunc
pFrom_PCZZSTR_Addr        LONG                 !PCZZSTR pFrom Address of File Name(s) String(s) Double Null Term
pTo_PCZZSTR_Addr          LONG                 !PCZZSTR pTo   Address of File Name(s) String(s) Double Null Term
fFlags                    LONG                 !FILEOP_FLAGS fFlags
fAnyOperationsAborted     BOOL                 !BOOL fAnyOperationsAborted
hNameMappings             UNSIGNED             !LPVOID hNameMappings
lpszProgressTitle         UNSIGNED             !PCSTR lpszProgressTitle - Address of *CSTRING Optional for  FOF_SIMPLEPROGRESS
    END ! } SHFILEOPSTRUCTA, *LPSHFILEOPSTRUCTA;

I would declare the pFrom and pTo PCZZSTR as a Clarion STRING. Then terminate the file name with
'<0,0>' .


! Shell File Operations

FO_MOVE                    EQUATE(0001h)  !FO_MOVE 0x0001
FO_COPY                    EQUATE(0002h)  !FO_COPY 0x0002
FO_DELETE                  EQUATE(0003h)  !FO_DELETE 0x0003
FO_RENAME                  EQUATE(0004h)  !FO_RENAME 0x0004

! SHFILEOPSTRUCT.fFlags and IFileOperation::SetOperationFlags() flag values

FOF_MULTIDESTFILES         EQUATE(0001h)  !FOF_MULTIDESTFILES 0x0001
FOF_CONFIRMMOUSE           EQUATE(0002h)  !FOF_CONFIRMMOUSE 0x0002
FOF_SILENT                 EQUATE(0004h)  !FOF_SILENT 0x0004 // don't display progress UI (confirm prompts may be displayed still)
FOF_RENAMEONCOLLISION      EQUATE(0008h)  !FOF_RENAMEONCOLLISION 0x0008 // automatically rename the source files to avoid the collisions
FOF_NOCONFIRMATION         EQUATE(0010h)  !FOF_NOCONFIRMATION 0x0010 // don't display confirmation UI, assume "yes" for cases that can be bypassed, "no" for those that can not
FOF_WANTMAPPINGHANDLE      EQUATE(0020h)  !FOF_WANTMAPPINGHANDLE 0x0020 // Fill in SHFILEOPSTRUCT.hNameMappings
! Must be freed using SHFreeNameMappings
FOF_ALLOWUNDO              EQUATE(0040h)  !FOF_ALLOWUNDO 0x0040 // enable undo including Recycle behavior for IFileOperation::Delete()
FOF_FILESONLY              EQUATE(0080h)  !FOF_FILESONLY 0x0080 // only operate on the files (non folders), both files and folders are assumed without this
FOF_SIMPLEPROGRESS         EQUATE(0100h)  !FOF_SIMPLEPROGRESS 0x0100 // means don't show names of files
FOF_NOCONFIRMMKDIR         EQUATE(0200h)  !FOF_NOCONFIRMMKDIR 0x0200 // don't dispplay confirmatino UI before making any needed directories, assume "Yes" in these cases
FOF_NOERRORUI              EQUATE(0400h)  !FOF_NOERRORUI 0x0400 // don't put up error UI, other UI may be displayed, progress, confirmations
FOF_NOCOPYSECURITYATTRIBS  EQUATE(0800h)  !FOF_NOCOPYSECURITYATTRIBS 0x0800 // dont copy file security attributes (ACLs)
FOF_NORECURSION            EQUATE(1000h)  !FOF_NORECURSION 0x1000 // don't recurse into directories for operations that would recurse
FOF_NO_CONNECTED_ELEMENTS  EQUATE(2000h)  !FOF_NO_CONNECTED_ELEMENTS 0x2000 // don't operate on connected elements ("xxx_files" folders that go with .htm files)
FOF_WANTNUKEWARNING        EQUATE(4000h)  !FOF_WANTNUKEWARNING 0x4000 // during delete operation, warn if object is being permanently destroyed instead of recycling (partially overrides FOF_NOCONFIRMATION)
! #if (NTDDI_VERSION >= NTDDI_WINXP)
FOF_NORECURSEREPARSE       EQUATE(8000h)  !FOF_NORECURSEREPARSE 0x8000 // deprecated; the operations engine always does the right thing on FolderLink objects (symlinks, reparse points, folder shortcuts)
! #endif // (NTDDI_VERSION >= NTDDI_WINXP)
! #define FOF_NO_UI        (FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_NOCONFIRMMKDIR) // don't display any UI at all

You must implement the callback so don’t declare it inside a MODULE, declare it inside a MAP and implement for your needs.

I’ve only used copyfileA in some template Dll’s to move files around so far, but I can see CopyFileEx has the same two parameters as CopyFileA

BOOL CopyFileExA(
  [in]           LPCSTR             lpExistingFileName,
  [in]           LPCSTR             lpNewFileName,

CopyFileA function (winbase.h) - Win32 apps | Microsoft Docs

BOOL CopyFileA(
  [in] LPCSTR lpExistingFileName,
  [in] LPCSTR lpNewFileName,

some hints
lp = Long Pointer which is a Long in Clarion.
another way of expressing a long point is to use the *before the data type, most will be familiar with *cstring as a parameter, but you could do *long, and others.
It boils down to do you want clarion to do this for you
Loc:Address1 long
Loc:Address2 long
Loc:Bool bool
Loc:ReturnValueBool bool
Loc:Cstring1 cstring(1000)
Loc:Cstring2 cstring(1000)
Loc:ReturnValueBool = CopyFileA(Loc:Address1,Loc:Address2,Loc:Bool)
Peek(loc:Address1,Loc:cstring1)
Peek(loc:Address2,Loc:cstring2)

TLDR * = Peek(LongPointer,DestinationVariable)

As this is attached to a Cstr
[MS-DTYP]: LPCSTR | Microsoft Docs

its a CONST in the clarion parameter and it say in the description its a null terminated string of ansi characters. So as its null terminated you would need to use a Clarion cstring as that is also null terminated.

So you have two ways to do the api prototype in Clarion
CopyFileA(long,long,bool),Bool,Pascal,Name(‘CopyFileA’)
or
CopyFileA(CONST *cstring, CONST *cstring,bool),bool,Pascal,Name(‘CopyFileA’)
In clarion CONST tells clarion the parameter being passed by address can not be changed, its treated as a read only a parameter. However you can leave the CONST out of the prototype so it looks like this
CopyFileA(*cstring, *cstring,bool),bool,Pascal,Name(‘CopyFileA’)

Personally I’d get copyFileA working first and then try the CopyFileExA.

Common windows data types can be found here
[MS-DTYP]: Common Data Types | Microsoft Docs

Common windows base types can be found here
[MS-DTYP]: Common Base Types | Microsoft Docs
so it should be possible to work out what data type you need or group structure you need to make if you are getting into 64bit territory.

and for callbacks, this might help you

fwiw.

Hello Mike,

I’ve actually got the callback working except that it GPF’s if I try to get to parameter values.

Thanks!!!

As mentioned on Skype
You need to use the 8 byte LARGE ( or ULARGE) instead of the 4 byte LONG

There’s an include, something like i64.inc that has the LARGE data type (sorry I’m away from my computer ATM so I can’t look it up for you)

I would urge you to try ShellFileOperation. I posted the prototypes back in my prior post. Its not a simple call but it provides its own window with progress and does all the calculations.

For CopyFileExA() to work your prototypes look mostly all wrong to me, but I could be wrong. It has some complex stuff I’m not sure about. The only way to make it work is to dive in and try so if you want it to work just keep going.

Here’s how I would write the prototypes (not tested). I’m not sure what that pbCancel is about.

CopyFileExA    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')

LARGE_INTEGER_In  EQUATE(REAL)  !??? Not sure this is right ???

LPPROGRESS_ROUTINE    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

TotalFileSize   LIKE(INT64),OVER(R_TotalFileSize)   !??? Not sure this is right
Ditto for other 3 R_xxx

A LARGE_INTEGER is 64 bits, do you know how those work in Clarion and the i64.INC file?

I would have to look at some of my code for Int64 but IIRC an INT64 passed by value uses the 64-bit Floating Point registers so in Clarion need to prototype as a REAL. But its not a REAL so put an INT64 OVER() it.

1 Like

So I got it working.

Carl’s theory on using REAL’s is spot on.

MAP
    CopyProgressRoutine(REAL TotalFileSize,REAL TotalBytesTransferred,REAL StreamSize,REAL StreamBytesTransferred,ULONG dwStreamNumber,ULONG dwCallbackReason,Long hSourceFile,Long hDestinationFile,Long lpData),ULONG,PASCAL,name('LpprogressRoutine')
    MODULE('kernel32.dll') 
        drCopyFileExA(*CSTRING lpExistingFileName,*CSTRING lpNewFileName,ULONG lpProgressRoutine,Long lpData,BOOL pbCancel,DWORD dwCopyFlags),BOOL,PASCAL,RAW,name('CopyFileExA')
    END
END

The Callback:

CopyProgressRoutine Procedure(REAL TotalFileSize,REAL TotalBytesTransferred,REAL StreamSize,REAL StreamBytesTransferred,ULONG dwStreamNumber,ULONG dwCallbackReason,Long hSourceFile,Long hDestinationFile,Long lpData)

myBase dwrBase
st StringTheory
TransferredG Group(drINT64),Over(TotalBytesTransferred).
FileSizeG Group(drINT64),Over(TotalFileSize).

CODE
!Get the progress
myBase.SendDebug(myBase.GetProgress(TransferredG.lo,FileSizeG.lo))

…and the progress window

ScreenHunter 49

1 Like

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

Its the same trick I’m using here. :wink:

TLDR, the compiler isnt too fussy about the data types used in api declarations in clarion map modules() and windows isnt either provided the number of bytes of each parameter matches up in the right order.

A Real is an 8byte data type, so it gets its bytes and only later in the runtime does the code to process a Real get used.

A Real could be used where ever an 8byte parameter is specified, which would be alot of the 64bit api’s.

I should add, where you need to match the calling convention like whats detailed here x86 calling conventions - Wikipedia
just reverse the order of the parameters like I did, so these are the same

  map
  module('win32')
  Pragma ('call(c_conv=> on)')
  someWinAPIusingC(MatchingByteLengthDataType param1, MatchingByteLengthDataType param2),C
  Pragma ('call(c_conv=> off)')
  end
  end

  map
  module('win32')
  someWinAPIusingC(MatchingByteLengthDataType param2, MatchingByteLengthDataType param1)
  end
  end

I think its a few levels of progression up from a vintage tupperware shape sorter ball. :nerd_face:

Hi ,

may it is a silly question but when I tried to compile the example in Clarion 9 I get these errors:
2022-09-03 02 50 37

Thanks

You’ll have to add these types at the top. I think they were added in C11.

INT64    GROUP,TYPE
lo         ULONG
hi         LONG
         END

UINT64   GROUP,TYPE
lo         ULONG
hi         ULONG
         END
1 Like

Sorry … feeling stupid today :roll_eyes:

got this error !

image

In C9 you must link win32ext.lib.

1 Like

Which can do in code with:

PRAGMA('link(win32ext.lib)')

I put those PRAGMA up just above the MAP. I like that it moves with the code. Can OMIT('***', _C110_) … or _c100_

Very good. thanks.

one last question, I tried to run it in clarion 6.3 and I got the same error “Unresolved External CopyFileExA in CopyFileExTest.obj” and I tried to link win32ext.lib but did not work.

thank you for your support.

Regards

The API doc shows it’s in shell32
So, using libmaker, create a .lib for this API

You can try adding the entire dll
But it’s likely that will lead to duplicates.

So delete everything you don’t need inside of libmaker before you save the .lib

Then link in the lib you created

1 Like

With the shipping LibMaker it is a PITA to have to carefully delete all but 1 function. With the " @ArnorBld + Mark + my " LibMaker you can Search and Tag 1+ Functions then write just Tagged in the Lib.

A unique feature … You can Subtract the current Clarion Win32.Lib so just have left everything missing and will not have duplicate errors. This allows opening a new release ClaRun.dll then subtract a prior release to see new exports that may reveal new RTL features.

All set and working fine.

thank you all and best regards

the conclusion that after creating the new .lib, I compiled the project in Clarion 6.3 under windows 7 32 bit.

the application works fine under window 10 64 bit but crashes in window 7 32 bit :frowning_face: