1. copyFileEx() hanging
I'm almost done with my backup program for work. One person requested
a file-copy progress bar along with a total count progress bar. The
total count bar works fine, but when attempting to use copyFileEx()
with call-back routine, it just hangs the app. copyFileEx() still
copies the file successfully, however. So I am led to believe this is
a call-back issue. The call-back routine accepts 9 parameters, which I
believe is the limit, so I should be fine.
I've whipped up a small demo that demonstates this hanging behavior.
It may be downloaded here:
http://www.freewebtown.com/ghaberek/copy_crash.zip
Any advice is welcome.
~Greg Haberek
2. Re: copyFileEx() hanging
Greg Haberek wrote:
>
> I'm almost done with my backup program for work. One person requested
> a file-copy progress bar along with a total count progress bar. The
> total count bar works fine, but when attempting to use copyFileEx()
> with call-back routine, it just hangs the app. copyFileEx() still
> copies the file successfully, however. So I am led to believe this is
> a call-back issue. The call-back routine accepts 9 parameters, which I
> believe is the limit, so I should be fine.
>
> I've whipped up a small demo that demonstates this hanging behavior.
> It may be downloaded here:
> <a
> href="http://www.freewebtown.com/ghaberek/copy_crash.zip">http://www.freewebtown.com/ghaberek/copy_crash.zip</a>
>
> Any advice is welcome.
There are a few problems with your code. First, pbCancel is really a pointer
to a boolean. You're supposed to be able to set that at any time during
progress to cancel the transfer. Seems like it's duplicating the purpose
of the callback, but there you go. (Technically, lpData is supposed to
be a pointer, but it probably doesn't really matter since Windows doesn't
use it for anything).
Second, the first 4 parameters are defined as LARGE_INTEGERs, which means
that they're actually 64-bit integers. You need to use 2 32-bit parameters
to properly accept them. Then you can multiply the high value by
#100000000 and add together.
But this means that you're over the 9-parameter limit, so you can use fptr.e
(http://www.rapideuphoria.com/fptr.zip) to get around this. Finally,
the callback should actually be a cdecl callback. Here's how I reworked
the file so that it works (however, even copying a 10MB file, it happens so
quickly that no progress calls are actually made)--I've omitted the
createDir() routine, since I didn't change anything there:
include windir.ew as WD
include fptr.e
global constant xCopyFileExW = registerw32Function( kernel32, "CopyFileExW",
{C_POINTER,C_POINTER,C_POINTER,C_POINTER,C_POINTER,C_LONG}, C_INT )
global constant xCreateDirectoryW = registerw32Function( kernel32,
"CreateDirectoryW", {C_POINTER,C_POINTER}, C_INT )
global constant
-- values for dwCallbackReason
CALLBACK_CHUNK_FINISHED = #00000000,
CALLBACK_STREAM_SWITCH = #00000001,
-- return values from CopyProgressRoutine
PROGRESS_CONTINUE = 0,
PROGRESS_CANCEL = 1,
PROGRESS_STOP = 2,
PROGRESS_QUIET = 3
atom pbCancel
pbCancel = allocate( 4 )
global function copyFileEx( sequence pExistingFileName, sequence pNewFileName,
object pFlags )
-- pFlags may be dwCopyFlags or {lpProgressRoutine, lpData, pbCancel,
dwCopyFlags}
atom lpExistingFileName, lpNewFileName, lpProgressRoutine, lpData, dwCopyFlags
integer retv
-- \\?\ forces Windows to turn of directory parsing, effectively
-- increasing the path length from 255 to 32,767 characters
pExistingFileName = "\\\\?\\" & pExistingFileName
pNewFileName = "\\\\?\\" & pNewFileName
lpExistingFileName = WD:allocate_unicode( pExistingFileName )
lpNewFileName = WD:allocate_unicode( pNewFileName )
pbCancel = allocate(4)
if sequence(pFlags) and length(pFlags) = 4 then
lpProgressRoutine = pFlags[1]
lpData = allocate(4)
poke4( lpData, pFlags[2])
--pbCancel = pFlags[3]
poke4( pbCancel, pFlags[3] )
dwCopyFlags = pFlags[4]
else
lpProgressRoutine = 0
lpData = 0
--pbCancel = 0
poke4( pbCancel, 0 )
dwCopyFlags = pFlags
end if
retv = w32Func( xCopyFileExW,
{lpExistingFileName,lpNewFileName,lpProgressRoutine,lpData,pbCancel,dwCopyFlags}
)
free( lpExistingFileName )
free( lpNewFileName )
return retv
end function
-- set CopyCancel to w32True to stop the copy process
global integer CopyCancel
CopyCancel = w32False
global function CopyProgressRoutine(
atom TotalFileSizeLow, atom TotalFileSizeHigh,
atom TotalBytesTransferredLow, atom TotalBytesTransferredHigh,
atom StreamSizeLow, atom StreamSizeHigh,
atom StreamBytesTransferredHigh,atom StreamBytesTransferredLow,
object params )
atom dwStreamNumber, dwCallbackReason, hSourceFile, hDestinationFile, lpData
atom TotalFileSize, TotalBytesTransferred, StreamSize, StreamBytesTransferred
TotalFileSize = TotalFileSizeHigh * #100000000 + TotalFileSizeLow
TotalBytesTransferred = TotalBytesTransferredHigh * #100000000 +
TotalBytesTransferredLow
StreamSize = StreamSizeHigh * #100000000 + StreamSizeLow
StreamBytesTransferred = StreamBytesTransferredHigh * #100000000 +
StreamBytesTransferredLow
params = peek4u( params & 5 )
dwStreamNumber = params[1]
dwCallbackReason = params[2]
hSourceFile = params[3]
hDestinationFile = params[4]
lpData = params[5]
-- This routine will update your scroll bar
-- with the status of a file copy progress.
-- Your progress bar ID should be the lpData
-- parameter of copyFileEx()
--
-- Example:
-- i = copyFileEx( "Myfile1.ext", "Myfile2.ext", {CopyProgressRoutine_CB,
ProgBar1, 0, 0} )
if CopyCancel = w32True then
return PROGRESS_CANCEL
end if
if dwCallbackReason = CALLBACK_STREAM_SWITCH then
-- call for first time, setup scroll bar
if lpData != 0 then
lpData = peek4u( lpData )
setScrollRange( lpData, 0, TotalFileSize )
setScrollPos( lpData, 0 )
end if
CopyCancel = w32False
elsif dwCallbackReason = CALLBACK_CHUNK_FINISHED then
-- call to update scroll bar
if lpData != 0 then
lpData = peek4u( lpData )
setScrollPos( lpData, TotalBytesTransferred )
doEvents( 0 )
end if
end if
return PROGRESS_CONTINUE
end function
global constant
CopyProgressRoutine_ID = routine_id( "CopyProgressRoutine" ),
CopyProgressRoutine_CB = call_back_cdecl( CopyProgressRoutine_ID, 13 )
Matt Lewis
3. Re: copyFileEx() hanging
> There are a few problems with your code. First, pbCancel is really a poi=
nter
> to a boolean. You're supposed to be able to set that at any time during
> progress to cancel the transfer. Seems like it's duplicating the purpose
> of the callback, but there you go. (Technically, lpData is supposed to
> be a pointer, but it probably doesn't really matter since Windows doesn't
> use it for anything).
>
> Second, the first 4 parameters are defined as LARGE_INTEGERs, which means
> that they're actually 64-bit integers. You need to use 2 32-bit paramete=
rs
> to properly accept them. Then you can multiply the high value by
> #100000000 and add together.
>
> But this means that you're over the 9-parameter limit, so you can use fpt=
r.e
> (http://www.rapideuphoria.com/fptr.zip) to get around this. Finally,
> the callback should actually be a cdecl callback. Here's how I reworked
> the file so that it works (however, even copying a 10MB file, it happens =
so
> quickly that no progress calls are actually made)--I've omitted the
> createDir() routine, since I didn't change anything there:
Ok -- I applied the changes you made to my code, and it still crashes.
Maybe I missed something. I am making progress however, now I get a
machine-level crash instead of an all-out hang. :) The zip file
contains the changes to filecopy.ew as well as the ex.err file from
the crash.
Here's the file (again): http://www.freewebtown.com/ghaberek/copy_crash.zip
~Greg