На этом шаге мы рассмотрим организацию поиска сетевых ресурсов.
Следующая программа осуществляет рекурсивный поиск сетевых ресурсов. Работая в консольном режиме, она выдает на экран название провайдера и удаленное имя ресурса. Данная программа должна правильно работать и в сетях Microsoft, и в сетях Novell.
.386P ;Плоская модель. .MODEL FLAT, STDCALL ;Константы. STD_OUTPUT_HANDLE equ -11 RESOURCETYPE_DISK equ 1h RESOURCE_GLOBALNET equ 2h RESOURCETYPE_ANY equ 0h ;Прототипы внешних процедур. IFDEF MASM EXTERN CharToOemA@8:NEAR EXTERN RtlMoveMemory@12:NEAR EXTERN WNetCloseEnum@4:NEAR EXTERN WNetEnumResourceA@16:NEAR EXTERN WNetOpenEnumA@20:NEAR EXTERN lstrcpy@8:NEAR EXTERN lstrcat@8:NEAR EXTERN lstrlen@4:NEAR EXTERN GetStdHandle@4:NEAR EXTERN WriteConsoleA@20:NEAR EXTERN ExitProcess@4:NEAR EXTERN GetCommandLineA@0:NEAR ELSE EXTERN CharToOemA:NEAR EXTERN RtlMoveMemory:NEAR EXTERN WNetCloseEnum:NEAR EXTERN WNetEnumResourceA:NEAR EXTERN WNetOpenEnumA:NEAR EXTERN lstrcpy:NEAR EXTERN lstrcat:NEAR EXTERN lstrlen:NEAR EXTERN GetStdHandle:NEAR EXTERN WriteConsoleA:NEAR EXTERN ExitProcess:NEAR EXTERN GetCommandLineA:NEAR CharToOemA@8 = CharToOemA RtlMoveMemory@12 = RtlMoveMemory WNetCloseEnum@4 = WNetCloseEnum WNetEnumResourceA@16 = WNetEnumResourceA lstrcpy@8 = lstrcpy WNetOpenEnumA@20 = WNetOpenEnumA lstrcat@8 = lstrcat lstrlen@4 = lstrlen GetStdHandle@4 = GetStdHandle WriteConsoleA@20 = WriteConsoleA ExitProcess@4 = ExitProcess GetCommandLineA@0 = GetCommandLineA ENDIF ;Структуры. NETRESOURCE STRUC dwScope DWORD ? dwType DWORD ? dwDisplayType DWORD ? dwUsage DWORD ? lpLocalName DWORD ? lpRemoteName DWORD ? lpCorament DWORD ? lpProvider DWORD ? NETRESOURCE ENDS ;Директивы компоновщику для подключения библиотек. IFDEF MASM ;Для компоновщика LINK.EXE. includelib \masm32\lib\user32.lib includelib \masm32\lib\kernel32.lib includelib \masm32\lib\mpr.lib ELSE ;Для компоновщика TLINK32.EXE. includelib c:\tasm32\lib\import32.lib ENDIF ;------------------------------------------------ ;Сегмент данных. _DATA SEGMENT DWORD PUBLIC USE32 'DATA' LENS DWORD ? ;Количество выведенных символов. HANDL DWORD ? NR NETRESOURCE <?> BUF DB 100 DUP(0) ENT DB 13,10,0 _DATA ENDS ;Сегмент кода. _TEXT SEGMENT DWORD PUBLIC USE32 'CODE' START: ;Получить дескриптор вывода. PUSH STD_OUTPUT_HANDLE CALL GetStdHandle@4 MOV HANDL,EAX ;Запустить процедуру поиска сетевых ресурсов. PUSH 0 PUSH OFFSET NR CALL POISK _END: PUSH 0 CALL ExitProcess@4 ;Процедура поиска. PAR1 EQU [EBP+8] ;Указатель на структуру. PAR2 EQU [EBP+0CH] ;Признак. ;Локальные переменные. HANDLP EQU [EBP-4] ;Дескриптор поиска. CC EQU [EBP-8] NB EQU [EBP-12] NR1 EQU [EBP-44] ;Структура. BUFER EQU [EBP-144] ;Буфер. RS EQU [EBP-32144] ;Массив структур. POISK PROC PUSH EBP MOV EBP,ESP SUB ESP,32144 CMP DWORD PTR PAR2,0 JNE SECOND ;При первом запуске NULL. XOR EBX,EBX JMP FIRST SECOND: ;Запуск при рекурсивном вызове. ;Вначале скопировать структуру в локальную ;переменную, хотя для данной программы это излишне. PUSH 32 PUSH DWORD PTR PAR1 LEA EAX,DWORD PTR NR1 PUSH EAX CALL RtlMoveMemory@12 ;При вторичном поиске указатель на структуру. LEA EBX,DWORD PTR NR1 FIRST: ;Запуск при первом вызове. LEA EAX,HANDLP PUSH EAX PUSH EBX PUSH 0 PUSH RESOURCETYPE_ANY PUSH RESOURCE_GLOBALNET CALL WNetOpenEnumA@20 CMP EAX,0 JNE _EN ;Здесь осуществляется основной поиск. REP1: ;Запуск функции WNetEnumResource. ;Объем массива структур NETRESOURCE. MOV DWORD PTR NB,32000 LEA EAX,NB PUSH EAX LEA EAX,RS PUSH EAX ;Искать максимальное количество объектов. MOV DWORD PTR CC,0FFFFFFFFH LEA EAX,CC PUSH EAX PUSH DWORD PTR HANDLP CALL WNetEnumResourceA@16 CMP EAX,0 JNE _CLOSE ;Цикл по полученному массиву. MOV ESI,CC SHL ESI,5 ;Умножаем на 32. MOV EDI,0 LOO: CMP EDI,ESI JE REP1 ;Вывод информации. ;Провайдер. MOV EBX,DWORD PTR RS[EDI]+28 CALL SETMSG ;Удаленное имя. MOV EBX,DWORD PTR RS[EDI]+20 CALL SETMSG ;Сохранить нужные регистры. PUSH ESI PUSH EDI ;Теперь рекурсивный вызов. PUSH 1 LEA EAX,DWORD PTR RS[EDI] PUSH EAX CALL POISK ;Восстановить регистры. POP EDI POP ESI ADD EDI,32 JMP LOO ;------------------------------------------------ JMP REP1 ;------------------------------------------------ _CLOSE: PUSH DWORD PTR HANDLP CALL WNetCloseEnum@4 _EN: MOV ESP,EBP POP EBP RET 8 POISK ENDP ;Вывод сообщения. ;EBX -> строка. SETMSG PROC ;Скопировать текст в отдельный буфер. PUSH EBX PUSH OFFSET BUF CALL lstrcpy@8 LEA EBX,BUF ;Перекодировать для консоли. PUSH EBX PUSH EBX CALL CharToOemA@8 ;Добавить перевод строки PUSH OFFSET ENT PUSH EBX CALL lstrcat@8 ;Определить длину строки. PUSH EBX CALL lstrlen@4 ;Вывести строку. PUSH 0 PUSH OFFSET LENS PUSH EAX PUSH EBX PUSH HANDL CALL WriteConsoleA@20 RET SETMSG ENDP _TEXT ENDS END START
Трансляция программы:
ML /с /coff /DMASM pr78_1.asm LINK /SUBSYSTEM:CONSOLE /STACK:1000000,100000 pr78_1.obj
TASM32 /ml pr78_1.asm TLINK32 -ap -S:1000000 -Sc:1000000 pr78_1.obj
Приведенная программа довольно сложна и требует серьезных пояснений. Прежде всего отметим, что, если читатель действительно хочет разобраться в сетевом программировании (в данном случае мы говорим о локальной сети), ему необходимо самостоятельно написать несколько программ. Приведенные программы могут служить отправными точками.
Мы коснулись сетевого программирования весьма поверхностно. Заинтересованному читателю можем перечислить те вопросы, которые он мог бы изучить, воспользовавшись соответствующей литературой.
Со следующего шага мы начнем рассматривать вопросы системного программирования в Windows.