News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Help with CopyFileEx and CopyProgressRoutine

Started by shadow, June 27, 2005, 11:10:57 PM

Previous topic - Next topic

shadow

How do you use CopyProgressRoutine with CopyFileEx in MASM?  I can't find examples anywhere!  I really want to use a progress bar while copying files in my program and be able to pause and resume the copy operation .  Thanks for your help!      :wink

shadow

Jeez isCopyProgressRoutine even supported by masm32?? I can't find any reasources anywhere...   ::)  Growl..  No one has ever used CopyProgressRoutine in their programs?

Mark Jones

Wow, no references to it occur in masm32\include... think you've stumbled upon a function not implemented in MASM32 yet! :clap:

Anyone know in what .DLL the CopyProgressRoutine function lies? (Or if there is some other reason it is not included?) We should be able to make libs for it easily.
"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08

donkey

Quote from: Mark Jones on July 03, 2005, 04:10:11 PM
Wow, no references to it occur in masm32\include... think you've stumbled upon a function not implemented in MASM32 yet! :clap:

Anyone know in what .DLL the CopyProgressRoutine function lies? (Or if there is some other reason it is not included?) We should be able to make libs for it easily.

The CopyProgressRoutine is not in any DLL, it is an application defined callback. The name is simply a placeholder so that it can be described, nothing more. You must write the routine and pass the address to the CopyFileEx function in the lpProgressRoutine parameter.

Just to be clear here, it is not part of the API and does not really exist, you must write it yourself.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/copyprogressroutine.asp

It would look something like this

CopyProgressRoutine FRAME cbFileLow,cbFileHigh,cbTransferredLow,cbTransferredHigh,cbStreamLow,cbStreamHigh,cbStreamTransferredLow,cbStreamTransferredHigh,dwStreamNumber,dwCallbackReason,hSourceFile,hDestinationFile,lpData

mov edx,0
mov eax,[cbTransferredLow]
shl eax,8
mov ecx,[cbFileLow]
div ecx
mov ecx,100
mul ecx
shr eax,8
// Display progress here eax contains the % of transfer completed

ret
ENDF
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

Mark Jones

Aaah, well we heard it right from the Donkey's mouth. :toothy I was wondering how it could be an API exactly, but thought there would be a PROTO for it in any case.
"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08

shadow

#5
wow donkey, thanks for your help.  I would have never figured out how to do that on my own.   :eek  I was thinking it would be a structure like OPENFILENAME.

That looks like GoASM...
would that be the same as


CopyProgressRoutine PROC TotalFileSize:DWORD,TotalBytesTransferred:DWORD,StreamSize:DWORD,StreamBytesTransferred:DWORD,dwStreamNumber:DWORD,dwCallbackReason:DWORD,hSourceFile:DWORD,hDestinationFile:DWORD,lpData:DWORD

mov edx,0
mov eax,[TotalBytesTransferred]
shl eax,8
mov ecx,[TotalFileSize]
div ecx
mov ecx,100
mul ecx
shr eax,8
invoke SendDlgItemMessage,hWnd,IDC_PGB2,PBM_SETPOS,eax,0
ret
CopyProgressRoutine endp


?

And how do you get lpData to CopyProgressRoutine?


donkey

Actually the first 4 parameters are split high/low in my proc, they are actually LARGE_INTEGER types and therefor should be QWORDs not DWORDS...

CopyProgressRoutine PROC TotalFileSize:QWORD,TotalBytesTransferred:QWORD,StreamSize:QWORD,StreamBytesTransferred:QWORD,dwStreamNumber:DWORD,dwCallbackReason:DWORD,hSourceFile:DWORD,hDestinationFile:DWORD,lpData:DWORD

etc...


In GoAsm the parameters must be DWORD sized as in reality that is all the stack can use. you might like to split them up as well, makes it easier than dealing with all those disparaging types.


lpData is passed in the lpData parameter of CopyFileEx, it is user defined and can be anything you like.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

shadow

Sorry... I'm still really new to this...
would I split them like this?

invoke atodw,addr TotalBytesTransferred
shl eax,32
push TotalBytesTransferred
push eax
call dwtoa
invoke atodw,addr TotalFileSize
shl eax,32
push TotalFileSize
push eax
call dwtoa

(Just a guess) to get the low DWORD out of a QWORD?

invalid instruction operands for both push TotalFileSize and push TotalBytesTransferred when TotalBytesTransferred and TotalFileSize are QWORDS... I guess a QWORD can't fit in a 32 bit register.  How do I split these up?


donkey

No, atodw converts ascii to a dword for example the string "1234" to a numeric value. A QWORD is essentially 2 DWORDs stored contiguously with the low order DWORD first. In a structure it would look like this (this is just an example for demonstration purposes, it is not really a structure)...

QWORD struct
LowPart DD ?
HighPart DD ?
QWORD ends


So in order to extract the low order dword from a qword in MASM you would use DWORD PTR as follows...

SomeQWord DQ 12345

mov eax, DWORD PTR SomeQWord


To get the high part you would move the pointer ahead by 4 bytes...

mov eax, DWORD PTR SomeQWord+4
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

donkey

For what you need using integer arithmetic might not be the best idea, if you are looking to get the percentage of the copy completed you might think about the FPU. This is because some files may be over 4 Gig in size and DWORD math fails at that point. To get the percentage using the FPU you would do this...

LOCAL Percentage :DWORD

mov [Percentage], 100
fild TotalBytesTransferred
fild TotalFileSize
db 0DEh, 0F9h ; For some stupid reason MASM won't encode FDIVP without operands ????
fild Percentage
db 0DEh, 0C9h ; Same stupid thing for FMULP
fistp Percentage


I used Percentage the first time just to store 100, as the FPU cannot take immediate operands. This will use the QWORDs directly, no need to alter them. On completion Percentage will contain a DWORD percentage (0-100).

Note that for the FDIVP and FMULP instructions I couldn't figure out how to get MASM to properly encode them. It kept giving an error even though they are perfectly legal without operands. Eventually I just gave up and coded those two lines in HEX, it is sometimes easier not to argue with the assembler :) The pop versions of the instructions are necessary in order to balance the FPU.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

shadow

 :U Thanks!
I'm still not getting something though... this basically what I have:

.data
data   DWORD 0

.code
invoke CopyFileEx,addr finalpth,addr copypath,addr CopyProgressRoutine,addr data,FALSE,NULL

CopyProgressRoutine PROC TotalFileSize:QWORD,TotalBytesTransferred:QWORD,StreamSize:QWORD,StreamBytesTransferred:QWORD,dwStreamNumber:DWORD,dwCallbackReason:DWORD,hSourceFile:DWORD,hDestinationFile:DWORD,lpData:DWORD

LOCAL Percentage :DWORD

mov [Percentage], 100
fild TotalBytesTransferred
fild TotalFileSize
db 0DEh, 0F9h
fild Percentage
db 0DEh, 0C9h
fistp Percentage
invoke SendDlgItemMessage,hWnd,IDC_PGB2,PBM_SETPOS,Percentage,0
ret
CopyProgressRoutine endp

I'm sorta confused... CopyFileEx is supposed to send all this to CopyProgressRoutine, but what does lpData do?  I just have lpData for CopyFileEx going to data:DWORD.   Is my CopyProgressRoutine supposed to do something with it?  TotalBytesTransferred and TotalFileSize seem to be empty when I run my code..   :eek  I'm so confused...  But thanks for spending some 4th of july time trying to help me! :) (old school smiley) Happy 4th by the way... everyone :toothy


donkey

As I said in an earlier post...

QuotelpData is passed in the lpData parameter of CopyFileEx, it is user defined and can be anything you like.

Just set it to 0 if you don't need to pass any extra information to the callback.

In Canada the holiday is the 1st of July ;) The 4th is US only.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

shadow

O!  so i don't really need it :)  Happy 1st of july 3 days ago then!    :lol

donkey

Thanks :)

You must put PROGRESS_CONTINUE in EAX before you return from the callback if you wish to continue copying the file. Either that or one of the other allowed values...

PROGRESS_CONTINUE (0) Continue the copy operation.
PROGRESS_CANCEL (1) Cancel the copy operation and delete the destination file.
PROGRESS_STOP (2) Stop the copy operation. It can be restarted at a later time.
PROGRESS_QUIET (3) Continue the copy operation, but stop invoking CopyProgressRoutine to report progress.

Since PBM_SETPOS returns the previous position of your progress bar in EAX, you are definitely not returning the right response from the callback. As soon as your progress indicator reaches 4 you effectively shut the routine off as PROGRESS_QUIET = 3, but I doubt you got there as you would have sent PROGRESS_CANCEL at 2%.

I tried the following with a 4.5 Gig file and it worked flawlessly, didn't bother setting up the progress indicator etc... but the percentages printed perfectly all values, 0 - 100. (GoAsm Syntax)

invoke CopyFileEx,"C:\BIG_DVD.ISO","C:\RadGoAsm\BIG_DVD.ISO",offset CopyProgressRoutine,0,0,0

CopyProgressRoutine FRAME cbFileLow,cbFileHigh,cbTransferredLow,cbTransferredHigh,cbStreamLow,cbStreamHigh,cbStreamTransferredLow,cbStreamTransferredHigh,dwStreamNumber,dwCallbackReason,hSourceFile,hDestinationFile,lpData

LOCAL Percentage :D

DATA SECTION
OldPercent DD 0
CODE SECTION

mov D[Percentage], 100
fild Q[cbTransferredLow]
fild Q[cbFileLow]
fdivp
fild D[Percentage]
fmulp
fistp D[Percentage]

// Display progress here
mov eax,[Percentage]
cmp eax,[OldPercent]
je >
PrintDec([Percentage])
:
mov [OldPercent],eax

mov eax,PROGRESS_CONTINUE
ret
ENDF

"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

chep

BTW, how does exactly the pause/resume thing work?

Here is how I understand it :

- call CopyFileEx with the COPY_FILE_RESTARTABLE flag
- later, send PROGRESS_STOP from the progress routine
- even later, calling CopyFileEx again with exactly the same parameters should resume the copy operation

Am I right? I don't find the documentation is really clear about this point...