Good Day,

This messageboard has helped me so very much, and I wanted to return a little something. I am posting a Copy Files routine. This routine will copy files using filename.ext and wildcards while filtering out the folders, and this proc is easy to manipulate into a movefiles routine.

I hope that this contribution helps people struggling with this topic.


;================ How to use Copy_Files PROC ===============
;Copy_Files PROTO :DWORD, :DWORD

;.data
;FilesPattern db "*.*",0
;DestinationDir db "c:\",0
;BackSlash db "\",0

;invoke Copy_Files,addr FilesPattern,addr DestinationDir

;================= Required Data In Main File ================
.data?
FHandle dd ?
hSearch dd ?
Win32FindData WIN32_FIND_DATA<>
;=================================================
Copy_Files proc Pattern:DWORD, DestFolder:DWORD
LOCAL tmpbuf:BYTE
LOCAL CmpByte:BYTE

invoke lstrcpy,addr tmpbuf,DestFolder
invoke lstrlen,addr tmpbuf
dec eax
lea ebx, tmpbuf
mov cl, BYTE PTR

.if cl != '\'
invoke lstrcat,addr tmpbuf,addr BackSlash
.endif

invoke FindFirstFile,Pattern,addr Win32FindData
.if eax != INVALID_HANDLE_VALUE
mov hSearch,eax
xor edi,edi
.while eax!=ERROR_NO_MORE_FILES

invoke lstrcat,ADDR tmpbuf,ADDR Win32FindData.cFileName

invoke CopyFile,addr Win32FindData.cFileName, addr tmpbuf,0
invoke FindNextFile,hSearch,addr Win32FindData
invoke GetLastError
.endw

invoke FindClose,hSearch
.endif
ret
Copy_Files endp
;=================================================


I am always looking to improve procs, so feel free to optimize this...;)
Posted on 2002-12-13 07:34:00 by SpEcIeS
SpEcIeS,

Here is the same code in C from MSDN:


WIN32_FIND_DATA FileData;
HANDLE hSearch;
DWORD dwAttrs;
char szDirPath[] = "c:\;
char szNewPath[MAX_PATH];
char szHome[MAX_PATH];
BOOL fFinished = FALSE;

hSearch = FindFirstFile("*.*", &FileData);
if (hSearch == INVALID_HANDLE_VALUE)
{
ErrorHandler("No files found.");
}

while (!fFinished)
{
lstrcpy(szNewPath, szDirPath);
lstrcat(szNewPath, FileData.cFileName);
if (!CopyFile(FileData.cFileName, szNewPath, FALSE))
{
ErrorHandler("Couldn't copy file.");
}

if (!FindNextFile(hSearch, &FileData))
{
if (GetLastError() == ERROR_NO_MORE_FILES)
{
MessageBox(hwnd, "No more files.",
"Search completed.", MB_OK);
fFinished = TRUE;
}
else
{
ErrorHandler("Couldn't find next file.");
}
}
}
if (!FindClose(hSearch))
{
ErrorHandler("Couldn't close search handle.");
}

I'm wondering why you translate from C in "C like ASM"
Your code will be slower because of that.

The messageboard will helps you again with Readiosys's advice:
"Personally, I never use these as if I'm writing in assembly, it is to have 100% control over my source code...
Otherwise, it is better to use a HLL language like C with high optimizing compilers."

You can read it here: http://www.asmcommunity.net/board/showthread.php?threadid=9462

Regards,
Lingo
Posted on 2002-12-13 09:40:55 by lingo12
Thanks for the input...:grin:

Since I was having difficulties in creating such a procedure, I used a C code template (Not from MSDN) to build such a function. It gets the job done, but I see your point about being slower. I guess I will have to go over this proc and speed things up.
Also, It is difficult to paste information on the board. I have looked over the code that I pasted and have found that not only has the code been drawn in, but a backslash was removed in the if cl != statement. I am not sure why, but it happened...:(
Anyway, thanks again for the imput. :alright:
Posted on 2002-12-13 10:00:07 by SpEcIeS
Here is an altered version of the original Copy_Files above. Is it really any different that using .IF and .WHILE? Perhaps someone could enlighten me on this subject. <???> :confused:

Revamped Copy_Files:

;======= How to use Copy_Files PROC ===========
;Copy_Files PROTO :DWORD, :DWORD

;.data
;FilesPattern db "*.*",0
;DestinationDir db "c:\",0
;BackSlash db "\",0

;invoke Copy_Files,addr FilesPattern,addr DestinationDir
;======= Required Data In Main File =============
.data?
FHandle dd ?
hSearch dd ?
Win32FindData WIN32_FIND_DATA<>
;========================================
Copy_Files proc Pattern:DWORD, DestFolder:DWORD
LOCAL tmpbuf:BYTE

invoke FindFirstFile,Pattern,addr Win32FindData

cmp eax,INVALID_HANDLE_VALUE
je InvalidHandle

mov hSearch,eax

CheckForFiles:

cmp eax,ERROR_NO_MORE_FILES
je LeaveLoop

invoke lstrcpy,addr tmpbuf,DestFolder
invoke lstrlen,addr tmpbuf

dec eax
lea ebx, tmpbuf
mov cl, BYTE PTR

cmp cl,05ch
je BSOK

invoke lstrcat,addr tmpbuf,addr BackSlash
BSOK:

cmp Win32FindData.dwFileAttributes,FILE_ATTRIBUTE_DIRECTORY
jne NotDir

jmp Continue
NotDir:

invoke lstrcat,ADDR tmpbuf,ADDR Win32FindData.cFileName
invoke CopyFile,addr Win32FindData.cFileName, addr tmpbuf,0

Continue:
invoke FindNextFile,hSearch,addr Win32FindData
invoke GetLastError

jmp CheckForFiles

LeaveLoop:

invoke FindClose,hSearch

InvalidHandle:
ret
Copy_Files endp
;========================================

This proc is tested on Win95 and 98....:)
Posted on 2002-12-15 08:59:52 by SpEcIeS
I find that this proc doesn't work in Win2k, but I could not find the purpose of it :(
Posted on 2002-12-15 12:00:04 by gaidar
Thanks for the input on the win2k angle gaidar :) Perhaps someone else can contribute other information regarding OS performance. I would be very greatful.

As for the use, it is good for copying file(s) from one folder to another using filename.ext and/or wildcards while filtering out the folders.

I have not tested the speed of the proc yet, but I will be on that one soon. :grin:
Posted on 2002-12-15 13:06:14 by SpEcIeS
SpEcIeS,
You can substitute:

- "invoke lstrcpy,addr tmpbuf,DestFolder
invoke lstrlen,addr tmpbuf"
with "extended" lstrlen function
from algo section

- "lea ebx, tmpbuf
mov cl, BYTE PTR
cmp cl,05ch"
with cmp byte ptr , 05Ch

- "invoke lstrcat,addr tmpbuf,addr BackSlash"
with sample mov , 05Ch

- "jne NotDir
jmp Continue" with
je Continue

- CopyFile with CopyFileEx
and use lpProgressRoutine

- "FHandle" with nothing

- "hSearch" with esi

- " cmp eax,INVALID_HANDLE_VALUE
je InvalidHandle
mov hSearch, eax " with

mov esi, eax
inc eax
je InvalidHandle


Regards,
Lingo
Posted on 2002-12-15 15:00:44 by lingo12
Thanks for the input lingo12 ;) I will get right on the modifications.

I have applied speed testings to the last two procs, old and new, and have found that the two are really not that different. I will reapply the testing once the new optimizations are in place.

Thanks again :grin:
Posted on 2002-12-15 15:13:37 by SpEcIeS
You won't get much speed improvement from a routine who's main bottleneck is the hardware disk IO. So don't bother optimising it for anything other than size.
Posted on 2002-12-15 16:16:49 by iblis
iblis,
It is just an asm "literate" optimization rather than a speed optimization
If we want a speed optimization we will use additional criteria,
well formulated in A.Fog's book.
From other hand, the question "Why we use unoptimized assembly rather than C/C++"
is still in suspense, because modern C/C++ compilers have optimization options,
ml.exe hasn't. (see my first reply)
So, "the bottleneck is the hardware disk IO" is not important in our case, because it
doesn't depend on us and as a programmers we must improve our programming style
rather than be lazy.

Regards,
Lingo
Posted on 2002-12-15 17:41:22 by lingo12
Huh?

I was not talking to you. I was responding to SpEcIeS' post where he said he was testing his procedure for speed. Speed is not important here. Focus on size.

That's all. ;)
Posted on 2002-12-16 03:51:54 by iblis
I am with Iblis here, get it to work first, get it as small as you can be bothered and keep it ready to use with your asm code where you need file copy.

Having it already written in C/C++/VB/Delphi etc ... is not much use to you if your main source is in asm.

With regard to the posted code, I don't see the point of memory copy in the code when the file IO API function write to a buffer and read back from a buffer. Just allocate the buffer size from the file that has been opened, write the data to it and then read it back with WriteFile() to the location on disk.

Regards,

hutch@movsd.com
Posted on 2002-12-16 16:40:50 by hutch--
"...C/C++/VB/Delphi etc.. "
I'm wondering why Power Basic isn't included

Regards,
Lingo
Posted on 2002-12-16 17:26:30 by lingo12
Lingo12,

"I'm wondering why Power Basic isn't included"

Probably because it cannot be used in asm either. :grin:

Regards,

hutch@movsd.com
Posted on 2002-12-17 04:54:42 by hutch--
Thanks for all the excellent input from all :)

I am still unclear about a few things. One of which is the line from lingo12: mov , 05Ch. I have not had any success with this, and I am really not clear how to setup CopyFileEx with lpProgressRoutine. However, the other lines of code were great and appreciated :) Perhaps someone could help me out with this CopyFileEx lpProgressRoutine issue? I have only been using the CopyFile function up to this point.

Here is the CopyFiles so far:

CopyFiles proc Pattern:DWORD, DestFolder:DWORD
LOCAL tmpbuf:BYTE

invoke FindFirstFile,Pattern,addr Win32FindData

mov esi, eax
inc eax
je InvalidHandle

CheckForFiles:
cmp eax,ERROR_NO_MORE_FILES
je LeaveLoop

invoke lstrcpy,addr tmpbuf,DestFolder
invoke lstrlen,addr tmpbuf

dec eax
cmp byte ptr ,05Ch
je BSOK

invoke lstrcat,addr tmpbuf,addr BackSlash
BSOK:

cmp Win32FindData.dwFileAttributes,FILE_ATTRIBUTE_DIRECTORY
je Continue

invoke lstrcat,addr tmpbuf,ADDR Win32FindData.cFileName
invoke CopyFile,addr Win32FindData.cFileName,addr tmpbuf,NULL

Continue:
invoke FindNextFile,esi,addr Win32FindData
invoke GetLastError

jmp CheckForFiles

LeaveLoop:
invoke FindClose,esi

InvalidHandle:
ret
CopyFiles endp

I must admit that this looks a lot better that the first example :grin:
Thanks again for all of the help.
Posted on 2002-12-18 07:33:11 by SpEcIeS
lingo12,

I finally figured out the mov , 05Ch code. It took a while to sink in :rolleyes: Here is the code change to the CopyFiles proc:

invoke lstrlen,addr tmpbuf

dec eax
cmp byte ptr ,05Ch
je BSOK

inc eax

mov byte ptr,05Ch
inc eax
mov byte ptr,0

BSOK:

Thanks again for the eye opener...:grin:
Posted on 2002-12-18 11:16:43 by SpEcIeS
"I must admit that this looks a lot better that the first example"



CopyFiles proc Pattern:DWORD, DestFolder:DWORD
LOCAL tmpbuf[MAX_PATH]:BYTE

; Job for you
; if destination folder exists OK, else create it
; FilesPattern must be db "c:\MyFiles\*.*", 0 rather then db "*.*",0
; change source directory to "c:\MyFiles\"

invoke FindFirstFile,Pattern,addr Win32FindData
mov esi, eax
inc eax
je InvalidHandle
invoke lstrcpy, addr tmpbuf, DestFolder
invoke lstrlen, addr tmpbuf
lea ebx, [eax+offset tmpbuf]
cmp byte ptr [ebx-1], 05Ch
je IsDir
mov byte ptr [ebx], 05Ch
inc ebx
IsDir: mov eax, Win32FindData.dwFileAttributes
and eax, FILE_ATTRIBUTE_DIRECTORY
je Continue
invoke lstrcpy, ebx, addr Win32FindData.cFileName
invoke CopyFile, addr Win32FindData.cFileName, addr tmpbuf, 0
Continue: invoke FindNextFile, esi, addr Win32FindData
test eax, eax
jne IsDir
invoke FindClose, esi
InvalidHandle: ret
CopyFiles endp
Posted on 2002-12-18 11:18:08 by lingo12
Wow, now that is nice work :)
Posted on 2002-12-18 11:29:45 by SpEcIeS
SpEcIeS,

I meant to say thanks in the first place for posting your code for other people to use. The source code forum is a good place for code to be beaten to death and I think with Lingo's help that you have both produced a good fast piece of code.

Regards,

hutch@movsd.com
Posted on 2002-12-27 10:34:13 by hutch--
There is a lot of excellent feedback on this code....:)

This is where I left off after lingo's reply:

CopyFiles PROTO :DWORD,:DWORD
DirExist PROTO :DWORD

data?
Win32FindData WIN32_FIND_DATA<>

CopyFiles proc Pattern:DWORD, DestFolder:DWORD
LOCAL tmpbuf:BYTE

invoke DirExist,DestFolder

invoke FindFirstFile,Pattern,addr Win32FindData
mov esi, eax
inc eax
je InvalidHandle
CheckForFiles:

cmp eax,ERROR_NO_MORE_FILES
je LeaveLoop

invoke lstrcpy,addr tmpbuf,DestFolder
invoke StrLen,addr tmpbuf

dec eax
cmp byte ptr ,05Ch
je BSOK
inc eax
mov byte ptr,05Ch
inc eax
mov byte ptr,0
BSOK:
cmp Win32FindData.dwFileAttributes,FILE_ATTRIBUTE_DIRECTORY
je Continue

invoke lstrcat,addr tmpbuf,addr Win32FindData.cFileName
invoke CopyFile,addr Win32FindData.cFileName, addr tmpbuf,0
Continue:
invoke FindNextFile,esi,addr Win32FindData
invoke GetLastError
jmp CheckForFiles

LeaveLoop:
invoke FindClose,esi
InvalidHandle:
ret
CopyFiles endp

DirExist proc DestFolder:DWORD
;If Directory does not exist then create it
LOCAL CurDir:BYTE

invoke GetCurrentDirectory,MAX_PATH,addr CurDir
invoke SetCurrentDirectory,DestFolder
test eax,eax
jne @F
invoke CreateDirectory,DestFolder,NULL
@@:
invoke SetCurrentDirectory,addr CurDir

ret
DirExist endp

How is this? :)
Posted on 2002-12-27 16:43:19 by SpEcIeS