SvrAPI для непродвинутых. Часть1
Как-то потребовалось программным способом открыть доступ к сетевому ресурсу. После прочтения (в очередной раз) хелпа от Дельфи стало ясно, что сетевым администрированием занимаются функции семейства Net*. А в частности для открытия, закрытия доступа к сетевому ресурсу, а также получения или изменения информации о нем применяются функции подсемейства NetShare*. Однако, как написано в хелпе, все эти функции работают только под WinNT. К сожалению... Но раз Win'9x открывает (закрывает) доступ, значит, можно сделать то же самое и программно. И тут начались поиски. В хелпе сказано, что для Си++ надо применять заголовочный модуль LmShare.h, в котором даны прототипы функций библиотеки netapi32.dll. Посмотрев эту библиотеку утилитой tdump.exe (лежит в директории Delphi_X\Bin), я увидел, что библиотека netapi32.dll (для Win'9x) кроме одной экспортируемой функции netbios более ничего не содержит. Далее включаю обычный поиск текста "NetShareAdd" в файлах *.dll. Поиск выдал результат - среди нескольких библиотек эту строку содержит и библиотека svrapi.dll. Следуя проторенным путем, т.е. через tdump.exe, увидел, что эта библиотека содержит почти все экспортируемые функции с названиями Net*. Ура! Место, где "собака порылась" найдено! Осталось только эту собаку откопать. Ясно, что без знания прототипов этих функций, сами по себе их названия - пустой хлам. Включаю поиск в Интернет строки "svrapi". И вот он, заветный заголовочный модуль! SvrApi.pas. Лежит, голубчик на JEDI! Написал его Petr Vones , за что ему большое спасибо! В этом модуле даны прототипы следующих классов Net-функций:
Все семейство NetShare*, а это:
Итак функция NetShareAdd . Вот ее прототип: function NetShareAdd(const pszServer: PChar; sLevel: SmallInt; pbBuffer: Pointer; cbBuffer: Word): NET_API_STATUS; stdcall;Описание аргументов функции будут даны ниже. Сейчас рассмотрим, как следует подключать эту функцию.
Если не вдаваться в подробности, то в подключении внешних функций оказывается нет ничего сложного. В Unit.pas после описания класса TForm и до клаузы implementation следует написать: Function NetShareAdd(ServerName : PChar; Level : Integer; pbBuffer : Pointer; BufferSize : Integer) : Integer; stdcall; external 'svrapi.dll';На что следует обратить внимание. Во-первых, я вольно заменил типы некоторых переменных на более привычный Integer (хотя по большому счету этого делать не следует). Во-вторых, stdcall - это способ передачи данных через стек, применяемый для Паскаля. И, в-третьих, external 'svrapi.dll' - означает, что функция находится во внешней библиотеке с названием svrapi.dll. Теперь к аргументам.
ServerName - сетевое имя компьютера, для локального можно писать Nill . Что можно сказать об этом аргументе. Для работы с локальной машиной проблем не возникает. Например, если сетевое имя машины Toshiba, то в этот параметр надо писать '\\Toshiba' или указать Nill . А вот для сетевой машины возникают проблемы. Испытывая NetShareAdd в сети, я постоянно результатом работы функции получал значение 65, что означает - "Нет доступа к сети" . Оказалось, чтобы открыть доступ к сети для NetShare-функций, надо "Разрешить удаленное управление этим сервером" (делается в "Пароли" из "Панели управления"). Тогда директории Windows присваивается сетевое имя ADMIN$ и после подключения этого имени в качестве сетевого диска, "сезам" открывается. Все это можно сделать программно: с помощью описываемой функции открыть доступ с именем ADMIN$ к любой директории, в том числе несуществующей ( см. ниже ) и с помощью одной из трех WNetAddConnection подключить сетевой диск для этого имени. Тогда все сработает на ура. Level - уровень администрирования. Для WinNT применяют три уровня 1,2 и 502, для Win'9x следует применять уровень 50. pbBuffer - указатель на структуру, в которую будем заносить все данные, необходимые для открытия доступа к ресурсу. На этой структуре следует остановиться более подробно. Вот она сама: Type TShareInfo50 = packet record shi50_netname: array[0..LM20_NNLEN] of Char; //сетевое имя shi50_type: Byte; //тип ресурса shi50_flags: Short; //флаг доступа shi50_remark: PChar; // комментарий shi50_path: PChar; // путь к ресурсу shi50_rw_password: array[0..SHPWLEN] of Char; //пароль полного доступа shi50_ro_password: array[0..SHPWLEN] of Char; //пароль "только чтение" доступа end;shi50_netname - сетевое имя, по обращению к которому, будет доступен сетевой ресурс. Сетевое имя должно быть уникальным. Константа LM20_NNLEN имеет значение 12, т.е. сетевое имя не должно быть более 12-ти символов. shi50_type - тип ресурса, может иметь следующие значения:
shi50_flags - флаг доступа, может иметь следующие значения:
shi50_remark - комментарий shi50_path - полный физический путь к устройству. Здесь надо учесть следующее:
shi50_rw_password - пароль для полного доступа; shi50_ro_password - пароль "только чтение", где SHPWLEN = 8, т.е. максимальное количество символов в пароле с учетом символа под номером 0 составляет 9 штук. И наконец, последний аргумент BufferSize - размер буфера, в котором находятся необходимые для открытия доступа данные. Теперь перейдем к значению, возвращаемому функцией NetShareAdd .
В случае успешного выполнения функции возвращается 0. В случае неудачи возвращается числовое значение. Обработка этого значения в большинстве случаев позволяет локализировать причину неудачи. Для функции NetShareAdd предлагаются следующие виды ошибок (в моем вольном переводе): NO_ERROR = 0; 'Все в порядке' (из LmErr.pas): NERR_BASE = 2100; базовая ошибка для NERR_ ; NERR_NetNotStarted = NERR_BASE+2 'Сеть недоступна' ; NERR_UnknownServer = NERR_BASE+3 'Неизвестный сервер' ; NERR_ServerNotStarted = NERR_BASE+14 'Сервер не работает' ; NERR_UnknownDevDir = NERR_BASE+16 'Сетевое устройство отсутствует' ; NERR_RedirectedPath = NERR_BASE+17 'Переназначенное устройство' ; NERR_DuplicateShare = NERR_BASE+18 'Сетевое имя уже существует' ; NERR_BufTooSmall = NERR_BASE+23 'Слишком маленький буфер для данных!' ; NERR_NetNameNotFound = NERR_BASE+210 'Сетевое имя не существует' ; NERR_InvalidComputer = NERR_BASE+251 'Неверное имя компьютера' ; NERR_ShareNotFound = NERR_BASE+292 'Сетевое устройство не обнаружено' . Однако бывают и другие ошибки. Почему-то функции SysErrorMessage (GetLastError) и WNetGetLastError при работе с NetShare* (по крайней мере у меня) не срабатывают, поэтому значения ошибок, коды которых менее 2100, я взял из ошибок, общих для всей операционной системы. (из Windows.pas:) ERROR_NOT_ENOUGH_MEMORY = 8 'Недостаточно памяти' ; ERROR_BAD_NETPATH = 53 'Неверное сетевое имя' ; ERROR_NETNAME_DELETED = 64 'Сетевой ресурс более недоступен' ; ERROR_NETWORK_ACCESS_DENIED = 65 'Отсутствует доступ к сети' ; ERROR_BAD_DEV_TYPE = 66 'Неверный тип сетевого ресурса' ; ERROR_BAD_NET_NAME = 67 'Не найдено сетевое имя' ; ERROR_INVALID_PARAMETER = 87 'Неверный параметр' ; ERROR_INVALID_LEVEL = 124 'Неверный уровень администрирования' ; Т.е. если результатом функции возвращается число больше, чем 2100, то смотри модуль LmErr.pas, если меньше - то модуль Windows.pas. На этом вроде все. Но, лучше один раз увидеть, чем... Поэтому посмотрим, как все работает на практике.
Для директории C:\Temp локальной машины откроем доступ с именем "TEST", паролем для чтения "QWE", для полного доступа "ASDF", комментарием "This is a network machine's commentary", с автоматическим открытием доступа при перезагрузке компьютера. И заодно закроем доступ. На новую форму следует положить две кнопочки и привести вид Unit1.pas в соответствие с ниже приведенным кодом.
unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Не забываем, что все, о чем говорилось в этой статье, относится к Win'9x! |