It is not too rare for me to have to do some action on all files in a folder (and in all subfolders). Usually it's to set or remove the archive attribute. This is what I created:


memmove proc uses ecx esi edi Desty,Source,ln
cld
mov esi, Source
mov edi, Desty
mov ecx, ln

shr ecx, 2
rep movsd

mov ecx, ln
and ecx, 3
rep movsb
ret
memmove endp

EnumerateSubfiles proc uses eax ebx ecx edx RootDir
local strSize,hFind
local DaString[256]:BYTE
local fd:WIN32_FIND_DATA

invoke lstrlen,RootDir
.if !eax
jmp _ret
.endif
.if eax>255
mov eax,255
.endif
mov strSize,eax
inc eax
invoke memmove,addr DaString,RootDir,eax
invoke lstrcat,addr DaString,CTEXT("\*.*")
invoke FindFirstFile,addr DaString,addr fd
mov hFind,eax
.if eax==INVALID_HANDLE_VALUE
jmp _ret
.endif
_morer:

invoke lstrcpy,addr DaString,RootDir
invoke lstrcat,addr DaString,CTEXT("\")
invoke lstrcat,addr DaString,addr fd.cFileName
lea eax,fd.cFileName
mov ax,[eax]
.if ax!=02Eh && ax !=02e2eh
mov eax,fd.dwFileAttributes
.if eax & FILE_ATTRIBUTE_DIRECTORY
invoke EnumerateSubfiles,addr DaString
.else

;----[ Do action with that file ]-------------------------------\

invoke SetFileAttributes,addr DaString,FILE_ATTRIBUTE_NORMAL

;---------------------------------------------------------------/
.endif
.endif

invoke FindNextFile,hFind,addr fd
.if eax
jmp _morer
.endif
invoke FindClose,hFind

_ret: ret
ret
EnumerateSubfiles endp


Usage:
invoke EnumerateSubfiles,CTEXT("D:\folder1")

I created this function for the refill packer for my proggie 'Dreamer' :grin: .
I thought about making it as a macro, that will do this:
ForEachFileIn "D:\folder1", invoke SetFileAttributes,addr DaString,FILE_ATTRIBUTE_NORMAL

but I'll have to study the @strcat for macros and find a way to make unique procs or global labels.
I'll try to do that later
Posted on 2003-08-19 10:51:04 by Ultrano
attrib -a *.* /s :grin:
Posted on 2003-08-20 15:15:00 by Nebob

Usage:
invoke EnumerateSubfiles,CTEXT("D:\folder1")

I created this function for the refill packer for my proggie 'Dreamer' :grin: .
I thought about making it as a macro, that will do this:
ForEachFileIn "D:\folder1", invoke SetFileAttributes,addr DaString,FILE_ATTRIBUTE_NORMAL

but I'll have to study the @strcat for macros and find a way to make unique procs or global labels.
I'll try to do that later


You might want to take a look at "iterators" in HLA (the High Level Assembler) and their implementation in MASM (IIRC, I've got a discussion of iterators in the 16-bit edition of "The Art of Assembly Language Programming"). Iterators and the corresponding "foreach" loop are exactly what you're looking for.

Here's what a "foreach" loop would look like in a typical HLA program that processes all the files in a directory, given a regular expression:



foreach FileInList( "*.*" ) do

stdout.put( "file: ", (type string eax), nl );

endfor;


It's easy enough to write macros in MASM to simulate the FOREACH and ENDFOR statements, assuming you don't need to have nested FOREACH loops (if you do, it's still possible in MASM, just a lot more work).

I've attached a sample HLA application that provides a "FileInList" iterator along with a short main program that demonstrates calls to this iterator (via a "FOREACH" loop). Again, "The Art of Assembly Language Programming" (16-bit edition) on Webster (http://webster.cs.ucr.edu) will tell you how to implement iterators, the foreach loop, and the "yield" statement in MASM.
Cheers,
Randy Hyde






// HLA Demonstration program.
//
// This short program demonstrates two things:
//
// (1) How to call the Windows "FindFirstFile",
// "FindNextFile", and "FindClose" routines
// to process filenames, possibly containing
// wildcard characters.
//
// (2) The use of HLA iterators to process
// iterative objects (e.g., a file name list).
//
// Randall Hyde
// 10/7/99


program FindFirstDemo;
#include( "stdlib.hhf" )
#include( "w.hhf" )

type
FileTime:
record

LowDateTime: dword;
HighDateTime:dword;

endrecord;

Win32FindData:
record

FileAttributes: dword;
CreationTime: FileTime;
LastAccessTime: FileTime;
LastWriteTime: FileTime;
FileSizeHigh: dword;
FileSizeLow: dword;
Reserved0: dword;
dwReserved1: dword;
FileName: char[ 260 ];
AlternateFileName: char[ 14 ];

endrecord;




// External declarations for Windows API calls:

procedure FindFirstFile( var WFD:Win32FindData; FileName:string );
returns( "eax" ); // File Handle.
external( "_FindFirstFileA@8" );

procedure FindNextFile( var WFD:Win32FindData; handle:dword );
returns( "al" ); // Boolean result, true=got a file.
external( "_FindNextFileA@8" );

procedure FindClose( handle:dword );
external( "_FindClose@4" );


// These macros preserve registers that might get tweaked
// by Windows API calls.

#macro pusha2;
push( ebx );
push( ecx );
push( edx );
push( esi );
push( edi );
#endmacro;

#macro popa2;
pop( edi );
pop( esi );
pop( edx );
pop( ecx );
pop( ebx );
#endmacro;


// The following iterator returns a string (in EAX) that corresponds
// to a filename. The parameter passed to this iterator is a filename,
// one that typically contains wildcard characters (i.e., "*" and "?" ).
// This iterator returns a list of filenames that match the, possibly
// ambiguous, filename passed as a parameter. This iterator fails
// when there are no more matching filenames.

iterator FileInList( FileList:string ); @nodisplay;
var
handle: dword;
FileData: Win32FindData;

begin FileInList;

// Find the first matching file (if one exists).
// Save the handle for use by FindNextFile.

pusha2;
FindFirstFile( FileData, FileList );
popa2;
mov( eax, handle );

// If we matched at least one filename, return
// the corresponding string and call the
// FindNextFile routine to match any additional
// filenames.

if( eax <> w.INVALID_HANDLE_VALUE ) then

repeat

// FindFirstFile & FindNextFile return
// zero-terminated strings. Convert these
// to HLA compatible strings and return
// the converted string:

conv.a_cStrToStr( FileData.FileName );

// Return the converted string to the FOREACH
// loop and then free the storage associated
// with the string.

push( eax ); // Save, so we can free string on return
yield(); // Return string to FOREACH loop.
pop( eax ); // Free the storage used by the string.
strfree( eax );

// Get the next filename in the list:

pusha2;
FindNextFile( FileData, handle );
popa2;

until( al = false );

// When we've processed all the filenames in the list,
// call FindClose to free the handle and other resources.

pusha2;
FindClose( handle );
popa2;

endif;

end FileInList;





var
FindData: Win32FindData;

begin FindFirstDemo;

// Simple foreach loop that demonstrates the FileInList iterator
// by printing out all the filenames in the current directory.

stdout.put( "FindFirst Demo:", nl, nl );
foreach FileInList( "*.*" ) do

stdout.put( "file: ", (type string eax), nl );

endfor;

end FindFirstDemo;
Posted on 2003-08-28 10:08:03 by rhyde