Тип: Строка. Содержит идентификатор процесса, получившего лицензию, присвоенный ему операционной системой.
Полное описание, параметры и ограничения
АдминистрированиеЛицензия.ИдентификаторПроцесса (AdministrationLicense.ProcessID)
АдминистрированиеЛицензия (AdministrationLicense)
ИдентификаторПроцесса (ProcessID)
Доступен, начиная с версии 8.3.14.
Использование:
Только чтение.
Описание:
Тип: Строка.
Содержит идентификатор процесса, получившего лицензию, присвоенный ему операционной системой.
Доступность:
Тонкий клиент, сервер, толстый клиент, интеграция.
Использование в версии:
Доступен, начиная с версии 8.3.14.
Методическая информация
Практические примеры
Своя административная лицензия: настоящий источник, классификация и два приватных чтения
Цельный собственный RAS-процесс выбирает реальный клиентский сеанс из отдельно подготовленной VM, получает native массив лицензий, классифицирует поля и сравнивает два чтения. Никаких фиктивных UUID/лицензий, установки или доказательства юридической действительности. Изготовлены лишь исходники и статические тесты.
Где и как запускать
Полный модуль обычной формы отдельной файловой CF УчебныеЛицензии85Пульт, только толстый ordinary клиент own VM OWN-LIC85/8.5.1.1343. Actual source — собственный заранее подготовленный RAS и один конкретный target сеанс. Supporting module — отдельно управляемая target форма, client/server declarations точны.
Подготовка
Не выполняйте в рабочей системе. Нужна собственная изолированная Windows VM с сетевым именем OWN-LIC85 и уже подготовленной владельцем разрешённой для этого стенда лицензией. Не клонируйте рабочую VM, не копируйте .lic/PIN и не активируйте/покупайте лицензию ради упражнения. Если законно подготовленного стенда ещё нет, этот урок пока не выполняется; код его не создаёт и не доказывает владение.
Вручную собственный администратор готовит только отдельный сервер/RAS8.5.1.1343 в этой VM: агент15440, менеджер собственного кластера15441, свой диапазон рабочих процессов15600–15610, RAS слушает127.0.0.1:18585 и связан только с данным own агентом. Ни production, ни чужие RAS не подключаются. Один кластер Имя=УчебныеЛицензии85_0f605d14. Existing агентный администратор OwnLicenseAgent85 и отдельный existing кластерный OwnLicenseCluster85 имеют известные только владельцу непустые пароли; подготовьте их вручную до урока, не сохраняйте пароли в исходнике.
В этом выделенном кластере вручную зарегистрируйте одну совершенно новую пустую server-ИБ с регистрационным именем УчебныйКлиентЛицензий85_0f605d14, своей отдельной новой пустой БД и собственной CF УчебныеЛицензии85Клиент. Основной режим управляемый. Никаких каталогов, документов, регистров, extensions, заданий и рабочих modules; лишь обработка УчебныйКлиент85 с основной управляемой формой. Реквизит Состояние85 Строка неограниченная, поле только просмотр. Supporting module ниже вставьте целиком в эту форму, ПриОткрытии(Отказ) назначьте native событию.
В own target-ИБ вручную подготовьте пользователя Лицензии85Клиент с разрешением открыть только свой учебный интерфейс. Запустите на OWN-LIC85 ровно один толстый управляемый клиент данной ИБ с connection Srvr="127.0.0.1:15441";Ref="УчебныйКлиентЛицензий85_0f605d14";, без других частей connection. Loopback предотвращает зависимость от LAN DNS/IP. Собственная форма выполнит чтение серверного номера и останется открытой. Не держите Конфигуратор/второй клиент/фоновые сеансы target-ИБ во время RAS чтений. Не меняйте выдачу лицензий, key manager или режимы получения.
В той же VM вручную создайте новую пустую файловую CF УчебныеЛицензии85Пульт только по C:\1C85_OwnLicenseLab\0f605d14-979e-4970-b5fb-32f18510a40b\Pult. Если точная папка уже занята, не удаляйте/не используйте чужие данные: подготовьте новый собственный стенд и согласованно измените все guards. Основной режим обычный, только одна обработка ПультЛицензий85 с обычной основной формой; бизнес-объектов/расширений/заданий нет. Пульт запускается толстым обычным клиентом, не создавая второй кластерный сеанс.
Форма пульта: UUIDКластера85, UUIDБазы85, UUIDСеанса85, PIDКлиента85 Строка; НомерСеанса85 Число(10,0); ПарольАгента85 и ПарольКластера85 Строка с полями РежимПароля=Да; Отчет85 и Состояние85 Строка неограниченная, большие многострочные поля только просмотра. Не сохраняйте реквизиты/пароли в настройках формы. Main code целиком в модуле ordinary формы; назначьте ПриОткрытии() и ПриЗакрытии() одноимённым событиям. Кнопки ПрочитатьПервыйСнимок85 и СравнитьВтороеЧтение85 — одноимённые native действия с параметром Кнопка.
Откройте только собственную консоль кластера этой VM и вручную скопируйте actual UUID собственного кластера, actual UUID единственной target-ИБ и actual UUID её одного сеанса Лицензии85Клиент в поля пульта. Не подставляйте marker из названия папки вместо actual UUID! НомерСеанса85 возьмите из поддерживающей target-формы и сверяйте с тем же сеансом консоли. В Диспетчере задач собственной VM → Подробности сопоставьте именно её target 1cv8.exe (не пульт/ras/rphost) и скопируйте настоящий OS PID в PIDКлиента85. Номер сеанса, UUID и PID — три разные сущности.
Проверьте глазами соответствие VM/кластера/ИБ/сеанса и заранее разрешённую владельцем лицензию. Введите только свои два пароля непосредственно перед первым чтением. Код аутентифицирует native агент в порядке (Пароль, Имя), native кластер в порядке (Имя, Пароль); все имена/endpoint фиксированы на own стенд. После успеха или отказа поля паролей очищаются, повторное чтение требует нового локального ввода.
#Если ТолстыйКлиентОбычноеПриложение Тогда
Перем ПервыйСнимок85;
Процедура ПриОткрытии()
ПроверитьСвойПустойСтенд();
ПроверитьСвоюVMИПуть85();
ПервыйСнимок85 = Неопределено;
СброситьСвоиПароли85();
Отчет85 = "";
Состояние85 = "Введите actual UUID только своего кластера/ИБ/сеанса и OS PID своего клиента. Лицензия уже подготовлена владельцем стенда; этот урок её не устанавливает.";
КонецПроцедуры
Процедура ПриЗакрытии()
СброситьСвоиПароли85();
ПервыйСнимок85 = Неопределено;
КонецПроцедуры
Процедура ПрочитатьПервыйСнимок85(Кнопка)
Попытка
Снимок = ПрочитатьСвоиЛицензии85();
Исключение
СброситьСвоиПароли85();
Состояние85 = "Чтение прервано. Проверьте собственные UUID, номер/PID клиента, имена/порты, версию и доступ. Ранее показанный результат не заменён. Текст native ошибки не печатаем: он может содержать приватные сведения.";
ВызватьИсключение "Свой первый снимок не получен; это не заключение о действительности лицензии";
КонецПопытки;
СброситьСвоиПароли85();
ПервыйСнимок85 = Снимок;
Отчет85 = Снимок.Отчет;
Состояние85 = "Первое чтение сохранено только в памяти этой формы. Для сравнения снова введите свои два пароля и нажмите СравнитьВтороеЧтение85.";
КонецПроцедуры
Процедура СравнитьВтороеЧтение85(Кнопка)
Попытка
Если ПервыйСнимок85 = Неопределено Тогда
ВызватьИсключение "Сначала нужно первое actual чтение";
КонецЕсли;
ПроверитьСвоиВведенныеИдентификаторы85();
Если НРег(СокрЛП(UUIDКластера85)) <> НРег(Строка(ПервыйСнимок85.КластерUUID))
Или НРег(СокрЛП(UUIDБазы85)) <> НРег(Строка(ПервыйСнимок85.БазаUUID))
Или НРег(СокрЛП(UUIDСеанса85)) <> НРег(Строка(ПервыйСнимок85.СеансUUID)) Тогда
ВызватьИсключение "Второй снимок допускается только для прежних actual UUID";
КонецЕсли;
Второй = ПрочитатьСвоиЛицензии85();
Если Второй.КластерUUID <> ПервыйСнимок85.КластерUUID Или Второй.БазаUUID <> ПервыйСнимок85.БазаUUID
Или Второй.СеансUUID <> ПервыйСнимок85.СеансUUID Тогда
ВызватьИсключение "Actual источник двух чтений различается";
КонецЕсли;
Исключение
СброситьСвоиПароли85();
Состояние85 = "Второе чтение не принято. Первый результат сохранён. Новый/исчезнувший сеанс нельзя подменить первым элементом списка; обновите own идентичность отдельным первым чтением.";
ВызватьИсключение "Свои два чтения не сопоставлены; приватные native подробности не выводятся";
КонецПопытки;
СброситьСвоиПароли85();
Совпало = ПервыйСнимок85.ЗакрытыйОтпечаток = Второй.ЗакрытыйОтпечаток;
Отчет85 = ПервыйСнимок85.Отчет + Символы.ПС + Символы.ПС + "Второе чтение:" + Символы.ПС + Второй.Отчет;
Состояние85 = ?(Совпало, "Считанные наборы значений совпали", "Считанные наборы значений различаются")
+ ". Сравнение касается только двух чтений одного actual сеанса. Это НЕ проверка юридических прав, подписи, действительности лицензии или атомарности диагностики. Закрытые отпечатки не показаны.";
КонецПроцедуры
Процедура СброситьСвоиПароли85()
ПарольАгента85 = "";
ПарольКластера85 = "";
КонецПроцедуры
Процедура ПроверитьСвоюVMИПуть85()
Если ВРег(ИмяКомпьютера()) <> "OWN-LIC85" Тогда
ВызватьИсключение "Только вручную подготовленная собственная VM OWN-LIC85";
КонецЕсли;
Части = СтрРазделить(СтрокаСоединенияИнформационнойБазы(), ";");
Если Части.Количество() <> 1 И Части.Количество() <> 2 Тогда
ВызватьИсключение "Пульт должен быть своей файловой базой с единственным File";
КонецЕсли;
Если Части.Количество() = 2 И СокрЛП(Части[1]) <> "" Тогда
ВызватьИсключение "Параметры после File для собственного пульта не разрешены";
КонецЕсли;
Параметр = СокрЛП(Части[0]);
Если НРег(Лев(Параметр, 5)) <> "file=" Тогда
ВызватьИсключение "Пульт нельзя запускать из рабочего серверного подключения";
КонецЕсли;
Путь = Сред(Параметр, 6);
Если Лев(Путь, 1) = """" И Прав(Путь, 1) = """" Тогда
Путь = Сред(Путь, 2, СтрДлина(Путь) - 2);
КонецЕсли;
Если НРег(Путь) <> НРег("C:\1C85_OwnLicenseLab\0f605d14-979e-4970-b5fb-32f18510a40b\Pult") Тогда
ВызватьИсключение "Нужен exact собственный UUID-путь Pult без относительных путей или завершающего слеша";
КонецЕсли;
КонецПроцедуры
Процедура ПроверитьСвоиВведенныеИдентификаторы85()
Если UUIDКластера85 = "" Или UUIDБазы85 = "" Или UUIDСеанса85 = "" Или НомерСеанса85 <= 0 Тогда
ВызватьИсключение "Сначала скопируйте actual три UUID и номер своего сеанса из собственной консоли";
КонецЕсли;
Если СтрДлина(PIDКлиента85) = 0 Или СтрДлина(PIDКлиента85) > 10 Тогда
ВызватьИсключение "Нужен OS PID собственного target-клиента, не UUID и не номер сеанса";
КонецЕсли;
Для НомерСимвола = 1 По СтрДлина(PIDКлиента85) Цикл
Если СтрНайти("0123456789", Сред(PIDКлиента85, НомерСимвола, 1)) = 0 Тогда
ВызватьИсключение "PID собственного процесса должен содержать только цифры";
КонецЕсли;
КонецЦикла;
Если Число(PIDКлиента85) <= 0 Или Формат(Число(PIDКлиента85), "ЧГ=0;ЧДЦ=0") <> PIDКлиента85 Тогда
ВызватьИсключение "Нужен положительный канонический OS PID из своей VM";
КонецЕсли;
КонецПроцедуры
Функция СвойЛокальныйАдрес85(Адрес)
Возврат НРег(Адрес) = "own-lic85" Или Адрес = "127.0.0.1" Или Адрес = "::1";
КонецФункции
Функция НайтиТолькоСвойСеанс85(Кластер, БазаUUID, СеансUUID)
Сеансы = Кластер.ПолучитьСеансы();
Если ТипЗнч(Сеансы) <> Тип("Массив") Или Сеансы.Количество() <> 1 Тогда
ВызватьИсключение "В выделенном своём кластере разрешён только один собственный target-сеанс";
КонецЕсли;
Сеанс = Сеансы[0];
Если ТипЗнч(Сеанс) <> Тип("АдминистрированиеСеанс") Тогда
ВызватьИсключение "Источник должен быть настоящим native административным сеансом";
КонецЕсли;
Если Сеанс.ИдентификаторИнформационнойБазы <> БазаUUID Или Сеанс.ИдентификаторСеанса <> СеансUUID
Или Сеанс.НомерСеанса <> НомерСеанса85 Или Сеанс.ИмяПользователя <> "Лицензии85Клиент"
Или Не СвойЛокальныйАдрес85(Сеанс.ИмяКомпьютера) Или Не СвойЛокальныйАдрес85(Сеанс.IPАдресКлиента)
Или Сеанс.ИмяПриложения <> "1CV8" Тогда
ВызватьИсключение "Actual сеанс не совпал со своей ИБ/UUID/номером/user/VM/толстым target-клиентом";
КонецЕсли;
Возврат Сеанс;
КонецФункции
Функция ПрочитатьСвоиЛицензии85()
ПроверитьСвойПустойСтенд();
ПроверитьСвоюVMИПуть85();
ПроверитьСвоиВведенныеИдентификаторы85();
Если ПарольАгента85 = "" Или ПарольКластера85 = "" Тогда
ВызватьИсключение "Два существующих собственных администратора требуют непустые пароли; пустую auth не пробуем";
КонецЕсли;
КластерUUID = Новый УникальныйИдентификатор(СокрЛП(UUIDКластера85));
БазаUUID = Новый УникальныйИдентификатор(СокрЛП(UUIDБазы85));
СеансUUID = Новый УникальныйИдентификатор(СокрЛП(UUIDСеанса85));
Начало = ТекущаяДата();
Агент = Новый АдминистрированиеСервера("127.0.0.1", 18585);
Если Агент.ПолучитьВерсию() <> "8.5.1.1343" Тогда
ВызватьИсключение "Own RAS endpoint должен относиться к серверу8.5.1.1343";
КонецЕсли;
Агент.ВыполнитьАутентификацию(ПарольАгента85, "OwnLicenseAgent85");
Кластеры = Агент.ПолучитьКластеры();
Если ТипЗнч(Кластеры) <> Тип("Массив") Или Кластеры.Количество() <> 1 Тогда
ВызватьИсключение "Отдельный endpoint обязан иметь только один свой кластер";
КонецЕсли;
Кластер = Кластеры[0];
Если ТипЗнч(Кластер) <> Тип("АдминистрированиеКластер") Или Кластер.ИдентификаторКластера <> КластерUUID
Или Кластер.Имя <> "УчебныеЛицензии85_0f605d14" Или Кластер.Порт <> 15441
Или Не СвойЛокальныйАдрес85(Кластер.ИмяКомпьютера) Тогда
ВызватьИсключение "Actual кластер не совпал с exact own UUID/name/host/port";
КонецЕсли;
Кластер.ВыполнитьАутентификацию("OwnLicenseCluster85", ПарольКластера85);
Базы = Кластер.ПолучитьИнформационныеБазы();
Если ТипЗнч(Базы) <> Тип("Массив") Или Базы.Количество() <> 1 Тогда
ВызватьИсключение "В выделенном кластере должна быть только одна своя новая пустая target-ИБ";
КонецЕсли;
База = Базы[0];
Если ТипЗнч(База) <> Тип("АдминистрированиеИнформационнаяБаза") Или База.ИдентификаторИнформационнойБазы <> БазаUUID
Или База.Имя <> "УчебныйКлиентЛицензий85_0f605d14" Тогда
ВызватьИсключение "Actual target-ИБ не совпала со своим UUID и регистрационным именем";
КонецЕсли;
Сеанс = НайтиТолькоСвойСеанс85(Кластер, БазаUUID, СеансUUID);
Процессы = Кластер.ПолучитьРабочиеПроцессы();
Если ТипЗнч(Процессы) <> Тип("Массив") Тогда
ВызватьИсключение "Native список рабочих процессов должен быть массивом";
КонецЕсли;
СвойПроцесс = Неопределено;
Для Каждого Процесс Из Процессы Цикл
Если ТипЗнч(Процесс) <> Тип("АдминистрированиеРабочийПроцесс") Или Не СвойЛокальныйАдрес85(Процесс.ИмяКомпьютера) Тогда
ВызватьИсключение "Рабочие процессы должны принадлежать только собственной VM";
КонецЕсли;
Если Процесс.ИдентификаторРабочегоПроцесса = Сеанс.ИдентификаторПроцесса Тогда
Если СвойПроцесс <> Неопределено Тогда
ВызватьИсключение "Actual UUID рабочего процесса оказался неоднозначным";
КонецЕсли;
СвойПроцесс = Процесс;
КонецЕсли;
КонецЦикла;
Если СвойПроцесс = Неопределено Или Не СвойПроцесс.Активен Тогда
ВызватьИсключение "Связанный actual рабочий процесс уже не найден/не активен";
КонецЕсли;
Лицензии = Сеанс.Лицензии;
Если ТипЗнч(Лицензии) <> Тип("Массив") Тогда
ВызватьИсключение "Native Лицензии своего сеанса должны быть массивом";
КонецЕсли;
Строки = Новый Массив;
Строки.Добавить("Client-license чтение: " + Формат(Начало, "ДФ=yyyy-MM-dd HH:mm:ss"));
Строки.Добавить("Actual UUID сеанса: " + Строка(Сеанс.ИдентификаторСеанса));
Строки.Добавить("Элементов административных сведений: " + Строка(Лицензии.Количество()) + ". Это НЕ число свободных лицензий.");
Отпечатки = Новый ТаблицаЗначений;
Отпечатки.Колонки.Добавить("Отпечаток", Новый ОписаниеТипов("Строка"));
Номер = 0;
Для Каждого Лицензия Из Лицензии Цикл
Если ТипЗнч(Лицензия) <> Тип("АдминистрированиеЛицензия") Тогда
ВызватьИсключение "Реальный элемент native Лицензии имеет другой тип; подмену/искусственный ctor не используем";
КонецЕсли;
Адрес = Лицензия.АдресСервера;
PID = Лицензия.ИдентификаторПроцесса;
ФайлЛицензии = Лицензия.ИмяФайла;
Краткое = Лицензия.КраткоеПредставление;
Максимум = Лицензия.МаксимальноеКоличествоПользователей;
МаксимумКомплекта = Лицензия.МаксимальноеКоличествоПользователейПрограммнойЛицензии;
Подробное = Лицензия.ПодробноеПредставление;
ОтСервера = Лицензия.ПолученаСервером;
Порт = Лицензия.ПортСервера;
Программная = Лицензия.ПрограммнаяЛицензия;
Серия = Лицензия.СерияКлюча;
Сетевая = Лицензия.СетевойКлюч;
Для Каждого Текст Из Новый Структура("Адрес,PID,Файл,Краткое,Подробное,Серия", Адрес, PID, ФайлЛицензии, Краткое, Подробное, Серия) Цикл
Если ТипЗнч(Текст.Значение) <> Тип("Строка") Или СтрДлина(Текст.Значение) > 1000000 Тогда
ВызватьИсключение "Неожиданный тип/размер native строк; приватные значения не выводятся";
КонецЕсли;
КонецЦикла;
Если ТипЗнч(Максимум) <> Тип("Число") Или ТипЗнч(МаксимумКомплекта) <> Тип("Число") Или ТипЗнч(Порт) <> Тип("Число")
Или ТипЗнч(ОтСервера) <> Тип("Булево") Или ТипЗнч(Программная) <> Тип("Булево") Или ТипЗнч(Сетевая) <> Тип("Булево") Тогда
ВызватьИсключение "Native numeric/bool поля не совпали с документированными типами";
КонецЕсли;
Номер = Номер + 1;
Вид = ?(Программная, "программная", ?(Сетевая, "аппаратная, сетевой ключ через Aladdin License Manager", "аппаратная, без признака сетевого ключа"));
Источник = ?(ОтСервера, "получена сервером 1С и выдана клиенту", "получена клиентским приложением");
Сопоставление = "PID не сопоставлен с выбранным собственным процессом; это не признак недействительности";
Если ОтСервера Тогда
Если PID = СвойПроцесс.ИдентификаторПроцесса И СвойЛокальныйАдрес85(Адрес) Тогда
Сопоставление = "PID/host совпали с OS PID связанного own рабочего процесса; UUID процесса для этого не использовался";
КонецЕсли;
ИначеЕсли PID = PIDКлиента85 И СвойЛокальныйАдрес85(Адрес) Тогда
Сопоставление = "PID/host совпали с вручную подтверждённым собственным клиентским OS PID";
КонецЕсли;
Предупреждения = Новый Массив;
Если Не Программная И МаксимумКомплекта <> Максимум Тогда
Предупреждения.Добавить("Для аппаратной лицензии справка описывает равные MaxUsers/MaxSoftwareLicenseUsers; здесь они различаются. Повторите собственное чтение, не объявляйте юридический результат.");
КонецЕсли;
Если Программная И Сетевая Тогда
Предупреждения.Добавить("NetworkKey относится к аппаратному ключу; SoftwareLicense/NetworkKey требуют отдельного наблюдения, не локализованного string parsing.");
КонецЕсли;
Если Максимум < 0 Или МаксимумКомплекта < 0 Или Порт < 0 Или Порт > 65535 Тогда
Предупреждения.Добавить("Численные поля неожиданны для этого стенда; это только диагностическое предупреждение.");
КонецЕсли;
Строки.Добавить("Элемент " + Строка(Номер) + ": " + Вид + "; " + Источник);
Строки.Добавить("Предел используемого ключа/файла=" + Строка(Максимум)
+ "; предел программного комплекта=" + Строка(МаксимумКомплекта) + ". Это НЕ свободные места и не число текущих пользователей.");
Строки.Добавить(Сопоставление);
Строки.Добавить("Адрес получения: " + ?(СвойЛокальныйАдрес85(Адрес), "собственный локальный", "не сопоставлен; никуда не подключаемся")
+ "; reported IP-порт=" + Строка(Порт) + ". Порт0 сам по себе не объявляется ошибкой клиента.");
Строки.Добавить("FileName скрыт; заполнен=" + Строка(ФайлЛицензии <> "") + "; серия/регномер скрыты; заполнены=" + Строка(Серия <> ""));
Строки.Добавить("Локализованные представления скрыты; краткое заполнено=" + Строка(Краткое <> "")
+ ", длина=" + Строка(СтрДлина(Краткое)) + "; подробное заполнено=" + Строка(Подробное <> "") + ", длина=" + Строка(СтрДлина(Подробное)));
Если Предупреждения.Количество() > 0 Тогда
Строки.Добавить(СтрСоединить(Предупреждения, Символы.ПС));
КонецЕсли;
ПоляОтпечатка = Новый Массив;
Для Каждого Пара Из Новый Структура("Адрес,PID,Файл,Краткое,Максимум,МаксимумКомплекта,Подробное,ОтСервера,Порт,Программная,Серия,Сетевая",
Адрес, PID, ФайлЛицензии, Краткое, Максимум, МаксимумКомплекта, Подробное, ОтСервера, Порт, Программная, Серия, Сетевая) Цикл
ПоляОтпечатка.Добавить(Строка(Пара.Значение));
КонецЦикла;
Отпечатки.Добавить().Отпечаток = ЗакрытыйОтпечатокСвоихЗначений85(ПоляОтпечатка);
КонецЦикла;
Повторный = НайтиТолькоСвойСеанс85(Кластер, БазаUUID, СеансUUID);
Если Повторный.ИдентификаторПроцесса <> Сеанс.ИдентификаторПроцесса Тогда
ВызватьИсключение "Привязка actual сеанса к рабочему UUID изменилась между чтениями; предыдущий отчёт сохраняется";
КонецЕсли;
Если Лицензии.Количество() = 0 Тогда
Строки.Добавить("Список пуст. Native сведения о клиентской лицензии не получены; никакой фиктивный элемент не создаётся и юридический вывод не делается.");
КонецЕсли;
Отпечатки.Сортировать("Отпечаток");
СписокОтпечатков = Новый Массив;
Для Каждого СтрокаОтпечатка Из Отпечатки Цикл
СписокОтпечатков.Добавить(СтрокаОтпечатка.Отпечаток);
КонецЦикла;
ЗакрытыйОтпечаток = ЗакрытыйОтпечатокСвоихЗначений85(СписокОтпечатков);
Строки.Добавить("Чтение завершено: " + Формат(ТекущаяДата(), "ДФ=yyyy-MM-dd HH:mm:ss") + ". Это не атомарный snapshot сервера.");
Возврат Новый Структура("КластерUUID,БазаUUID,СеансUUID,ЗакрытыйОтпечаток,Отчет", Кластер.ИдентификаторКластера,
База.ИдентификаторИнформационнойБазы, Сеанс.ИдентификаторСеанса, ЗакрытыйОтпечаток, СтрСоединить(Строки, Символы.ПС));
КонецФункции
Функция ЗакрытыйОтпечатокСвоихЗначений85(Значения)
Хеш = Новый ХешированиеДанных(ХешФункция.SHA256);
Для Каждого Текст Из Значения Цикл
Хеш.Добавить(Формат(СтрДлина(Текст), "ЧГ=0;ЧДЦ=0") + ":" + Текст);
КонецЦикла;
Возврат Base64Строка(Хеш.ХешСумма);
КонецФункции
Процедура ПроверитьСвойПустойСтенд()
Если Метаданные.Справочники.Количество() <> 0 Или Метаданные.Документы.Количество() <> 0 Или Метаданные.Перечисления.Количество() <> 0 Или Метаданные.РегистрыСведений.Количество() <> 0 Или Метаданные.РегистрыНакопления.Количество() <> 0 Или Метаданные.РегистрыБухгалтерии.Количество() <> 0 Или Метаданные.РегистрыРасчета.Количество() <> 0 Или Метаданные.ПланыВидовХарактеристик.Количество() <> 0 Или Метаданные.ПланыВидовРасчета.Количество() <> 0 Или Метаданные.ПланыСчетов.Количество() <> 0 Или Метаданные.ПланыОбмена.Количество() <> 0 Или Метаданные.Последовательности.Количество() <> 0 Или Метаданные.БизнесПроцессы.Количество() <> 0 Или Метаданные.Задачи.Количество() <> 0 Или Метаданные.ОбщиеРеквизиты.Количество() <> 0 Или Метаданные.ПодпискиНаСобытия.Количество() <> 0 Или Метаданные.РегламентныеЗадания.Количество() <> 0 Или Метаданные.ВнешниеИсточникиДанных.Количество() <> 0 Тогда
ВызватьИсключение "Нужен только свой новый пустой учебный стенд";
КонецЕсли;
Если Метаданные.ЕстьИзмененияРасширениямиКонфигурации() Тогда
ВызватьИсключение "Свой сеанс не должен изменяться расширениями";
КонецЕсли;
Источники = Новый Массив;
Источники.Добавить(ИсточникРасширенийКонфигурации.БазаДанных);
Источники.Добавить(ИсточникРасширенийКонфигурации.СеансАктивные);
Источники.Добавить(ИсточникРасширенийКонфигурации.СеансОтключенные);
Для Каждого Источник Из Источники Цикл
Расширения = РасширенияКонфигурации.Получить(, Источник);
Если ТипЗнч(Расширения) <> Тип("Массив") Тогда
ВызватьИсключение "Native список расширений должен иметь тип Массив";
КонецЕсли;
Если Расширения.Количество() <> 0 Тогда
ВызватьИсключение "В своём новом стенде нет расширений базы или сеанса";
КонецЕсли;
КонецЦикла;
Если ТранзакцияАктивна() Тогда
ВызватьИсключение "Чужая или вложенная активная транзакция не допускается";
КонецЕсли;
КонецПроцедуры
#КонецЕслиПолный модуль своего толстого управляемого target-клиента: настоящий номер серверного сеанса
Своя CF УчебныеЛицензии85Клиент → Обработка УчебныйКлиент85 → Основная управляемая форма → модуль формы. Native ПриОткрытии(Отказ); серверный вызов без контекста только читает проверенный собственный сеанс.
Самостоятельная управляемая форма собственных target-ИБ и пользователя; клиентское ПриОткрытии(Отказ) и серверные процедуры компилируются в отдельных native контекстах. Никаких административных вызовов в этом модуле.
#Если ТолстыйКлиентУправляемоеПриложение Или Сервер Тогда
&НаКлиенте
Процедура ПриОткрытии(Отказ)
Если ВРег(ИмяКомпьютера()) <> "OWN-LIC85" Тогда
Отказ = Истина;
ВызватьИсключение "Только собственный target-клиент в VM OWN-LIC85";
КонецЕсли;
Номер = ПроверитьСвойСерверныйСеанс85();
Состояние85 = "Собственный target-клиент. Номер сеанса=" + Строка(Номер)
+ ". Это НЕ UUID сеанса и НЕ OS PID. Оставьте форму открытой, сопоставьте UUID в своей консоли RAS, PID собственного 1cv8.exe вручную в Диспетчере задач.";
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПроверитьСвойСерверныйСеанс85()
ПроверитьСвойПустойСтенд();
Если ВРег(ИмяКомпьютера()) <> "OWN-LIC85" Или ИмяПользователя() <> "Лицензии85Клиент" Тогда
ВызватьИсключение "Свой серверный сеанс должен принадлежать VM и target-пользователю";
КонецЕсли;
Части = СтрРазделить(СтрокаСоединенияИнформационнойБазы(), ";");
Если Части.Количество() <> 2 И Части.Количество() <> 3 Тогда
ВызватьИсключение "Target connection содержит только один Srvr и один Ref";
КонецЕсли;
СерверНайден = Ложь;
БазаНайдена = Ложь;
Для Каждого Часть Из Части Цикл
Параметр = СокрЛП(Часть);
Если НРег(Параметр) = "srvr=""127.0.0.1:15441""" Тогда
Если СерверНайден Тогда
ВызватьИсключение "Повторный Srvr не допускается";
КонецЕсли;
СерверНайден = Истина;
ИначеЕсли НРег(Параметр) = "ref=""учебныйклиентлицензий85_0f605d14""" Тогда
Если БазаНайдена Тогда
ВызватьИсключение "Повторный Ref не допускается";
КонецЕсли;
БазаНайдена = Истина;
ИначеЕсли Параметр <> "" Тогда
ВызватьИсключение "Target connection должна содержать только точные собственные Srvr/Ref";
КонецЕсли;
КонецЦикла;
Если Не СерверНайден Или Не БазаНайдена Тогда
ВызватьИсключение "Target-клиент подключён не к exact собственному серверу/имени ИБ";
КонецЕсли;
Возврат НомерСеансаИнформационнойБазы();
КонецФункции
&НаСервереБезКонтекста
Процедура ПроверитьСвойПустойСтенд()
Если Метаданные.Справочники.Количество() <> 0 Или Метаданные.Документы.Количество() <> 0 Или Метаданные.Перечисления.Количество() <> 0 Или Метаданные.РегистрыСведений.Количество() <> 0 Или Метаданные.РегистрыНакопления.Количество() <> 0 Или Метаданные.РегистрыБухгалтерии.Количество() <> 0 Или Метаданные.РегистрыРасчета.Количество() <> 0 Или Метаданные.ПланыВидовХарактеристик.Количество() <> 0 Или Метаданные.ПланыВидовРасчета.Количество() <> 0 Или Метаданные.ПланыСчетов.Количество() <> 0 Или Метаданные.ПланыОбмена.Количество() <> 0 Или Метаданные.Последовательности.Количество() <> 0 Или Метаданные.БизнесПроцессы.Количество() <> 0 Или Метаданные.Задачи.Количество() <> 0 Или Метаданные.ОбщиеРеквизиты.Количество() <> 0 Или Метаданные.ПодпискиНаСобытия.Количество() <> 0 Или Метаданные.РегламентныеЗадания.Количество() <> 0 Или Метаданные.ВнешниеИсточникиДанных.Количество() <> 0 Тогда
ВызватьИсключение "Нужен только свой новый пустой учебный стенд";
КонецЕсли;
Если Метаданные.ЕстьИзмененияРасширениямиКонфигурации() Тогда
ВызватьИсключение "Свой сеанс не должен изменяться расширениями";
КонецЕсли;
Источники = Новый Массив;
Источники.Добавить(ИсточникРасширенийКонфигурации.БазаДанных);
Источники.Добавить(ИсточникРасширенийКонфигурации.СеансАктивные);
Источники.Добавить(ИсточникРасширенийКонфигурации.СеансОтключенные);
Для Каждого Источник Из Источники Цикл
Расширения = РасширенияКонфигурации.Получить(, Источник);
Если ТипЗнч(Расширения) <> Тип("Массив") Тогда
ВызватьИсключение "Native список расширений должен иметь тип Массив";
КонецЕсли;
Если Расширения.Количество() <> 0 Тогда
ВызватьИсключение "В своём новом стенде нет расширений базы или сеанса";
КонецЕсли;
КонецЦикла;
Если ТранзакцияАктивна() Тогда
ВызватьИсключение "Чужая или вложенная активная транзакция не допускается";
КонецЕсли;
КонецПроцедуры
#КонецЕслиРазбор по шагам
Own guard останавливает чужую CF/VM/connection и неверную версию ещё до RAS. Кластер, ИБ и сеанс выбираются только из настоящих native списков; одиночность не заменяет проверки exact actual UUID/name/host/port/user/номер/тип приложения. Отсутствие или лишний объект означает отказ, не выбор первого доступного чужого элемента.
Клиентская лицензия приходит именно из Сеанс.Лицензии. Native страница АдминистрированиеЛицензия приводит этот RAS-маршрут. У типа нет конструктора; каждый actual элемент массива проверяется на этот тип. Пустой массив — отдельный честный результат без фиктивного примера или вывода о действительности.
Связь рабочего процесса определяется UUID сеанса ИдентификаторПроцесса → рабочего процесса ИдентификаторРабочегоПроцесса. После этого его ИдентификаторПроцесса — уже Строка OS PID. С PID лицензии сравнивается только OS PID: вручную подтверждённый клиентский либо связанный серверный. Возможный другой серверный процесс получения лицензии не объявляется чужим или недействительным только из-за несовпадения с rphost.
Все 12 native readonly полей сначала считываются из actual элемента в память с проверкой документированных типов. SoftwareLicense классифицирует программную/аппаратную лицензию; NetworkKey имеет смысл аппаратного сетевого Aladdin-ключа. RetrievedByServer отделяет полученную сервером и выданную клиенту лицензию от полученной клиентским приложением.
MaxUsers — предел используемого ключа или файла, MaxSoftwareLicenseUsers — предел программного комплекта, а для аппаратного должен совпадать с первым по справке. Ни количество сведений в массиве, ни эти два предела не являются свободными местами/текущими пользователями. Неожиданное сочетание — диагностическое предупреждение, не юридический вердикт.
АдресСервера и ПортСервера относятся к процессу получения лицензии, не автоматически к RAS18585 или manager15441. Для несопоставленного адреса выводится только эта классификация: никакого подключения к нему. Порт0 у client-полей сам по себе не объявляется ошибкой. Raw адрес/PID/путь/серия в отчёт не попадают.
FileName и KeySeries не выводятся: отчёт показывает только заполненность. Brief/DetailedPresentation локализованы и могут содержать приватные данные; выводятся лишь заполненность/длина, без разбора по строковым словам, regex или отображения полного значения. PIN никогда не читается и не требуется.
Для каждого набора 12 полей рассчитывается private SHA256 с длиной каждого добавленного значения перед текстом. Множество элементов сортируется по private отпечаткам с сохранением повторов; набор сравнивается независимо от порядка массива. Ни raw поля, ни отпечатки не сериализуются и не печатаются, сохраняется только private память формы.
Непосредственно после чтения повторно ищется тот же native сеанс; исчезнувший сеанс или изменившийся рабочий UUID прерывает принятие результата. Это не блокировка сервера, не лицензирующая транзакция и не доказательство атомарности набора readonly getter.
ПрочитатьПервыйСнимок85 сохраняет только первый private fingerprint и безопасный отчёт. СравнитьВтороеЧтение85 создаёт новый native acquisition того же actual кластера/ИБ/сеанса и реально читает лицензии снова. Результат — совпали/различаются значения двух наблюдений, НЕ проверена юридическая действительность/подпись/право владения. Ошибка оставляет старый отчёт, очищает пароли и не печатает native exception с возможными приватными деталями.
Как проверить результат
Отчёт показывает реальный вид/источник получения, два разных предела и masked presence/length каждого строкового поля; точные номера регистрации, файл лицензии и локализованные представления отсутствуют.
Сверьте сами в приватной консоли только выбранного собственного сеанса: software/hardware/network, client/server получение и capacity соответствуют native полям. Raw private значения никому не пересылайте.
Два последовательных чтения одного незаменённого собственного сеанса могут совпасть или различаться по реальным live данным. Оба исхода корректны; равенство не доказывает атомарность или validity, различие не объявляется дефектом лицензии.
Негативные безопасные проверки своего стенда: пустой пароль/UUID, вместо actual UUID ввести короткий номер сеанса, закрыть свой target-клиент до второго чтения. Пульт должен отказаться, сохранив предыдущий отчёт. Только если native ПолученаСервером=Ложь, отдельно введите собственный PID пульта вместо target-клиента: ожидается PID не сопоставлен. При server issuance сопоставляется серверный PID и этот клиентский PID не используется как доказательство. Чужую лицензию не подключайте ради теста.
Повторное чтение после нового сеанса требует отдельно скопировать его actual UUID и выполнить первое чтение, а не подменить старый. При нуле native license элементов выводится пустой список, не выдуманный объект.
Сверьте supporting target номер с консолью: это номер сеанса, не PID/UUID. Номер и client application1CV8 относятся к выбранному собственному толстому управляемому target-клиенту, не к обычному файловому пульту.
Ожидаемый результат
Собственный административный отчёт классифицирует actual сведения одной учебной клиентской лицензии/набора и безопасно сопоставляет два наблюдения одного настоящего сеанса, не устанавливая и не меняя лицензии.
На что обратить внимание
Все административные вызовы в примере — future manual код для собственного стенда. Автор не запускал RAS/COM/системные вызовы/1С/сеть или установку лицензий; выполнялись лишь source authoring и статические тесты. Root/config/production read-only, новых backups/archives нет.
Юридические права и разрешённое использование подтверждает владелец стенда вне программы. Getter, лицензия в массиве, PID совпадение и SHA256 fingerprint этого не доказывают. Эта программа не проверяет файл .lic, подпись или истечение срока.
АдминистрированиеРабочийПроцесс.Лицензии описывает серверные лицензии процесса, а Сеанс.Лицензии — клиентские лицензии сеанса. Здесь применяется именно второй источник; считать массивы взаимозаменяемыми нельзя.
Все свойства АдминистрированиеЛицензия readonly. PID лицензии — Строка OS PID; UUID сеанса/рабочего процесса — УникальныйИдентификатор. Нельзя выдумывать UUID, присваивать fields или напрямую сравнивать эти разные домены.
Repeated native reads неатомарны. Проверка неизменной идентичности в конце уменьшает очевидное устаревание, но не доказывает одновременность всех полей или отсутствие событий между чтениями.
Full Detailed/BriefPresentation и KeySeries/FileName могут раскрыть private сведения. Даже hash не является шифрованием/доказательством владения; здесь он private только для сравнения и не публикуется.
Пульт не сохраняет файлы/JSON, не открывает .lic, не получает PIN/регистрационный secret и не выполняет лицензирующие mutation. Для неизвестного адреса ничего не подключается. Не адаптируйте этот пример для сбора лицензий рабочего общего кластера.
Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.