Диалог выбора компьютера

Диалог выбора компьютера по аналогии с диалогом выбора папки

  • Автор: Still Zero
  • Уровень знаний: начальный
  • Подразделы: нет
  • Дата публикации: 21.10.2005

Как вы знаете, существует стандартный диалог выбора файла/папки. В Кларионе для этого используется команда FILEDIALOG. По большому счету, этой же командой можно воспользоваться для выбора компьютера в сети, но это не очень удобно, так как нет возможности сразу же встать на папку «Сетевое окружение», показываются «расшареные» ресурсы компьютеров и существует возможность выбора обычных папок. Поэтому, приложим немного усилий и пойдем другим путем.

Во-первых, существует несколько API функций для обзора сети: WNetOpenEnum, WNetEnumResource, WNetCloseEnum. Используя эти функции, можно перечислить ресурсы сети (сами сети, домены, компьютеры, «шары» и т.п.). Минус этого метода в том, что функция WNetEnumResource, которая собственно и отвечает за перечисление ресурсов, достаточно медленная. В примерах обычно показывается рекурсивный вызов этой функции, что еще более замедляет работу, так как при таком подходе просматривается вся сеть. Если уйти от просмотра всей сети и просматривать сеть по уровням, то возникает другое неудобство работы с этой функцией. Оно вызвано тем, что она возвращает адрес буфера памяти, в котором хранится массив групп с информацией о ресурсах. Таким образом, приходится хранить различные адреса буферов для разных уровней.
Когда я говорю о уровнях, я имею ввиду следующую структуру сети:

Использование адресов групп, вместо самих групп является не очень сложным, но несколько неудобным способом, я бы даже сказал громоздким. К тому же, необходимо помнить о освобождении памяти, после ее использования.

Таким образом, я пришел ко второму подходу, использование которого максимально просто. Существует API-функция SHBrowseForFolder.
Она показывает диалог выбора папки. При выставлении соответствующих флажков, эта функция также может служить и для выбора компьютеров. Также существует возможность просмотра именно «Сетевого окружения». Cамо собой отпадает необходимость создания диалогового окна. Плюсом также является то, что происходит вызов стандартного диалога Windows.
Минусом остается медленная работа при открытии веток сети.

Прототип функции:

SHBrowseForFolder(LONG lpbi),LONG,RAW,PASCAL

где lpbi — адрес группы. Группа имеет следующий вид:

BROWSE_INFO_TYPE          GROUP,TYPE
hwndOwner                    ULONG   ! хэндл окна "хозяина"
pidlRoot                     LONG    ! адрес на список начальной папки
pszDisplayName               LONG    ! адрес на возвращаемую строку
lpszTitle                    LONG    ! адрес на строку заголовка
ulFlags                      ULONG   ! флаги
lpfn                         LONG    ! адрес на callback-функцию
lParam                       LONG    ! параметр передаваемый в callback-функцию
iImage                       LONG    ! номер картинки, ассоциированный с выбранной папкой
                          END

Параметры группы lpfn, lParam, iImage я не использую.
Наиболее интересным параметров является pidlRoot. Он представляет собой указатель на список идентификаторов папок. Т.е. каждая папка (файл, ресурс) имеет свой номер. В этом списке может содержаться начальное значение — где смотреть ресурсы. В качестве отправной точки могут выступать системные папки, например, «Мой Компьютер», «Мои документы», «Принтеры и факсы» и т.п. Также этот параметр может быть не указан. В этом случае просмотр начинается с «Рабочего стола».

Параметр ulFlags должен содержать константу BIF_BROWSEFORCOMPUTER.
Функция возвращает указатель на список идентификаторов, в случае если выбрана обычная папка. В другом случае выбранное имя ресурса возвращается в переменной pszDisplayName. Если пользователь нажал на кнопку Отмена в диалоге, то функция возвращает ноль.

Нам необходимо просматривать только папку «Сетевое окружение». Для того, чтобы создать список идентификаторов для этой папки, используем функцию SHGetSpecialFolderLocation. Ее прототип:

SHGetSpecialFolderLocation(ULONG hwndOwner,LONG nFolder,*LONG ppidl),LONG,PASCAL

Последний параметром в этой функции и является указатель на список. В качестве параметра nFolder выступает константа CSIDL_NETWORK.

Выше я говорил, что функция возвращает указатель на список идентификаторов. Для того, чтобы узнать путь к выбранной папке по известному адресу списка, необходимо воспользоваться функцией SHGetPathFromIDList. Ее прототип:

SHGetPathFromIDList(LONG pidl,LONG pszPath),BOOL,RAW,PASCAL

На самом деле, используя SHGetPathFromIDList вы не узнаете имя компьютера, так как эта функция работает с «обычными» папками. При выборе компьютеров, выбранное имя будет возвращено в переменной pszDisplayName.

Замечания В документации к функции SHBrowseForFolder сказано, что перед ее вызовом необходимо вызвать функцию CoInitialize(). Я не использую этого вызова, проблем именно для выбора компьютеров замечено не было.
Также, в документации говорится о том, что необходимо освобождать память, выделяемую под списки идентификаторов. В данном случае у нас есть два списка: список для папки «Сетевое окружение» и возвращаемый список. Для освобождения памяти рекомендуется использовать COM-интерфейс IMalloc. Использование COM нетривиально, поэтому память в примере не очищается.

NetBrowse (815) (C55, ABC)
© Project Zero, 2005. Все права защищены.