При работе с торговым оборудованием (сканеры штрихкодов, эквайринговые терминалы, ККТ) и настройками рабочих мест часто возникает необходимость точно определить, где именно запущен клиент 1С. Встроенная функция платформы ИмяКомпьютера() в среде удаленных рабочих столов (RDP) или RemoteApp всегда возвращает имя сервера, а не клиентской машины. Из-за этого платформа не может разграничить настройки оборудования для разных пользователей, подключающихся к одному терминальному серверу, что приводит к ошибкам вида «Устройство уже занято».
Рассмотрим, как с помощью кода 1С запросить у операционной системы сведения о сеансе и корректно отличить физический запуск от удаленного (терминального).
Проанализируем стандартное поведение платформы: функция ИмяКомпьютера() опрашивает имя хоста, на котором выполняется клиентский процесс. Если пользователь заходит на терминальный сервер (или запускает 1С через RemoteApp), процесс 1cv8.exe физически выполняется на сервере. Соответственно, ИмяКомпьютера() вернет сетевое имя терминального сервера как для локального администратора, сидящего за консолью сервера, так и для всех удаленных пользователей.
Чтобы разделить настройки оборудования и рабочие места пользователей, нам необходимо обратиться к переменным окружения операционной системы Windows.
При создании удаленного сеанса Windows автоматически формирует специфические переменные среды процесса:
Console, а для удаленных пользователей — имеет вид RDP-Tcp#0 или аналогичный.Для считывания этих системных переменных из 1С мы можем использовать COM-объект WScript.Shell.
Рассмотрим базовая пример получения переменной окружения CLIENTNAME с помощью обращения к окружению процесса:
WSS = Новый COMОбъект("WScript.Shell");
WSSE = WSS.Environment("Process");
ИмяКлиентскогоПК = ВРег(WSSE.Item("ClientName"));
Если ПустаяСтрока(ИмяКлиентскогоПК) Или ИмяКлиентскогоПК = "CONSOLE" Тогда
// Запуск произведен локально на сервере или в консольной сессии
ИмяРабочегоМеста = ВРег(ИмяКомпьютера());
Иначе
// Сеанс запущен через RDP / RemoteApp
ИмяРабочегоМеста = ВРег(ИмяКомпьютера()) + "_" + ИмяКлиентскогоПК;
КонецЕсли;
Также проанализируем альтернативный метод expandEnvironmentStrings, который позволяет безопасно разворачивать подстановки переменных среды:
WshShell = Новый COMОбъект("WScript.Shell");
ИмяКомпьютераКлиента = WshShell.expandEnvironmentStrings("%CLIENTNAME%");
ИмяСессии = WshShell.expandEnvironmentStrings("%SESSIONNAME%");
Если ВРег(ИмяСессии) = "CONSOLE" Или ИмяКомпьютераКлиента = "%CLIENTNAME%" Тогда
// Физический запуск на локальной машине
ИмяРабочегоМеста = ИмяКомпьютера();
Иначе
// Удаленный терминальный сеанс
ИмяРабочегоМеста = ИмяКомпьютера() + "_" + ИмяКомпьютераКлиента;
КонецЕсли;
Объединим проверки в отказоустойчивую функцию с обработкой исключений. Это гарантирует, что даже при отсутствии COM-объекта в операционной системе (или при специфических правах доступа) программа не завершится с ошибкой.
Функция ПолучитьУникальноеИмяРабочегоМеста() Экспорт
СформированноеИмя = ВРег(ИмяКомпьютера());
ИмяКлиентаRDP = "";
Попытка
WshShell = Новый COMОбъект("WScript.Shell");
ИмяКлиентаRDP = WshShell.expandEnvironmentStrings("%CLIENTNAME%");
Исключение
ИмяКлиентаRDP = "";
КонецПопытки;
ИмяКлиентаRDP = ВРег(СокрЛП(ИмяКлиентаRDP));
// Проверяем, что переменная вернула корректное имя, а не исходный шаблон %CLIENTNAME% и не CONSOLE
Если ЗначениеЗаполнено(ИмяКлиентаRDP)
И НЕ ИмяКлиентаRDP = "%CLIENTNAME%"
И НЕ ИмяКлиентаRDP = "CONSOLE" Тогда
// Формируем составное имя: ИмяТерминальногоСервера_ИмяКлиентскогоПК
СформированноеИмя = СформированноеИмя + "_" + ИмяКлиентаRDP;
КонецЕсли;
Возврат СформированноеИмя;
КонецФункции
При внедрении данного решения обратите внимание на следующие нюансы:
COMОбъект("WScript.Shell") работает исключительно в ОС Windows на стороне клиента (контекст &НаКлиенте). На клиентах под управлением Linux, macOS, а также при работе через веб-клиент COM-объекты недоступны.1CV8SERVER, а не сеанса пользователя.GetSystemMetrics(SM_REMOTESESSION). Однако в современных ОС (Windows Server 2012 и новее) при включенном RemoteFX vGPU данный параметр может возвращать 0 даже для удаленных сеансов. По этой причине проверка переменных среды CLIENTNAME и SESSIONNAME является более надежным способом./C (например, 1cv8.exe ... /C TerminalUser) и считывать его на старте программы функцией ПараметрЗапуска.