ИВАН КОРОБКО
Автоматизируем подключение баз «1С» новой версии 8.0
Специалисты компании «1С» значительно переработали систему безопасности в базах «1С» новой версии 8.0 по сравнению с прошлой «1С» 7.7. В связи с этим архитектура программы изменилась коренным образом. Как следствие стал иным и механизм подключения баз
Мы уже знакомили вас с автоматическим управлением подключения баз «1С» v.7.7 с помощью сценария регистрации пользователей в сети (см. [1]). Пользователям, которые входили в соответствующие группы безопасности, сценарий автоматически подключал необходимые сетевые базы и отключал те, к которым пользователь не имел прав доступа, при этом подключенные локальные базы сценарием не затрагивались. С появлением «1С» v.8.0 ситуация изменилась: сценарий для подключения баз «1С» v.7.7 не подходит для новой версии «1С», поскольку информация о подключаемых базах для версии 7.7 хранилась в системном реестре на рабочей станции, а для версии 8.0 – в файлах. Сегодня мы подробно рассмотрим механизм подключения баз «1С» v.8.0, ее итогом будет сценарий, который в автоматическом режиме управляет подключением сетевых баз, записи, соответствующие в браузере локальным базам, будут перенесены в отдельную папку.
Выбираем язык программирования
Для создания сценариев регистрации пользователей существует множество языков, однако остановим свой выбор на KIXTart. Этот язык является стандартным языком программирования сценариев компании Microsoft. Его дистрибутив можно найти в Microsoft Resource Kit или бесплатно загрузить последнюю версию из сети Интернет (http://kixtart.org). Подробное описание функционала языка можно найти на этом же сайте.
Замечание: сценарии, созданные вами ранее на VBScript, Jscript, могут быть легко переписаны под KIXtart.
Рассмотрим внутреннее устройство клиентской части 1C v.8.0
Как было сказано ранее, информация о подключенных базах для версий 7.7 и 8.0 находится в разных местах. Теперь все данные хранятся в каталоге «Documents and Settings\%username% Application Data1C1Cv8». Для успешного подключения баз необходимо в нем создать минимум два файла (1Cv8strt.pfl и v8ib.lst) и соответствующие ID баз папки. В каждой из них также должен быть создан файл usr.def. Файловая структура подключаемых баз приведена на рис. 1.
Рисунок 1. Файловая структура клиентской части «1С» 8.0
Управление отображением списка баз (визуальная структура) в браузере «1С» осуществляется с помощью файла v8ib.lst (рис. 2). С помощью второго файла – 1Cv8strt.pfl реализовано манипулирование такими параметрами, как размер и положение браузера «1С» на экране, сортировка списка баз и т.д. В файле usr.def содержится имя пользователя, который последний открывал данную информационную базу. Все три файла имеют кодировку utf-8, и соответственно создавать их необходимо именно в этой кодировке. В противном случае данные в браузере «1С» будут отображаться некорректно либо не будут отображаться вовсе.
Рисунок 2. Браузер «1С»
Управляем текстовыми файлами в кодировке utf-8
Объект FSO, традиционно используемый для создания текстовых файлов, не подходит, поскольку он не поддерживает требуемой кодировки (utf-8). Для решения поставленной задачи предлагается использовать объект ADODB.Stream. Управление текстовыми файлами подразумевает чтение и запись данных в файл. Приведу два соответствующих примера. Чтение данных из текстового файла:
$Stream = CreateObject("ADODB.Stream")
$Stream.Type =2
$Stream.CharSet = "Utf-8"
$Stream.Open
$Stream.LoadFromFile("1.txt")
$GetFile = $Stream.Readtext()
$Stream.Close
В примере данные считываются из файла 1.txt в переменную $GetFile. Параметр $Stream.Type может принимать значения 1(binary) или 2(text), в зависимости от типа данных, содержащихся в файле. С помощью параметра $Stream.CharSet управляют кодировкой чтения/записи данных в файл. Доступные для данной ОС кодировки перечислены в системном реестре HKEY_CLASSES_ROOTMIMEDatabaseCharset.
Запись данных в текстовый файл:
$Stream = CreateObject("ADODB.Stream")
$Stream.CharSet = "utf-8"
$Stream.Mode = 3
$Stream.Open
$Stream.WriteText("Записываемые данные")
$Stream.SaveToFile("1.txt")
$Stream.Close
В приведенном примере данные, на которые ссылается функция Stream.WriteText(), записываются в файл 1.txt; С помощью параметра $Stream.Mode осуществляется управление режимом работы с данными файла. Основные принимаемые значения – 1 (чтение – по умолчанию), 2 (запись) и 3 (чтение/запись).
Структура файла v8ib.lst
В файле v8ib.lst содержащиеся данные описывают один из двух объектов: папку или ссылку на базу. Существуют ссылки на локальную или серверную базу. Описываемый файл имеет структуру ini-файла, названия разделов в котором совпадают с именами баз, отображаемыми в браузере.
Синтаксис баз
Как уже говорилось, название разделов должно совпадать с соответствующими именами баз. В каждом разделе присутствует пять обязательных параметров, описания которых приведены в таблице 1.
Таблица 1. Описание параметров, используемых в файле v8ib.lst
Параметр
|
Описание
|
Connect
|
Значением параметра является путь к базе данных. Для локальной базы значение формируется в соответствии с шаблоном File=”путь к локальной базе”; для сетевой – srvr=”sql_server.domain”; ref=”название базы данных на SQL-сервере”;
|
ID
|
Уникальный ID. На всех рабочих станциях, вопреки заявлениям представителей фирмы «1С», он может быть одинаковым для одной и той же базы
|
OrderInList
|
Порядковый номер базы в подпапке браузера
|
Folder
|
Путь к текущей папке в браузере «1С». Для корневого каталога параметр принимает значение «/», для остальных – «/название базы»
|
OrderInTree
|
Сквозной номер базы в общей структуре
|
Пример подключения локальной базы:
[Тестовая локальная база]
Connect=File="С:Base";
ID=28f15724-3c41-4753-b5a4-42bb454b8be3
OrderInList=32768
Folder=/Тестовые базы
OrderInTree=65536
Пример подключения сетевой базы:
[Тестовая сетевая база]
Connect=Srvr="sql.server.domain.ru";Ref="Enterprise_test";
ID=28f15724-3c41-4753-b5a4-42bb454b8be3
OrderInList=16384
Folder=/
OrderInTree=32768
Синтаксис подкаталога
Описание каталога аналогично описанию баз, однако есть два принципиальных отличия: отсутствие параметра connect и значение параметра OrderInList=-1:
[Локальные базы]
ID=7fa1d5a9-d087-4026-9eea-f18a233d618f
OrderInList=-1
Folder=/
OrderInTree=16384
Структура файла 1Сv8strt.pfl
Анализируя создаваемый «1С» файл и изменяя различные параметры, были приобретены знания по управлению настройками визуального представления браузера «1С», умение назначать базу по умолчанию (при открытии браузера). Проанализируем фрагменты файла (листинг файла см. на сайте www.samag.ru, в разделе «Исходный код»):
{"N",1},"ShowIBsAsTree",
{"B",1},"AutoSortIBs",
{"B",0},"ShowRecentIBs",
{"B",0},"LRInfoBaseIDList",
Таблица 2. Описание параметров, управляющих конфигурацией браузера «1С»
Параметр
|
Описание
|
ShowIBsAsTree
|
Отображать структуру баз в виде дерева
|
AutoSortIBs
|
Выполнять автоматическую сортировку баз
|
ShowRecentIBs
|
Показать список из Х последних открытых баз. Значение параметра Х определяется пользователем «1С» в настройках браузера
|
LRInfoBaseIDList
|
Установка курсора на базу по умолчанию
|
Рисунок 3. Параметры настройки браузера «1С»
Параметры «ShowIBsAsTree», «AutoSortIBs», «LRInfoBaseIDList» могут принимать значения 0 или 1, исключение составляет параметр «ShowRecentIBs» – принимаемые значения от 1 до 9.
Алгоритм работы скрипта
Работу скрипта условно можно разделить на несколько частей:
- Генерация файла 1Сv8strt.pfl
- Обработка данных файла v8ib.lst:
- Чтение, анализ и вычленение данных о локальных базах.
- Определение и формирование данных для подключения доступных сетевых баз.
- Формирование файла v8ib.lst, создание соответствующих каталогов, файлов def.usr.
Скрипт: файл 1cv8strt.pfl
Файл 1cv8strt.pfl статичен и меняется крайне редко, поэтому существует два варианта его создания на рабочей станции пользователя: первый – копирование с сервера (см. листинг файла в приложении на сайте журнала www.samag.ru в разделе «Исходный код»), второе – его генерация с помощью сценария. Рассмотрим второй случай.
Для упрощения управления базами по умолчанию и упорядочиванию структуры рекомендуется считывать соответствующую информацию из конфигурационного файла. Пример файла приведен ниже:
[1c8]
ShowAsTree=1
AutoSort=1
DefaultBaseName=Сетевая база данных 1
Считывание данных из конфигурационного файла осуществляется следующим образом:
…
$DefaultBaseName=readprofilestring("$config_ini","1c8","DefaultBaseName")
$meta_1c8=readprofilestring("$config_ini","1c8","base1c8prefix")
$ShowAsTree=readprofilestring("$config_ini","1c8","ShowAsTree")
$AutoSort=readprofilestring("$config_ini","1c8","AutoSort")
…
где переменная $config_ini содержит имя и полный путь, в случае необходимости, к конфигурационному файлу. Второй параметр – название раздела, третий – соответственно параметра, значение которого возвращает функция.
Ранее описывалась структура этого файла. ID-номер базы по умолчанию определяется в двойном цикле Do…Loop и зафиксируется в переменной $default_guid.
…
if instr(ucase($des), ucase($DefaultBaseName))<>0
$default_guid=right( $infos[1],len( $infos[1])-3)
Endif
…
Перед записью в файл данные накапливаются в переменную, в данном случае $cfg. Полностью листинг генерации файла 1cv8strt.pfl приведен в приложении. В данном примере покажем лишь принцип, лежащий в основе формирования. Использование кавычек вносит коррективы в механизм генерации файла: в листинге скрипта кавычка выглядит следующим образом: « + chr(34) + ».
$en=chr(13)+chr(10)
…
$cfg = $cfg + "{"+$en
$cfg = $cfg + "{" + chr(34) + "LRInfoBaseIDListSize" + chr(34) + ","+$en
$cfg = $cfg + "{" + chr(34) + "N" + chr(34) + ","+ $ShowAsTree+"}," + chr(34) + "ShowIBsAsTree" + chr(34) + ","+$en
$cfg = $cfg + "{" + chr(34) + "B" + chr(34) + ","+ $AutoSort+"}," + chr(34) + "AutoSortIBs"+ chr(34) + ","+$en
…
$cfg = $cfg + "}"+$en
После наполнения переменной данными осуществляется запись ее содержимого в файл. Напомним, что файл 1cv8strt.pfl находится в каталоге «Documents and Settings\%username%Application Data1C1Cv8».
$FSO = CreateObject("Scripting.FileSystemObject").GetFile($path_to_base+"1cv8strt.pfl")
if @error=0
$FSO.Delete
endif
$FSO.close
$Stream = CreateObject("ADODB.Stream")
$Stream.CharSet = "utf-8"
$Stream.Mode = 3
$Stream.Open
$Stream.WriteText($cfg)
$Stream.SaveToFile($path_to_base+"1cv8strt.pfl")
$Stream.Closeendif
Скрипт: файл v8ib.lst
Локальные базы
На первом этапе осуществляется чтение существующего файла и вычленение списка локальных баз. Пример чтения файла был приведен ранее, поэтому сразу перейдем к обработке считанных данных в переменную, например, $GetFile: после того как данные считаны, файл необходимо удалить:
$fso = CreateObject("Scripting.FileSystemObject")
$fso.DeleteFile($f_name)
$fso.close
Имеющиеся данные необходимо разбить на подстроки и записать в массив, затем, проанализировав их, вычленить локальные базы. В качестве признака, по которому будут формироваться подстроки, рекомендуется использовать символ «[». При таком преобразовании элементами массива будут содержать описания баз целиком, например:
a[0]= "[Тестовая сетевая база]" + chr(13) + chr(10) + "Connect= File = " + chr(34) + "С:\Base" + chr(34) + ";" + chr(13) + chr(10) + \
"ID=28f15724-3c41-4753-b5a4-42bb454b8be3" + chr(13) + chr(10) + "OrderInList=16384" + chr(13) + chr(10) + "" + chr(13) + chr(10) + \
"Folder=/" + chr(13) + chr(10) + "OrderInTree=32768"
Затем просмотрите и отберите элементы массива, характеризующие локальные базы. Признаком локальности базы является значение элемента connect, начинающегося с file=. Накопление данных осуществляется в переменную, которая потом также будет разложена в массив, но уже по другому признаку: переводу и возврату каретки на новую строку, а именно chr(13)+chr(10):
$en=chr(13)+chr(10)
…
$temp=""
' расчленение строки на элементы массива.
' Признак – наличие "["
$array_0=split($GetFile,"[")
for each $element in $array_0
' "connect=file=" – признак локальности БД
if instr(ucase($element),ucase("connect=file="))<>0
$element="["+$element
$temp=$temp+$element
endif
next
$array_base=split($temp, $en) ' массив локальных баз
Поскольку нумерация баз меняется, существующие локальные базы данных необходимо переместить в отдельную виртуальную папку, например, «Локальные базы», поэтому значения параметров OrderInList и OrderInTree необходимо обнулить, значения параметра Folder исправить на Folder=/ Локальные базы. Для этого необходимо обновить значения элементов массива:
$virtual_local_folder="Локальные базы"
for $i=0 to ubound($array_base)
$element=$array_base[$i]
if instr(ucase($array_base[$i]),ucase("orderin"))<>0
$array_base[$i]=left($element,instr($element,"="))
endif
if instr(ucase($element),ucase("folder="))<>0
$array_base[$i]=left($element,instr($element,"=")+1)+$virtual_local_folder
endif
next
После переприсвоения элементы массива $array_base могут иметь следующий вид:
$array_base[0]= "[Тестовая сетевая база]"
$array_base[1]= "Connect=File="С:\Base";"
$array_base[2]= "ID=28f15724-3c41-4753-b5a4-42bb454b8be3"
$array_base[3]= "OrderInList="
$array_base[4]= "Folder=/ Локальные базы"
$array_base[5]= "OrderInTree="
………………………………….
Сетевые базы
Составление списка сетевых баз основано на чтении данных из AD по следующему алгоритму: с помощью встроенной в KIX функции EnumGroup() просматривается список групп, в которые входит настоящий пользователь, и отфильтровываются только те из них, которые имеют заранее оговоренный префикс в названии, например, «1с8$_»:
$i=0
$Temp=""
Do
$Group = EnumGroup($i)
$i = $i + 1
If instr(ucase($group), ucase("1c8$_"))<>0
…………..
EndIf
Until Len($Group) =0
MessageBox("$Temp","",0,0)
Рисунок 4. Группа безопасности
Поскольку название группы все время меняется, то в соединение с AD необходимо интегрировать функцию EnumGroup():
' определение имени текущено домена
$Domain = "LDAP://"+GetObject("LDAP://RootDSE").Get("defaultNamingContext")
$objConnection = CreateObject("ADODB.Connection")
$objCommand = CreateObject("ADODB.Command")
$objConnection.CommandTimeout = 120
$objConnection.Provider = "ADsDSOObject"
$objConnection.Open ("Active Directory Provider")
$objCommand.ActiveConnection = $objConnection
$i=ubound($array_base)
DO
$Group = ENUMGROUP($p)
if instr("$Group","$meta_1c8")<>0
$1c8_group=right($group,len($group)-instrrev($group,"\"))
$strADSQuery = "SELECT name,info,description FROM '" +$domain+"' WHERE objectClass='group’ and samaccountname='"+$1c8_group+"'"
$objCommand.CommandText = $strADSQuery
$st = $objCommand.Execute
$st.Movefirst
Do
$name = $St.Fields("name").Value
$description = $St.Fields("description").Value
$des=""
For each $element in $description
$des=$des+$element
Next
$infos = split($St.Fields("info").Value,chr(13)+chr(10))
……………………………….
$st.MoveNext
Until $st.EOF
endif
$p=$p+1
UNTIL Len($Group) = 0
Замечание: в приведенном примере название группы, возвращаемое функцией enumgroup() имеет вид domain\groupname, где domain – короткое имя домена. В SQL-запросе к Active Directory должно фигурировать только имя группы, т.е. необходимо отбросить префикс «domain\», поэтому короткое имя группы будет выглядеть:
$1c8_group=right($group,len($group)-instrrev($group,"\"))
Данные, содержащиеся в массиве $infos необходимо преобразовать и добавить их в конец массива $array_base. При этом добавляемые в него элементы должны соответствовать ранее описанному шаблону для сетевых баз:
$i=ubound($array_base)
DO
…
$array_base[$i]="["+$des+"]"
$infos = split($St.Fields("info").Value,chr(13)+chr(10))
$array_base[$i+1]= "Connect="+$infos[0]
$array_base[$i+2]= $infos[1]
$array_base[$i+3]= "OrderInList="
$array_base[$i+4]= $infos[2]
$array_base[$i+5]= "OrderInTree="
$i=$i+6
…
Формирование файловой структуры
Файловая структура формируется внутри каталога «Documents and Settings\%username%Application Data1C1Cv8». Расположение данного каталога на рабочей станции не фиксировано, поэтому для каждого пользователя путь необходимо определять индивидуально с помощью функции:
$path_to_base=CreateObject("WScript.Shell").SpecialFolders(5)+"\1C\1Cv8\"
Определив ID сетевой базы, в том же цикле Do..Loop (см. листинг скрипта на сайте www.samag.ru в разделе «Исходный код»), необходимо создать соответствующую базе файловую структуру.
В каталоге «Documents and Settings\%username%Application Data1C1Cv8» для каждой базы необходимо создать папку, название которой совпадает с ID этой базы, а в нем файл usr.def в кодировке UTF-8 со следующим содержанием: {«У Вас нет доступа. Обратитесь к системному администратору»}. Это сообщение будет появляться в том случае, если у пользователя нет прав доступа к данной базе данных «1С».
…
$id_dir_name=$path_to_base+right( $infos[1],len( $infos[1])-3)
…
md $id_dir_name ; создание каталога
; создание файла def.usr
$FSO = CreateObject("Scripting.FileSystemObject").GetFile($id_dir_name+"\def.usr")
if @error=0
$FSO.Delete
endif
$FSO.close
$Stream = CreateObject("ADODB.Stream")
$Stream.CharSet = "utf-8"
$Stream.Mode = 3
$Stream.Open
$Stream.WriteText("{"+chr(34)+"У Вас нет доступа. Обратитесь к системному администратору."+chr(34)+"}")
$Stream.SaveToFile($id_dir_name+"\def.usr")
$Stream.Close
…
Запись данных в файл
На последнем этапе осуществляется запись сформированных данных в файл. В решении данной задачи есть несколько нюансов: помимо сформированных данных в файле необходимо в него записать информацию, касающуюся каталогов, и обновить нумерацию параметров OrderInList и OrderInTree.
Листинг описания папок для тестовых и локальных баз выглядит следующим образом:
$local_folder = "[Локальные базы]" + $en + "ID=7fa1d5a9-d087-4026-9eea-f18a233d618f" + $en + "OrderInList=-1" + $en + "Folder=/" + $en + "OrderInTree=16384"
$test_folder = "[Тестовые базы]" + $en + "ID=7fa1d5a9-d087-9636-9eea-f18a233d618f" + $en + "OrderInList=-1" + $en + "Folder=/" + $en + "OrderInTree=32768"
ID должен быть уникальным. Каким конкретно? – не известно. Был проведен эксперимент, в результате которого выяснилось, что ID может быть любым. На практике рекомендуется выбрать один из ID, созданных 1C, и изменить одну из его частей произвольным образом.
Из примера видно, что максимальное значение параметра OrderInTree=32768. Ранее отмечалось, что начало нумераций и шаг значений параметров OrderInList и OrderInTree не имеют значения. Этот факт подтвержден многочисленными экспериментами. В качестве начала отсчета были выбраны число 16384 и такой же шаг (заимствовано из «1С»). Для удобства корректировки значений введены два коэффициента $w_1 и $w_2. Один из них управляет значениями OrderInList, а второй – OrderInTree соответственно. При таком способе установки нумерации получится, что в одном из каталогов нумерация параметра OrderInList начнется с одного числа, например, 32768, а в другом – 65536. В каждом из разделов нумерация произвольна и содержимое файла будет корректно считано браузером «1С». Листинг корректировки данных следующий:
$const_w=16384
$w_1=1
$w_2=3
for each $element in $array_base
if instr(ucase($element),ucase("orderintree"))<>0
$s=$s+$element+cstr($const_w*$w_2)+$en
$w_2=$w_2+1
else
if instr(ucase($element),
ucase("orderinlist"))<>0
$s=$s+$element+cstr
($const_w*$w_1)+$en
$w_1=$w_1+1
else
$s=$s+$element+$en
endif
endif
next
После того как все данные к записи приготовлены, можно приступить к записи в файл. В него следует записать содержание трех переменных: две переменные содержат информацию о создаваемых каталогах в браузере «1С», третья – накопленные элементы массива $array_base (переменная s). Напомню, что файл v8ib.lst находится в каталоге «Documents and Settings\%username%Application Data1C1Cv8».
$en=chr(13)+chr(10)
…
$Stream = CreateObject("ADODB.Stream")
$Stream.CharSet = "utf-8"
$Stream.Mode = 3
$Stream.Open
$Stream.WriteText($local_folder+$en+$test_folder+$en+$s)
$Stream.SaveToFile($path_to_base+"v8ib.lst")
$Stream.Close
Таким образом, мы создали компонент сценария регистрации пользователей в сети, который позволил нам в автоматическом режиме управлять подключением сетевых баз данных, при этом локальные базы остаются неприкосновенными. Также выполняется сортировка существующего списка по локальным, сетевым и тестовым базам.
Литература:
- Коробко И. Автоматизация процесса подключения баз «1С» с помощью сценария регистрации пользователей в сети. – Журнал «Системный администратор» №3, 2005 г. – 48-51 с (http://www.samag.ru/cgi-bin/go.pl?q=articles;n=03.2005;a=01).