Здраствуйте, я тут собрался сделать маленькую процедурку для поиска файлов по всему компьютеру и в голову пришла мысль о организации рекурсии. Проблема в том, что самая большая рекурсионная процедура которую я делал: Код (Text): proc Factorial r_fact push bp mov bp, sp mov cx, [bp+4] mov ax, cx mul [r_fact] mov [r_fact], ax dec cx jz end_p push cx call Factorial end_p: mov sp, bp pop bp ret end Передо мной встало несколько вопросов: 1. Стек по сути дела не потходит, значит сколько нам надо выделить памяти для процедуры. 2. Как основать структуру для поиска: 3. В чем я не прав? Моя фича заходит только в первый найденый каталог. Код (Text): include '..\..\include\win32ax.inc' include '..\..\include\encoding\win1251.inc' .data path db 'C:\*.*',0 ext db '*.*',0 hmem dd ? buffer rb 260 string_buffer rb 260 path_buffer rb 260 path_default rb 260 fdata rb 100*(sizeof.WIN32_FIND_DATA) .code start: invoke GetModuleHandle,0 invoke DialogBoxParam,eax,IDD_FIND,HWND_DESKTOP,DialogProc,0 close: invoke ExitProcess,0 proc DialogProc hwnddlg,msg,wparam,lparam push ebx esi edi cmp [msg],WM_INITDIALOG je .wminitdialog cmp [msg],WM_COMMAND je .wmcommand cmp [msg],WM_CLOSE je .wmclose xor eax,eax jmp .finish .wminitdialog: jmp .processed .wmcommand: movsx eax,word[wparam] cmp eax,IDB_CLOSE je .wmclose cmp eax,IDB_FIND je .find jmp .processed .find: invoke GetDlgItem,[hwnddlg],IDB_LIST xchg eax, ebx invoke SendMessage,ebx,LB_RESETCONTENT,0,0 stdcall FindFiles,ebx,path,FLAG_FIND_DIRECTORIES jmp .processed .wmclose: invoke EndDialog,[hwnddlg],0 .processed: mov eax,1 .finish: pop edi esi ebx ret endp proc AssignArray array, mem, size cld mov esi, [mem] mov edi, [array] mov ecx, [size] rep movsb ret endp ; size = 20 ; index = 2 ; mem = 4 ; result = 44 proc GetBaseItem mem, size, index ; size*index+mem=result mov eax, dword[index] imul eax, dword[size] add eax, dword[mem] ret endp proc ExtractFilePath buffer, path push eax push ecx push esi push edi pushf stdcall ScanDecimalStr, [path] local extract_of_str: cld mov esi, [path] mov edi, [buffer] local extract_path: lodsb cmp al, '\' je dec_str cmp al, '/' je dec_str cmp ecx, 0 je end_of_str stosb jmp extract_path local dec_str: stosb sub ecx, 1 jmp extract_path local end_of_str: mov al, 0 stosb popf pop edi pop esi pop ecx pop eax ret endp proc ScanDecimalStr buffer push eax push esi pushf cld mov esi, [buffer] xor ecx, ecx local .str_find_decimal: lodsb cmp al, '\' je .ok_separator cmp al, '/' je .ok_separator cmp al, 0 je .end_find jmp .str_find_decimal local .ok_separator: add ecx, 1 jmp .str_find_decimal local .end_find: popf pop esi pop eax ret endp proc SetDownDir buffer, path, ext invoke wsprintf,[buffer],format.path, [path], [ext] ret format.path db '%s\%s',0 endp proc IsBackDir buffer invoke lstrcmpi,back.catalog1,[buffer] je catalog.true invoke lstrcmpi,back.catalog2,[buffer] je catalog.true xor eax, eax ret catalog.true: xor eax, eax inc eax ret back.catalog1 db '..',0 back.catalog2 db '.', 0 endp ;struct WIN32_FIND_DATA bytes ; dwFileAttributes dd ? 4 ; ftCreationTime FILETIME 8 ; ftLastAccessTime FILETIME 8 ; ftLastWriteTime FILETIME 8 ; nFileSizeHigh dd ? 4 ; nFileSizeLow dd ? 4 ; dwReserved0 dd ? 4 ; dwReserved1 dd ? 4 44 ; cFileName TCHAR MAX_PATH dup (?) ; cAlternateFileName TCHAR 14 dup (?) ;ends proc FindFiles hlist, buffer, param local hfind :dd 0 local offset :dd 0 local nesting :dd 0 find.init: stdcall ExtractFilePath,path_default,[buffer] stdcall GetBaseItem,fdata,sizeof.WIN32_FIND_DATA,[param] mov [offset], eax mov eax, [param] mov [nesting], eax find.first: mov eax, dword[fdata] add eax, [offset] invoke FindFirstFile,[buffer],eax cmp eax, INVALID_HANDLE_VALUE jz find.error mov [hfind], eax find.next: mov ebx, dword[fdata] add ebx, [offset] add ebx, 44 stdcall IsBackDir, ebx test eax, eax jne find.data sub ebx, 44 cmp dword[ebx], FILE_ATTRIBUTE_DIRECTORY je find.dir find.file: mov eax, dword[fdata] add eax, [offset] add eax, 44 invoke SendMessage,[hlist],LB_ADDSTRING,0,eax jmp find.data find.dir: mov eax, dword[fdata] add eax, [offset] add eax, 44 inc [nesting] invoke lstrcat,path_default, eax stdcall SetDownDir,path_buffer,path_default,ext invoke MessageBox,0,path_buffer,0,0 invoke SendMessage,[hlist],LB_ADDSTRING,0,string_buffer stdcall FindFiles,[hlist],path_buffer, [nesting] jmp find.data find.data: mov eax, dword[fdata] add eax, [offset] invoke FindNextFile,[hfind], eax cmp eax,0 je find.close jmp find.next find.close: invoke FindClose,[hfind] ret find.error: invoke FindClose,[hfind] xor eax, eax dec eax ret endp IDD_FIND = WM_USER+0 IDB_FIND = WM_USER+1 IDB_CLOSE = WM_USER+2 IDB_LIST = WM_USER+3 FLAG_FIND_ERROR = -1 ; Возрат ошибки FLAG_FIND_DIRECTORIES = 0 ; Искать в каталогах FLAG_FIND_NOT_DIRECTORIES = -2 ; Не искать в папках .end start section '.rsrc' resource data readable directory RT_DIALOG,dialogs resource dialogs,\ IDD_FIND,LANG_ENGLISH+SUBLANG_DEFAULT,find_dialog dialog find_dialog,'Рекурсивный поиск фалов',60,60,254,172,WS_CAPTION+WS_POPUP+WS_SYSMENU+DS_MODALFRAME dialogitem 'LISTBOX',0,IDB_LIST,4,4,200,170,WS_VISIBLE+WS_CHILD+WS_BORDER dialogitem 'BUTTON','Искать',IDB_FIND,206,6,42,14,WS_VISIBLE+WS_TABSTOP+BS_DEFPUSHBUTTON dialogitem 'BUTTON','Выход',IDB_CLOSE,206,22,42,14,WS_VISIBLE+WS_TABSTOP+BS_PUSHBUTTON enddialog Жду вашей помощи. Прошу не ругать, FASM'ом занимаюсь меньше года, а программированием в целом меньше двух.
Нафиг темы дублировать ? Тебе сюда: http://www.wasm.ru/forum/viewtopic.php?id=25322&p=2 EnumerateFiles()
Clerk Знаешь спасибо за подсказку, но мне нужен хороший рекурсионный пример и кстати ссылка твоя не работает.
Чтобы начать с рекурсии нужно начать с рекурcии Вот код по поиску файла пробегал: Код (Text): SearchForFile PROC StartPath:DWORD,FileToFind:DWORD LOCAL WFD:WIN32_FIND_DATA ; used for file/folder search LOCAL fPath[260]:BYTE ; used to store StartPath locally LOCAL fPath2[260]:BYTE ; we add sub-folders names onto this to form full paths LOCAL hFind:DWORD ; find handle ; Below is just some little data's that we need in order for function to work jmp @F WildCard db "\*",0 ; search ALL files CRLF db 13,10,0 ; tell me you don't know what this is foundat db "Found: ",0 ; tell the user we found a file that matches @@: lea edi,fPath push edi ; save EDI in stack mov esi,StartPath ; we are copying supplied StartPath to our buffer mov ecx,256 ; all 256 bytes rep movsb ; copy path pop edi ; put the path back in EDI xor al,al ; clear AL @GetToChar ; Find the first zero mov al,'\' ; now equals Drive:\Path\* stosb ; e.g.: C:\Windows\* mov al,'*' stosb @ClearFN ; clears the cFileName field in Win32_Find_Data invoke FindFirstFile,addr fPath,addr WFD ; find first file push eax ; mov hFind,eax ; save FindHandle pop ebx ; put handle in EBX .while ebx > 0 ; while a file is found.. lea esi,WFD.cFileName lodsw ; get first two chars .if AX!=02E2Eh && AX!=0002Eh ; '..' and '.' lea edi,WFD mov eax,[edi] ; file attributes .if ax & FILE_ATTRIBUTE_DIRECTORY ; is it a directory? sub esi,2 ; undo the lodsw lea edi,fPath2 ; load up the secondary path in EDI push edi ; save it on the stack... xor al,al ; clear secondary path mov ecx,260 ; .. rep stosb mov edi,[esp] ; restore EDI lea eax,fPath ; first path invoke lstrcpy,edi,eax ; copy first to second mov al,'*' ; get to the end.... @GetToChar mov byte ptr [edi],00h ; delete the wildcard invoke lstrcat,edi,esi ; tack on the new directory name pop edi ; restore EDI from stack pushad ; must save ALL regs or errors will ocur :) invoke SearchForFile,edi,FileToFind ; call function again popad ; restore all regs .else sub esi,2 ; undo the lodsw invoke lstrcmpi,FileToFind,esi ; case insensitive compare or eax,eax ; are they equal? jz found_file ; if eax=0 they are equal .endif .endif @ClearFN ; Clear the cFileName field again invoke FindNextFile,hFind,addr WFD mov ebx,eax .endw __cls_fnd: invoke FindClose,hFind ; close it up ret found_file: ; Если найден файл ! lea edi,fPath2 invoke lstrcpy,edi,addr fPath mov al,'*' scasb jnz $-1 dec edi mov byte ptr [edi],00h lea edi,WFD.cFileName invoke lstrcat,addr fPath2,edi ; Выводим результат поиска ; invoke StdOut,addr foundat ; invoke StdOut,addr fPath2 ; Имя файла invoke MessageBox,0,addr fPath2,addr fPath2 ,0 ; Выводим сообщение ; invoke StdOut,addr CRLF ; invoke CreateProcess, ADDR fPath2, NULL, NULL, NULL, FALSE,NORMAL_PRIORITY_CLASS, NULL, NULL,ADDR sInfo, ADDR pInfo ; jmp __cls_fnd jmp leave_prog SearchForFile ENDP
asmlamo Пример и вправду хороший, благодарю. Моя цель в том, что бы осмыслить код, а не заниматься COPY\PASTE, помогите сказав в чем мои ошибки.
Everhest Вот тупо на винапи старый код: Код (Text): SRC32FILES struct nFile dd ? nDir dd ? SRC32FILES ends FIND32 struct SignL dd ? ;Сигнатура 'xSea' SignH dd ? ;Сигнатура 'rch_' hMem dd ? ;хэндл памяти nFile dd ? ;число найденных файлов nDir dd ? ;число найденных папок pHandle dd ? ;номер текущего элемента таблицы дескрипторов *4 Handles dd MAX_PATH dup (0) ;таблица дескрипторов FindFirstFile wfd WIN32_FIND_DATA <> ;Структура принимающая информацию о найденном файле lBuf db MAX_PATH dup (0) ;буфер строки с путём + '\*' FIND32 ends .code ;------------------------------------------------------------------------------- StartSearch proc uses edi esi lpDir:dword,srcWfd:dword Local Vari:dword,srcfiles:SRC32FILES ;Процедура инициализации параметров поиска ;Выделяем память invoke GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT,sizeof FIND32 ;выделяем блок памяти mov Vari,eax ;hMem invoke GlobalLock,eax ;Определяем адрес его mov edi,eax ;указатель на FIND32 assume edi:ptr FIND32 mov eax,Vari mov [edi].hMem,eax ;хэндл памяти mov [edi].SignL,'xSea' ;младший DWORD сигнатуры структуры mov [edi].SignH,'rch_' ;старший DWORD сигнатуры структуры xor eax,eax mov [edi].pHandle,eax ;pHandle указывает на первый элемент Handles mov [edi].nFile,eax mov [edi].nDir,eax lea esi,[edi].lBuf ;esi-адрес строки в буфере invoke lstrcpy,esi,lpDir ;копируем путь в буфер invoke GetFileAttributes,esi ;<ERROR_PATH_NOT_FOUND> cmp eax,-1 jz initerr_ invoke lstrlen,esi ;определяем длину пути add eax,esi ;...0 cmp byte ptr [eax-1],'\' .if Zero? dec eax .endif mov dword ptr [eax],'*\' ;добавляем его lea eax,[edi].wfd invoke FindFirstFile,esi,eax ;начинаем поиск mov Vari,eax ;хэндл поиска cmp eax,INVALID_HANDLE_VALUE jz initerr_ lea ecx,[edi].Handles ;адрес текущего элемента таблицы хэндлов mov [ecx],eax ;сохраняем хэндл поиска add [edi].pHandle,4 ;указатель на следующий элемент таблица cmp byte ptr [edi].wfd.cFileName,'.' .if !Zero? mov eax,[edi].wfd.dwFileAttributes test eax,16 .if Zero? inc [edi].nFile .else inc [edi].nDir .endif .else invoke Search,edi,addr srcfiles test eax,eax jz pexit_ .endif findok_: mov edx,srcWfd ;указатель на адрес wfd lea eax,[edi].wfd ;адрес wfd mov [edx],eax ;сохраняем pWfd mov eax,edi ;адрес структуры возвращаем в качестве хэндла поиска jmp pexit_ initerr_: mov edi,[edi].hMem invoke GlobalUnlock,edi invoke GlobalFree,edi xor eax,eax pexit_: ret StartSearch endp ;------------------------------------------------------------------------------- FindSlash proc lea eax,[edi].lBuf invoke lstrlen,eax sub eax,3 lea edx,[edi].lBuf add eax,edx slashlp: dec eax cmp byte ptr [eax],'\' jz slashok cmp byte ptr [eax],'\' jz slashok cmp eax,edx ja slashlp xor eax,eax slashok: test eax,eax .if !Zero? mov dword ptr [eax],'*\' ;...\* .endif ret FindSlash endp ;------------------------------------------------------------------------------- Search proc uses edi esi pMem:dword,pInfo:dword Local Vari:dword mov edi,pMem assume edi:ptr FIND32 mov eax,[edi].SignL ;проверяем сигнатуру cmp eax,'xSea' jnz handleerr_ mov eax,[edi].SignH cmp eax,'rch_' jnz handleerr_ lea esi,[edi].lBuf ;адрес строки в буфере next1_: mov eax,[edi].pHandle test eax,eax jz closesrc_ mov al,byte ptr [edi].wfd.cFileName cmp al,'.' ;если вызывается из StartSearch jz findfile_ mov eax,[edi].wfd.dwFileAttributes test eax,16 ;если не ноль то файл - каталог jz findfile_ invoke lstrlen,esi add eax,esi ;Path\*0 dec eax ;Path\* lea edx,[edi].wfd.cFileName invoke lstrcpy,eax,edx ;дописываем имя каталога,Path\FileName0 invoke lstrlen,esi ;длина строки в буфере add eax,esi ;...0 mov dword ptr [eax],'*\' ;Path\FileName0\* lea eax,[edi].wfd invoke FindFirstFile,esi,eax cmp eax,INVALID_HANDLE_VALUE jz finddirerr_ mov edx,[edi].pHandle lea ecx,[edi].Handles mov [edx+ecx],eax add [edi].pHandle,4 jmp nextfile_ finddirerr_: invoke FindSlash findfile_: lea edx,[edi].wfd ;адрес Wfd lea ecx,[edi].Handles - 4 mov eax,[edi].pHandle mov eax,[eax+ecx] invoke FindNextFile,eax,edx test eax,eax jnz nextfile_ invoke GetLastError cmp eax,ERROR_NO_MORE_FILES ;в директории больше файлов не найдено jnz findfile_ mov edx,[edi].pHandle ;указатель на хэндл поиска lea ecx,[edi].Handles - 4 mov eax,[edx+ecx] invoke FindClose,eax sub [edi].pHandle,4 jz closesrc_ invoke FindSlash ;в каталоге больше нет файлов jmp findfile_ nextfile_: mov al,byte ptr [edi].wfd.cFileName cmp al,'.' jz findfile_ mov eax,[edi].wfd.dwFileAttributes test eax,16 .if Zero? inc [edi].nFile .else inc [edi].nDir .endif mov edx,pInfo mov eax,[edi].nFile mov dword ptr [edx],eax mov eax,[edi].nDir mov [edx+4],eax mov eax,edi ;адрес структуры возвращаем в качестве хэндла поиска jmp pexit_ handleerr_: invoke SetLastError,ERROR_INVALID_HANDLE mov eax,INVALID_HANDLE_VALUE jmp pexit_ closesrc_: mov edi,[edi].hMem invoke GlobalUnlock,edi ;освобождаем память invoke GlobalFree,edi invoke SetLastError,ERROR_NO_MORE_FILES xor eax,eax pexit_: ret Search endp ;------------------------------------------------------------------------------- StopSearch proc uses edi esi pMem:dword mov edi,pMem assume edi:ptr FIND32 mov eax,[edi].SignL ;проверяем сигнатуру cmp eax,'xSea' jnz memerr_ mov eax,[edi].SignH cmp eax,'rch_' jnz memerr_ mov esi,[edi].pHandle test esi,esi jz freemem_ push edi lea edi,[edi].Handles - 4 stoplp_: mov eax,dword ptr [edi+esi] invoke FindClose,eax sub esi,4 jnc stoplp_ pop edi mov edi,[edi].hMem invoke GlobalUnlock,edi ;освобождаем память invoke GlobalFree,edi mov eax,TRUE jmp pexit_ freemem_: invoke SetLastError,ERROR_SUCCESS mov eax,TRUE jmp pexit_ memerr_: invoke SetLastError,ERROR_INVALID_HANDLE mov eax,INVALID_HANDLE_VALUE pexit_: ret StopSearch endp end Код (Text): StartSearch proto :dword,:dword ;ptr lpPath,ptr dwWfd ;Начинает перечисление файлов ;1-й параметр: указатель на путь поиска например C:\Windows или D:\ ;2-й параметр: указатель на двойное слово принимающее адрес структуры SRC32 через которую передаётся информация о найденном файле ;Возвращается в случае успеха хэндл поиска,иначе ноль Search proto :dword,:dword ;hSrc,ptr SRC32FILES ;вызывается циклически для перечисления файлов. ;1-й параметр: хэндл поиска,возвращённый StartSearch ;2-й параметр: указатель на структуру SRC32FILES,принимающую общее число найденых файлов и папок ;Возвращается в случае успеха указатель на двойное слово принимающее адрес структуры SRC32 через которую передаётся информация о найденном файле, ;если ноль то поиск закончен StopSearch proto :dword ;hSrc ;Принудительно завершает перечисление. ;1-й параметр: хэндл поиска SRC32FILES struct nFiles dd ? ;Число файлов,увеличивается на 1 с каждым найденным файлом nDir dd ? ;Число папок,увеличивается на 1 с каждой найденной папкой SRC32FILES ends SRC32 struct wfd WIN32_FIND_DATA <> ;Структура принимающая информацию о найденном файле lBuf db MAX_PATH dup (0) ;буфер строки с путём + '\*' SRC32 ends Код (Text): .data WinDir db MAX_PATH dup (0) SrcFiles SRC32FILES <> dwWfd dd ? hSrc dd ? ;..................................................................... lpExt db ".exe",".dll",".ocx",".avi",".bmp",".jpg",".gif",".ico",".doc",".hlp",".sys",0,0,0,0 ;..................................................................... nExe dd 0 nDll dd 0 nOcx dd 0 nAvi dd 0 nBmp dd 0 nJpg dd 0 nGif dd 0 nIco dd 0 nDoc dd 0 nHlp dd 0 nSys dd 0 nSystem dd 0 nHidden dd 0 nRead dd 0 ;..................................................................... lpMsgCapt db "Íàéäåíî_",0 lpFiles db "Ôàéëîâ ",0 lpDir db "Ïàïîê ",0 lpSys db "Ñèñòåìíûõ ",0 lpHid db "Ñêðûòûõ ",0 lpRead db "Äëÿ ÷òåíèÿ ",0 .code NumToMsg proc pMsg_:dword,sizeMsg:dword,Value:dword invoke lstrlen,esi add esi,eax mov byte ptr [esi],13 inc esi invoke lstrcpy,esi,pMsg_ add esi,sizeMsg dec esi mov dword ptr [esi],0 mov dword ptr [esi+4],0 invoke udw2str,Value,esi ret NumToMsg endp ;------------------------------------------------------------------------------- start: invoke GetWindowsDirectory,addr WinDir,MAX_PATH invoke StartSearch,addr WinDir,addr dwWfd test eax,eax jz exit_ mov hSrc,eax loopsrc_: mov edx,dwWfd assume edx:ptr SRC32 mov eax,[edx].wfd.dwFileAttributes test eax,FILE_ATTRIBUTE_HIDDEN .if !Zero? inc nHidden .endif test eax,FILE_ATTRIBUTE_SYSTEM .if !Zero? inc nSystem .endif test eax,FILE_ATTRIBUTE_READONLY .if !Zero? inc nRead .endif test eax,FILE_ATTRIBUTE_DIRECTORY jnz findnext_ ;êàòàëîã lea eax,[edx].wfd.cFileName push eax invoke lstrlen,eax pop edx add edx,eax ;...0 cmp eax,4 jc findnext_ mov eax,dword ptr [edx-4] or eax,00100000001000000010000000000000b cmp eax,'exe.' jnz @F inc nExe jmp findnext_ @@: cmp eax,'lld.' jnz @F inc nDll jmp findnext_ @@: cmp eax,'xco.' jnz @F inc nOcx jmp findnext_ @@: cmp eax,'iva.' jnz @F inc nAvi jmp findnext_ @@: cmp eax,'pmb.' jnz @F inc nBmp jmp findnext_ @@: cmp eax,'gpj.' jnz @F inc nJpg jmp findnext_ @@: cmp eax,'fig.' jnz @F inc nGif jmp findnext_ @@: cmp eax,'oci.' jnz @F inc nIco jmp findnext_ @@: cmp eax,'cod.' jnz @F inc nDoc jmp findnext_ @@: cmp eax,'plh.' jnz @F inc nHlp jmp findnext_ @@: cmp eax,'sys.' jnz findnext_ inc nSys findnext_: invoke Search,hSrc,addr SrcFiles test eax,eax jnz loopsrc_ lea esi,WinDir lea edi,lpExt enumlp_: invoke lstrlen,esi add esi,eax mov byte ptr [esi],13 inc esi mov eax,[edi] test eax,eax jz endenum_ mov dword ptr [esi],eax mov dword ptr [esi+4],' ' add esi,8 mov dword ptr [esi],0 mov dword ptr [esi+4],0 mov dword ptr [esi+8],0 mov eax,dword ptr [edi + sizeof lpExt] add edi,4 invoke udw2str,eax,esi jmp enumlp_ endenum_: invoke lstrcpy,esi,addr lpFiles add esi,sizeof lpFiles - 1 mov dword ptr [esi],0 mov dword ptr [esi+4],0 lea eax,SrcFiles mov eax,[eax] invoke udw2str,eax,esi lea eax,SrcFiles mov eax,[eax+4] invoke NumToMsg,addr lpDir,sizeof lpDir,eax invoke NumToMsg,addr lpSys,sizeof lpSys,nSystem invoke NumToMsg,addr lpHid,sizeof lpHid,nHidden invoke NumToMsg,addr lpRead,sizeof lpRead,nRead invoke MessageBox,0,addr WinDir,addr lpMsgCapt,MB_OK invoke StopSearch,hSrc exit_: invoke ExitProcess,0 end start
Вот из пакета на нативе, рекурсия: Код (Text): EnumerateFileInDirectoryW proc uses ebx DirectoryName:PUNICODE_STRING, DirectoryHandle:HANDLE, EnumerateCallback:PVOID, EnumerateParameter:DWORD Local FileHandle:HANDLE Local ObjAttr:OBJECT_ATTRIBUTES Local IoStatusBlock:IO_STATUS_BLOCK Local Buffer:PVOID, BufferSize:ULONG Local RestartScan:BOOLEAN _setseh_ xor eax,eax mov ebx,1000h mov edx,DirectoryName mov ecx,DirectoryHandle mov ObjAttr.uLength,SizeOf OBJECT_ATTRIBUTES mov ObjAttr.hRootDirectory,eax mov ObjAttr.pSecurityDescriptor,eax mov ObjAttr.pSecurityQualityOfService,eax mov ObjAttr.pObjectName,eax mov ObjAttr.uAttributes,eax mov RestartScan,ebx ;TRUE .if Edx mov ObjAttr.pObjectName,edx .endif .if Ecx mov ObjAttr.hRootDirectory,ecx .endif invoke ZwOpenFile, addr FileHandle, FILE_LIST_DIRECTORY or SYNCHRONIZE, addr ObjAttr, addr IoStatusBlock, FILE_SHARE_READ or FILE_SHARE_WRITE, FILE_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT or FILE_OPEN_FOR_BACKUP_INTENT test eax,eax jnz exit_ mov Buffer,eax mov BufferSize,ebx invoke ZwAllocateVirtualMemory, NtCurrentProcess, addr Buffer, NULL, addr BufferSize, MEM_COMMIT, PAGE_READWRITE test eax,eax jnz close_ query_loop_: mov ebx,Buffer assume ebx:PFILE_DIRECTORY_INFORMATION invoke ZwQueryDirectoryFile, FileHandle, NULL, NULL, NULL, addr IoStatusBlock, Buffer, BufferSize, FileDirectoryInformation, FALSE, NULL, RestartScan test eax,eax mov RestartScan,eax jz enum_loop_ cmp eax,STATUS_NO_MORE_FILES jne return_ xor eax,eax jmp return_ enum_loop_: _subsetseh_ push ebx ;Сохраняем push EnumerateParameter push ebx ;PFILE_DIRECTORY_INFORMATION push FileHandle Call EnumerateCallback pop ebx _subendseh_ test eax,eax mov edx,[ebx].NextEntryOffset jnz return_ test edx,edx jz query_loop_ add ebx,edx jmp enum_loop_ return_: push eax invoke ZwFreeVirtualMemory, NtCurrentProcess, addr Buffer, addr BufferSize, MEM_RELEASE pop eax close_: push eax invoke ZwClose,FileHandle pop eax exit_: _endseh_ ret err_param_1_: mov eax,STATUS_INVALID_PARAMETER_1 jmp exit_ EnumerateFileInDirectoryW endp Код (Text): EnumerateFileInDirectory proc DirectoryName:PSTR, DirectoryHandle:HANDLE, EnumerateCallback:PVOID, EnumerateParameter:DWORD Local UnicodeFileName:UNICODE_STRING _setseh_ invoke RtlCreateUnicodeStringFromAsciiz, addr UnicodeFileName, DirectoryName test eax,eax jz err_param_1_ invoke RtlDosPathNameToNtPathName_U, UnicodeFileName.Buffer, addr UnicodeFileName, NULL, NULL test eax,eax jz err_param_1_ invoke EnumerateFileInDirectoryW, addr UnicodeFileName, DirectoryHandle, EnumerateCallback, EnumerateParameter push eax invoke RtlFreeUnicodeString, addr UnicodeFileName pop eax exit_: _endseh_ ret err_param_1_: mov eax,STATUS_INVALID_PARAMETER_1 jmp exit_ EnumerateFileInDirectory endp Код (Text): ENUMERATE_FS_DATA struct CallbackRoutine PVOID ? CallbackPatameter DWORD ? ENUMERATE_FS_DATA ends PENUMERATE_FS_DATA typedef ptr ENUMERATE_FS_DATA .code ;Рекурсивный вызов EnumerateFilesCallback proc uses ebx DirectoryHandle:HANDLE, FileInformation:PFILE_DIRECTORY_INFORMATION, EnumerateData:PENUMERATE_FS_DATA Local DirectoryName:UNICODE_STRING xor eax,eax mov ebx,FileInformation assume ebx:PFILE_DIRECTORY_INFORMATION cmp word ptr [ebx].FileName,'.' je exit_ mov edx,EnumerateData assume edx:PENUMERATE_FS_DATA push [edx].CallbackPatameter push ebx push DirectoryHandle call [edx].CallbackRoutine test eax,eax jnz exit_ test [ebx].FileAttributes,FILE_ATTRIBUTE_DIRECTORY jz exit_ mov edx,[ebx].FileNameLength lea eax,[ebx].FileName mov DirectoryName.Buffer,eax mov DirectoryName._Length,dx mov DirectoryName.MaximumLength,dx invoke EnumerateFileInDirectoryW, addr DirectoryName, DirectoryHandle, addr EnumerateFilesCallback, EnumerateData exit_: ret EnumerateFilesCallback endp EnumerateFiles proc DirectoryName:PSTR, DirectoryHandle:HANDLE, EnumerateCallback:PVOID, EnumerateParameter:DWORD Local EnumerateData:ENUMERATE_FS_DATA mov eax,EnumerateCallback mov edx,EnumerateParameter mov EnumerateData.CallbackRoutine,eax mov EnumerateData.CallbackPatameter,edx invoke EnumerateFileInDirectory, DirectoryName, DirectoryHandle, addr EnumerateFilesCallback, addr EnumerateData ret EnumerateFiles endp EnumerateFilesW proc DirectoryName:PUNICODE_STRING, DirectoryHandle:HANDLE, EnumerateCallback:PVOID, EnumerateParameter:DWORD Local EnumerateData:ENUMERATE_FS_DATA mov eax,EnumerateCallback mov edx,EnumerateParameter mov EnumerateData.CallbackRoutine,eax mov EnumerateData.CallbackPatameter,edx invoke EnumerateFileInDirectoryW, DirectoryName, DirectoryHandle, addr EnumerateFilesCallback, addr EnumerateData ret EnumerateFilesW endp Код (Text): EnumerateFileInDirectoryW( IN PUNICODE_STRING DirectoryName, ;"\??\c:\windows\system32" IN HANDLE DirectoryHandle OPTIONAL, IN PVOID EnumerateCallback, IN DWORD EnumerateParameter):NTSTATUS EnumerateCallback proto DirectoryHandle:HANDLE, FileInformation:PFILE_DIRECTORY_INFORMATION, EnumerateParameter:DWORD EnumerateFileInDirectory( IN PSTR DirectoryName, ;"c:\windows\system32" IN HANDLE DirectoryHandle OPTIONAL, IN PVOID EnumerateCallback, IN DWORD EnumerateParameter):NTSTATUS EnumerateCallback proto DirectoryHandle:HANDLE, FileInformation:PFILE_DIRECTORY_INFORMATION, EnumerateParameter:DWORD EnumerateFiles( IN PSTR DirectoryName, ;"c:\windows\system32" IN HANDLE DirectoryHandle OPTIONAL, IN PVOID EnumerateCallback, IN DWORD EnumerateParameter):NTSTATUS EnumerateFiles( IN PUNICODE_STRING DirectoryName, ;"\??\c:\windows\system32" IN HANDLE DirectoryHandle OPTIONAL, IN PVOID EnumerateCallback, IN DWORD EnumerateParameter):NTSTATUS EnumerateCallback proto DirectoryHandle:HANDLE, FileInformation:PFILE_DIRECTORY_INFORMATION, EnumerateParameter:DWORD'
Everhest Моя ошибка. Не выдержал, скомпилил вашу прогу. Беда у вас не в рекурсии. У меня она находит все каталоги (сужу по МБ еррор), а в неправильном заполнении path_buffer. При его переполнении прога слетает.
_basmp_ А вот с этого момента поподробней... Где именно происходит это переполнение. Здесь что ли на 239 строке? Код (Text): proc SetDownDir buffer, path, ext invoke wsprintf,[buffer],format.path, [path], [ext] ret format.path db '%s\%s',0 endp
Everhest Не знаю. Я уже закрыл все. Иду спать. Попробуйте отладить самостоятельно. Найдите все упоминания, определитесь где меняться может. Смотрите что до и что после распространяясь от места обнаружения ошибки назад по ходу алга. Думайте как оно должно быть, при несовпадении думайте еще раз и если надумаете - правьте. Итд пока не все не заработает. Все. Удачи. Спокойной ночи.
_basmp_ Спокойной ноч... Спокойного утра. Ладно надо и мне поспать, а то чет голова уже не работает. Спасибо всем...
Everhest Если честно, Вашу кучу-малу прочитать нелегко. ИМХО Вам всю процедуру заново переписать лучше. И самое главное для рекурсивной процедуры - она должна быть реентерабельна!!! Т.е. при каждом вхождении иметь свою копию ВСЕХ используемых ей данных. Вот у Вас path_buffer где объявлена? Глобально? Дальше можно не смотреть: вся Ваша рекурсия идет на все три. Вы пишете: С чего бы это стэк не подходил? Стэк - это источник жизни рекурсии. Именно в него стоит загонять все Ваши WIN32_FIND_DATA, строки и т.п. Можно выделять память и отдельно(в куче, например), хотя это - не лучшая идея. НО! если отдельно, то в самом начале функции выделяете динамически память, а в самом конце освобождаете, храня при этом указатель в стэке (либо каждый рекурсивный вызов обрамляете выделением/освобождением памяти). И никаких внешних глобальных массивов в рассчете на всю глубину вхождения ф-ии в саму себя! Только усложняете этим задачу. А ведь смысл рекурсии исключительно в ее простоте для понимания при решении определенных задач. Никаких других преимуществ она не дает: объемов памяти не жалеет, а производительность в общем случае понижает. Надо полагать, что nesting должна считать глубину вхождения. Плохая идея. Незачем для данной задачи считать глубину вхождения. От этого портится вся красота/простота рекурсивного подхода.
В принципе я с вами согласен, процедура с самого начала пошла по иксу. А на счет динамического выделения памяти, попробую сегодня этот вариант.
asmfan В следующий раз учту, а процедурку сейчас переписываю. Кто хочет может глянуть, коряво правда: