Шаг 76.
Определение сетевых устройств

    На этом шаге мы рассмотрим программу, составляющую перечень устройств.

    В прикладном программировании часто возникает вопрос определения сетевых устройств. В принципе, вопрос можно поставить более широко: как определить тип того или иного устройства. Тот, кто программировал в MS-DOS, помнит, что там правильное определение типа устройства было не простой задачей. В Windows имеется очень полезная функция GetDriveType, единственным аргументом которой является строка корневого каталога искомого устройства, например "А:\" или "D:\". По возвращаемому функцией значению мы и определяем тип устройства.

    Файл pr76_1.asm.

.386P
;Плоская модель.
.MODEL FLAT, STDCALL
include pr76_1.inc
;Директивы компоновщику для подключения библиотек.
IFDEF MASM
;Для компоновщика  LINK.EXE.
    includelib \masm32\lib\user32.lib
    includelib \masm32\lib\kernel32.lib
ELSE
;Для компоновщика  TLINK32.EXE.
    includelib c:\tasm32\lib\import32.lib
ENDIF
;------------------------------------------------
;Сегмент данных. 
_DATA SEGMENT DWORD PUBLIC USE32 'DATA'
     PRIZ       DB  0
     MSG        MSGSTRUCT <?>
     HINST      DD 0 ;Дескриптор приложения.
     PA         DB "DIAL1",0
     ROO        DB "?:\",0
     BUFER      DB 40 DUP(0)
     TYP0       DB " Нет устройства",0
     TYP1       DB " Нет устройства",0
     TYP2       DB " Гибкий диск",0
     TYP3       DB " Жесткий диск",0
     TYP4       DB " Сетевой диск",0
     TYP5       DB " Лазерный диск",0
     TYP6       DB " Электронный диск",0
     INDEX      DD OFFSET TYP0
                DD OFFSET TYP1
                DD OFFSET TYP2
                DD OFFSET TYP3
                DD OFFSET TYP4
                DD OFFSET TYP5
                DD OFFSET TYP6
_DATA ENDS 
;Сегмент кода.
_TEXT SEGMENT DWORD PUBLIC USE32 'CODE'
START: 
;Получить дескриптор приложения.
     PUSH  0
     CALL  GetModuleHandleA@4
     MOV   [HINST], EAX
;-------------------------------------
;Создать диалоговое окно.
     PUSH  0
     PUSH  OFFSET WNDPROC
     PUSH  0
     PUSH  OFFSET PA
     PUSH  [HINST] 
     CALL  DialogBoxParamA@20 
     CMP   EAX,-1 
     JNE   KOL 
;Здесь можно разместить сообщение об ошибке.
KOL:
;-------------------------------------
     PUSH  0
     CALL  ExitProcess@4
;-------------------------------------
;-------------------------------------
;Процедура окна.
;Расположение параметров в стеке: 
;[ЕВР+014Н] LPARAM 
;[ЕВР+10Н] WAPARAM 
;[ЕВР+0СН] MES 
;[ЕВР+8] HWND 
WNDPROC PROC
        PUSH EBP
        MOV  EBP, ESP
        PUSH EBX
        PUSH ESI
        PUSH EDI
;-------------------------------------
;Сообщение при закрытии окна.
        CMP  DWORD PTR [EBP+0CH],WM_CLOSE
        JNE  L1
        PUSH 0
        PUSH DWORD PTR [EBP+08H]
        CALL EndDialog@8
        JMP  FINISH 
L1:
        CMP  DWORD PTR [EBP+0CH],WM_INITDIALOG
        JNE  L2 
L4: 
;Здесь анализ устройств и заполнение списка.
        MOV  ECX,65 
LOO:
        PUSH ECX
        MOV  ROO,CL 
;Определить тип устройства.
        PUSH OFFSET ROO
        CALL GetDriveTypeA@4 
;Полный список.
        CMP  PRIZ,0
        JZ   _ALL
        CMP  EAX,2
        JB   L3 
_ALL: 
;Получить индекс.
        SHL  EAX, 2
        PUSH EAX 
;Создать строку для списка.
        PUSH OFFSET  ROO
        PUSH OFFSET  BUFER
        CALL lstrcpy@8
        POP  EBX
        PUSH INDEX[EBX]
        PUSH OFFSET BUFER
        CALL lstrcat@8 
;Отправить строку в список.
        PUSH OFFSET BUFER
        PUSH 0
        PUSH LB_ADDSTRING
        PUSH 101
        PUSH DWORD PTR [EBP+08H]
        CALL SendDlgItemMessageA@20 
L3: 
;Проверить, не достигнута ли граница цикла.
        POP  ECX
        INC  ECX
        CMP  ECX,91
        JNE  LOO
        JMP  FINISH 
L2:
        CMP  DWORD PTR [EBP+0CH],WM_LBUTTONDOWN
        JNE  FINISH
        PUSH 0
        PUSH 0
        PUSH LB_RESETCONTENT
        PUSH 101
        PUSH DWORD PTR [EBP+08H]
        CALL SendDlgItemMessageA@20
        CMP  PRIZ,0
        JE   YES_0
        MOV  PRIZ,0
        JMP  L4
YES_0:	
        MOV  PRIZ,1
        JMP  L4
FINISH:	
        MOV  EAX,0
        POP  EDI
        POP  ESI
        POP  EBX
        POP  EBP
        RET  16
WNDPROC	ENDP
_TEXT   ENDS	
        END  START	

    Файл pr76_1.inc.

;Константы.
;Значения, возвращаемые функцией GetDiveType.
;Значения 0 и  1 можно считать  признаком
;отсутствия устройства.
DRIVE_REMOVABLE   equ 2   ; Накопитель  на  гибком диске.
DRIVE_FIXED       equ 3   ; Устройство жесткого диска.
DRIVE_REMOTE      equ 4   ; Сетевой  диск.
DRIVE_CDROM       equ 5   ; Накопитель  на лазерном диске.
DRIVE_RAMDISK     equ 6   ; Электронный диск.
;Сообщение приходит при закрытии окна.
WM_CLOSE      equ 10h
;Сообщение приходит при создании окна.
WM_INITDIALOG equ 110h
;Сообщение приходит при событии 
;с элементом на окне.
WM_COMMAND       equ 111h
LB_ADDSTRING     equ 180h
LB_RESETCONTENT  equ 184h
WM_LBUTTONDOWN   equ 201h
;Прототипы внешних процедур.
IFDEF MASM
    EXTERN  lstrcpy@8:NEAR 
    EXTERN  lstrcat@8:NEAR 
    EXTERN  GetDriveTypeA@4:NEAR 
    EXTERN  ExitProcess@4:NEAR 
    EXTERN  GetModuleHandleA@4:NEAR 
    EXTERN  DialogBoxParamA@20:NEAR 
    EXTERN  EndDialog@8:NEAR 
    EXTERN  SendDlgItemMessageA@20:NEAR
ELSE
    EXTERN  lstrcpy:NEAR 
    EXTERN  lstrcat:NEAR 
    EXTERN  GetDriveTypeA:NEAR 
    EXTERN  ExitProcess:NEAR 
    EXTERN  GetModuleHandleA:NEAR 
    EXTERN  DialogBoxParamA:NEAR 
    EXTERN  EndDialog:NEAR 
    EXTERN  SendDlgItemMessageA:NEAR
    lstrcpy@8              = lstrcpy
    lstrcat@8              = lstrcat
    GetDriveTypeA@4        = GetDriveTypeA
    ExitProcess@4          = ExitProcess
    GetModuleHandleA@4     = GetModuleHandleA
    DialogBoxParamA@20     = DialogBoxParamA
    EndDialog@8            = EndDialog
    SendDlgItemMessageA@20 = SendDlgItemMessageA
ENDIF
;Структуры.
;Структура сообщения.
MSGSTRUCT  STRUC	
           MSHWND     DD ? ;Идентификатор окна, получающего сообщение.
           MSMESSAGE  DD ? ;Идентификатор сообщения.
           MSWPARAM   DD ? ;Доп. информация о сообщении.
           MSLPARAM   DD ? ;Доп. информация о сообщении.
           MSTIME     DD ? ;Время посылки сообщения.
MSGSTRUCT ENDS	

    Файл pr76_1.rc.

//Определение констант.
#define WS_SYSMENU         0x00080000L
#define WS_MINIMIZEBOX     0x00020000L
#define WS_MAXIMIZEBOX     0x00010000L
//Элементы на окне должны быть изначально видимы.
#define WS_VISIBLE         0x10000000L
//Возможность фокусировать  элемент
//при помощи клавиши TAB.
#define WS_TABSTOP         0x00010000L
#define WS_VSCROLL         0x00200000L
//Стиль - диалоговое  окно Windows 95.
#define DS_3DLOOK          0x0004L
#define LBS_NOTIFY         0x0001L
#define LBS_SORT           0x0002L
#define LBS_WANTKEYBOARDINPUT   0x0400L
//Идентификаторы.
#define LIST1   101
//Определение диалогового окна.
DIAL1 DIALOG 0, 0, 180, 110
STYLE  WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | DS_3DLOOK
CAPTION "Определение типов устройств"
FONT 8, "Arial"
{
  CONTROL "ListBox1", LIST1, "listbox",  WS_VISIBLE | WS_TABSTOP | 
       WS_VSCROLL | LBS_NOTIFY | LBS_WANTKEYBOARDINPUT, 16, 16, 100, 75 
}
Тексты этих файлов можно взять здесь.

    Результат работы программы представлен на рисунке 1.


Рис.1. Результат работы приложения

    Трансляция программы:

    После того как вы определили, что данное устройство является сетевым, может возникнуть вторая задача: определить статус устройства. Под статусом в данном случае мы понимаем три возможных ситуации:

    Можно поступить следующим образом. Для проверки статуса устройства можно использовать две функции: CreateFile и GetDiskFreeSpace. С первой функцией вы уже знакомы, с помощью второй функции можно определить объем свободного места на диске. Если данное устройство позволяет создать файл (файл лучше создавать с атрибутом "удалить после закрытия", и операционная система сама выполнит процедуру удаления) и прочесть данные об устройстве, следовательно, оно открыто для чтения и записи. Если устройство позволяет прочитать данные о нем, но не позволяет создать файл, следовательно, устройство открыто только для чтения. Наконец, если не разрешено ни то, ни другое, следовательно, устройство недоступно. Такой бесхитростный подход, однако, работает весьма эффективно.

    На следующем шаге мы рассмотрим доступ к ресурсам локальной сети.




Предыдущий шаг Содержание Следующий шаг