News:

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

Copying folders

Started by Ghirai, July 27, 2006, 10:51:02 PM

Previous topic - Next topic

Ghirai

What would be the best way of copying a folder (that contains other folders, files, and so forth)?

I thought about using findfirstfile/findnextfile.

Any suggestions, methods?

Thanks.
MASM32 Project/RadASM mirror - http://ghirai.com/hutch/mmi.html

Ian_B

#1
Deleted.

Ghirai

Thanks a bunch Ian_B for the clean code, i ppreciate it.
MASM32 Project/RadASM mirror - http://ghirai.com/hutch/mmi.html

zooba

Possibly SHFileOperation is able to do this, though the documentation is not clear. There are some flags which appear to disable recursive behaviour, so presumably it is on by default.

SHFileOperation is the function called when the user drag-drops/deletes files and folders, so there is some (optional but standard) GUI as part of the function.

Cheers,

Zooba :U

Ian_B

SO what are you saying? This is a useless procedure because I didn't also add a little animated progress box?  :dazzled:

Glad to be of help, Ghirai. It's nice that someone appreciates the art of an efficient recursive algorithm. I have removed the code so that library-boy can't steal it for one of his own do-everything code packages.

MichaelW

SHFileOperation seems to work, this copied the entire hla directory OK.

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .data
        shop    SHFILEOPSTRUCT <>
        from    db "c:\hla",0,0
        to      db "d:\hla",0,0
        fAbort  dd 0
    .code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    mov shop.hwnd, 0
    mov shop.wFunc, FO_COPY
    mov shop.pFrom, offset from
    mov shop.pTo, offset to
    mov shop.fFlags, FOF_SILENT
    mov shop.fAnyOperationsAborted, offset fAbort

    invoke SHFileOperation, ADDR shop
    print ustr$(eax),13,10
    print ustr$(fAbort),13,10
    inkey "Press any key to exit..."
    exit
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start   

typedef struct _SHFILEOPSTRUCT {
    HWND hwnd;
    UINT wFunc;
    LPCTSTR pFrom;
    LPCTSTR pTo;
    FILEOP_FLAGS fFlags;
    BOOL fAnyOperationsAborted;
    LPVOID hNameMappings;
    LPCTSTR lpszProgressTitle;
} SHFILEOPSTRUCT, *LPSHFILEOPSTRUCT;


I expect SHFileOperation will be much slower, but I don't have time to do a benchmark right now.



eschew obfuscation

Ghirai

MASM32 Project/RadASM mirror - http://ghirai.com/hutch/mmi.html

Ghirai

Ian_B, i'm having a few probs with your code.

You said that:

; for SourcePathSpec:
; find the end of the path and ensure there's a final terminating "\" character
; the offset to the NULL-termination after this "\" should now be in EAX
; do similar with TargetPathSpec and get offset to final NULL-termination in ECX

I suppose you meant position relative to the offset.

Say the destination is "c:\aaa\",0
This means ecx=8 (including 0)

And the src is "d:\*",0
This means eax=4? Or 5, including the 0?


Thanks in advance for the clarification.


Regards,
Ghirai.
MASM32 Project/RadASM mirror - http://ghirai.com/hutch/mmi.html

Ian_B

Quote from: Ghirai on July 28, 2006, 02:38:20 PM
; for SourcePathSpec:
; find the end of the path and ensure there's a final terminating "\" character
; the offset to the NULL-termination after this "\" should now be in EAX
; do similar with TargetPathSpec and get offset to final NULL-termination in ECX

I suppose you meant position relative to the offset.

Say the destination is "c:\aaa\",0
This means ecx=8 (including 0)

And the src is "d:\*",0
This means eax=4? Or 5, including the 0?

No. As implied by the function parameters, the offsets are at each recursion the length of the path, ie. the offset from the start of the buffer to the NULL-termination character (NOT including the * wildcard you add afterwards). This is because you want to add new path elements and filenames immediately after the last "\" char from that offset.

So for "c:\aaa\" the offset to the NULL-termination is 7, the length of the path, as the first char "c" is at offset 0 in the buffer. For "d:\" it's 3.

The simplest way to get this is to copy the path byte-by-byte from the location where you acquire it (probably a BROWSEINFO structure) to the buffer. Use a [buffer start reg + buffer offset reg] form of indexing and when you have copied the NULL-termination and exited the loop then your buffer offset reg is correct. Save for later or just use a different reg to do the other path/buffer. Obvously you can set the buffer start registers up earlier at this point in EDI/ESI and then they are already set for the proc. If you don't want to reserve buffer space in the app DATA? section, you can also allocate memory and store the handles (for LocalAlloc these are the same as the start address) all the way through in EDI/ESI without bothering to save them, just use the registers as parameters to release the memory after.

Ian_B

Ghirai

Ok, i have this test code:


.data

szSRC db "c:\RadASM\*",0
szDest db "c:\aaa\",0


.data?

SourcePathSpec  db MAX_PATH DUP (?)
TargetPathSpec  db MAX_PATH DUP (?)

.code

invoke lstrcat,addr SourcePathSpec,addr szSRC
mov esi,eax

invoke lstrcat,addr TargetPathSpec,addr szDest
mov edi,eax

mov eax,10
mov ecx,7

invoke GetAllFiles,eax,ecx


It creates the first dir in <aaa>, but then crashes at:

FoundSubFolder:
        mov     WORD PTR [edi+edx], "\"


Any ideas as to what i'm doing wrong?
MASM32 Project/RadASM mirror - http://ghirai.com/hutch/mmi.html

Ian_B

Check my original source and notes for where and why to push/pop EDI/ESI/EBX. Set the EDI/ESI registers using LEA as I coded for you first. I don't know what the lstrcat function does but assigning the output to ESI/EDI seems likely to be the error. You should be invoking it as "lstrcat, esi, OFFSET szSRC" as you should already have the pointer in ESI at that stage. Similarly for "lstrcat, edi, OFFSET szDest".

I rest my case about the problems of using prepackaged library functions that you haven't coded yourself and therefore can't trace through to find the errors...  ::) 

Ian_B

Ghirai

Changed as suggested, crash at the same address.

And lstrcat returns pointer to SourcePathSpec (TargetPathSpec).

Thanks for your quick replies :)
MASM32 Project/RadASM mirror - http://ghirai.com/hutch/mmi.html

Ian_B

You do realise that you are copying an entire subtree into an existing folder? So the folder you are copying the tree into (c:\aaa\) must already exist before you attempt to call this and create subfolders under a non-existent root folder...

I am building a version of my own to debug and see if I've made a logic error.

Ghirai

Yes, i am aware of that.

I created the destination folder.
MASM32 Project/RadASM mirror - http://ghirai.com/hutch/mmi.html

Ian_B

#14
A small bug - replace the offending section with this (used wrong offset after copy loop, ie. remove two ADD lines):

FoundSubFolder:
        mov     WORD PTR [edi+edx-1], "\"       ; replace NULL-termination with path delimiter
        mov     DWORD PTR [esi+ecx-1], "*\"     ; terminate with wildcard for new search
        xor     ebx, ebx                        ; EBX = NULL
        push    edx                             ; set params now for recursion call
        push    ecx


Heh, now even smaller and faster.  :wink

Ian_B