| Сетевые функции Windows |
ВведениеНачиная писать статью рассказывающую о средствах Windows, для работы с сетью. Я не мог не упомянуть тот факт, что изначально Windows не была сетевой операционной системой. Во времена выхода Windows 1.0 сети ещё не были распространены и не оправдывали своей стоимости. Однако, к появлению Windows 2.0 сети уже стали распространённей, но их работа была основана на DOS. И только после появления Windows for Workgroups и Windows NT, Windows можно считать сетевой операционной системой. Но за это время появилось множество других сетевых операционных систем и каждая из них обладала собственным набором функций API. Microsoft уже не могла заставить всех использовать свой стандартный API, был выбран подход - определения минимального количества общих сетевых функций, работающий не зависимо от типа реализации сети. Имена функций независящих от провайдера и типа сети, начинаются с префикса WNet - о них и пойдет речь в этой статье. Понятие "Сеть"Все сети Windows представляют собой иерархию сетевых ресурсов. Некоторые из них являются физическими устройствами - диски, принтеры. Другие представляют собой логические контейнеры. На верхнем уровне находится root-узел. На следующем уровне, в иерархии, расположены сетевые провайдеры. Далее идут домены и рабочие группы, которые содержат отдельные сервера. Функции WNet позволяют Вам подключатся к сетевым ресурсам, способом не зависящим от типа сети или типа подключения. К примеру, Вы хотите подключиться к серверу RemoteServer, на котором установлен диск RemoteDiskC и обратится к файлу RemoteFile.txt, расположенному в root-каталоге. Для этого можно подключить \\RemoteServer\RemoteDiskC как диск Z: и после ссылаться на нужный файл в привычном виде, Z:\RemoteFile.txt. WNet функции и классСчастью WNet функции, а особенно с функциями перечисления очень тяжело работать в Visual Basic, приходится постоянно учитывать множество аспектов, относящихся к работе с буферами и выравниванию переменных. Они прекрасно подходят для инкапсуляции их в классах. Список WNet функций приведен в таблице 1:
Структура классовПервым шагом при проектировании классов для группы функций, будет анализ типов данных и структур, используемыми этими функциями. Любая структура используемая несколькими однородными функциями является хорошим кандидатом для инкапсуляции её в класс. Каждый экземпляр класса будет связан со структурой, а по всей видимости и содержать её саму. Обращение к данным будет происходить через свойства класса, а обращения к функциям через методы. В нашей ситуации отличным кандидатом для этого является структура NETRESOURCE, которая используется для перечисления и получении информации о сетевых ресурсах. Класс dwNetResource инкапсулирует эту структуру и использующие её функции. Подробнее класс описан далее. А что делать с функциями не относящимися к отдельным структурам, например такая функция как WNetAddConnection? Их сделать глобальными, то у нас возникнут проблемы при организации доступа через ActiveX DLL. Лучшим решением будет создать класс высокого уровня содержащий только эти функции. В нашем случае для этого был создан класс dwNetwork. Для примера рассмотрим объявление функции WNetAddConnection в классе dwNetwork: Private Declare Function intWNetAddConnection Lib "mpr.dll" _ Обратите внимание, что использовался псевдоним функции, это потребовалось для того, чтобы оставить имя WNetAddConnection для наших целей. Метод WNetAddConnection, класса dwNetwork, объявляется так: Public Function WNetAddConnection(RemoteName As String, _ Такой принцип можно применять для большей части остальных функций. Сетевые ошибкиОбрабатывать ошибки сетевых функций несколько сложнее чем, ошибки других функций Windows API. Это происходит из-за существования различных сетевых систем. Некоторые ошибки определенны в Windows, как и многое другие, и их можно обрабатывать используя функцию GetLastError. Но некоторые ошибки, при работе с сетью, генерируются конкретным провайдером. Для этих случаев существует специальная функция WNetGetLastError, через которую Вы можете получить код ошибки и её описание от любого провайдера. WNetGetLastError используется в тех случаях когда GetLastError возвращает ERROR_EXTENDED_ERROR. Для обработки ошибок был создан класс dwNetError, его код приведен ниже: Private Declare Function WNetGetLastError Lib "mpr.dll" _ В классе инициализируются три открытых переменных в которых хранится: код ошибки, её описание и имя сетевого провайдера. Данные помещаются в эти переменные при создание объекта. Обработка ошибок показана в следующем примере: ' Loads the LastError and LastNetError information Переменные LastError и LastNetError будут закрытыми переменными конкретного класса. При возвращении ошибки сетевой функцией признака ошибки будет вызвана функция SetErrorValues, для занесения в переменные подробной информации об ошибке. Так же Вы получаете централизованное средство для обработки и получения информации об ошибках, которое можно расширить для инициализации собственных ошибок, если Вы захотите реализовать этот класс в виде ActiveX. Перечисление сетевых ресурсовНаиболее сложной и часто выполняемой задачей является получение информации о доступных сетевых ресурсах или перечисление. Как уже было сказано, все сетевые ресурсы доступные в системе описываются структурой NETRESOURCE, подробно структура описана в таблице 2:
Перечисление сетевых ресурсов происходит в три этапа. Первое, вызывается функция WNetOpenEnum, которая определяет тип перечисляемых ресурсов указанных в структуре NETRESOURCE. Далее вызывается WNetEnumResource возвращающая структуру NETRESOURCE для каждого ресурса на этом уровне. И на конец WNetCloseEnum удаляет манипулятор перечисления, полученный при вызове WNetOpenEnum. Процесс с первого взгляда не понятный, но не сложный. Главная проблема заключается в том, что приходится манипулировать адресами строк в буфере. Из-за того, что параметры lpLocalName, lpRemoteName, lpComment и lpProvider нельзя задать как стоки Visual Basic, поскольку в ряде случаев их значения задают сетевые функции Win32, не поддерживающие типы данных VB или OLE. Как упоминалось выше, структура NETRESOURCE идеально подходит для инкапсуляции в класс. Так же этот класс должен выполнять все манипуляции над строками. Как Вам уже известно, перечисления начинается с конкретного уровня иерархии, а этот уровень указывается в структуре NETRESOURCE, то функции перечисления будет разумно сделать частью класса. Класс dwNetResourceТот факт, что в Windows API перечисление сетевых ресурсов происходит в три этапа, вовсе не значит, что в класс ложен быть построен по аналогичной схеме. В нашем случае, каждые ресурс описывается объектом dwNetResource, то более гибкое решение - создать метод Enumerate, который бы просто возвращал коллекцию объектов dwNetResource, содержащихся в объекте. Вы скоро убедитесь, что именно такой подход использован в этой реализации. Объявления, Данные и ИнициализацияОбъявление API функций использующихся в нашем классе: Private Declare Function WNetOpenEnum Lib "mpr.dll" _ Обратите внимание на два момента. Первое, создано два объявления одной функции. В первом случае, сетевой ресурс передается, в качестве параметра, для перечисления ресурсов в контейнере для функции WNetOpenEnum. Во втором случае передаётся NULL для перечисления всех ресурсов. Во-вторых, функции WNetAddConnection2 и WNetAddConnection3, тоже реализованы в этом классе, из-за того что им в качестве параметра передается структура NETRESOURCE. Все функции из этого класса получают NETRESOURCE в следующем виде: Private Type NETRESOURCE Они получают строковые параметры, так как не изменяют их содержимого. В каждом классе содержится глобальная переменная info инициализированная как NETRESOURCE для текущего объекта. Также, определяется тип NETRESOURCELONG, который используется при заполнении структуры функцией WNetEnumResource. Выглядит тип так: Private Type NETRESOURCELONG Метод Enumerate имеет те же параметры, что и функция WNetOpenEnum, и вызывает её в самом начале своей работы. Так же у класса есть флаг инициализации, по состоянию которого определяется, был ли он инициализирован раньше. Если инициализации не происходила, то функция предполагает, что перечисление должно быть выполнено с верхнего уровня иерархии. Получив манипулятор перечисления, в памяти создаётся временный буфер очень большого размера, предназначенный для заполнения структуры NETRESOURCELONG, за которой следуют строковые данные структуры. После этого создаётся новый объект dwNetResource и адрес буфера передаётся его закрытому методу Load. Метод преобразует содержимое буфера в структуру NETRESOURCE для объекта. Новый объект включается в коллекцию results, которая в свою очередь возвращается методом Enumerate. Этот процесс продолжается до нахождения всех сетевых ресурсов на указанном уровне. Код метода Enumerate: Public Function Enumerate(ByVal dwScope&, _ Функция Load инициализирует объект dwNetResource на основании созданного буфера, заполненного функцией WNetOpenEnum. Инициализация состоит из двух частей: открытой функции Load, получающей адрес буфера, и закрытой функции LoadInfoFromNRLong, загружающей строковые данные. Работа функции начинается с копирования начальной области буфера во временную структуру NETRESOURCELONG. Функция LoadInfoFromNRLong проверяет значения типа Long и извлекает строковые данные при помощи функции agGetStringFromPointer из библиотеки APIDIG32.DLL Код функций Load и LoadInfoFromNRLong: Public Sub Load(ByVal bufferaddress&) Автор: Appleman Daniel Источник: http://www.vbnet.ru/
|