Как в 1С программно выполнить ping, получить IP-адрес и избежать проблем с кодировкой и всплывающими окнами?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

При разработке механизмов мониторинга сетевых узлов или интеграции с оборудованием (например, онлайн-кассами) программисты часто сталкиваются с необходимостью проверить доступность компьютера по его имени и узнать его актуальный IP-адрес. Стандартный подход с использованием команды ping.exe через WScript.Shell часто преподносит неприятные сюрпризы: появление «черных окон» консоли и нечитаемый текст («кракозябры») в результатах ответа. В этой статье мы подробно разберем, как решить эти проблемы и какие методы являются наиболее надежными.

Проблема кодировки и «кракозябр» в ответе ping

Когда мы запускаем внешнюю программу через объект WScript.Shell методом Exec, операционная система перехватывает текстовый поток StdOut. Проблема заключается в том, что консоль Windows по умолчанию использует OEM-кодировку (для русской Windows это CP866), в то время как 1С работает с кодировкой Unicode. В результате вместо текста «Ответ от...» мы видим нечитаемый набор символов.

Рассмотрим вариант решения этой проблемы путем принудительной смены кодировки в потоке выполнения. Проанализируем пример кода, который позволяет переключить кодовую страницу консоли на 1251 (Windows-1251) или 1252 прямо во время сессии:


WshShell = Новый COMОбъект("WScript.Shell");
// Запускаем оболочку cmd в тихом режиме
WshExec = WshShell.Exec("cmd.exe /q /k echo off");
// Отправляем команду смены кодировки в стандартный ввод
WshExec.StdIn.WriteLine("chcp 1251>nul");
// Выполняем пинг
WshExec.StdIn.WriteLine("ping.exe -n 1 " + ИмяКомпьютера);
// Завершаем работу оболочки
WshExec.StdIn.WriteLine("exit");

// Читаем результат, который теперь будет в читаемом виде
РезультатТекст = WshExec.StdOut.ReadAll();
Сообщить(РезультатТекст);

Хотя этот метод решает вопрос с текстом, у него остается существенный минус: при использовании Exec на экране пользователя на мгновение мелькает черное окно командной строки. Это может раздражать пользователей при частых проверках.

Оптимальное решение: использование WMI (Win32_PingStatus)

Выясним, можно ли выполнить проверку сети вообще без запуска внешних программ вроде ping.exe. Да, для этого идеально подходит инструментарий WMI (Windows Management Instrumentation). Этот метод работает «тихо», не создает окон, не зависит от локализации системы и сразу возвращает структурированные данные.

Разберем по шагам реализацию функции проверки через WMI:

  1. Подключаемся к сервису WMI локальной машины.
  2. Выполняем запрос к классу Win32_PingStatus, передавая адрес целевого узла.
  3. Анализируем свойство StatusCode: если оно равно 0, значит, узел доступен.
  4. Извлекаем свойство ProtocolAddress, чтобы получить IP-адрес.

Посмотрим на пример реализации такой функции:


Функция ПроверитьДоступностьУзла(ИмяКомпьютера, IP_Адрес) Экспорт
    
    // Подключаемся к WMI
    Попытка
        Локатор = Новый COMОбъект("WbemScripting.SWbemLocator");
        СервисWMI = Локатор.ConnectServer(".", "root\cimv2");
    Исключение
        Возврат Ложь;
    КонецПопытки;
    
    // Формируем запрос. Параметр ResolveAddressNames позволяет получить IP по имени
    Запрос = "Select * From Win32_PingStatus Where Address = '" + ИмяКомпьютера + "' And ResolveAddressNames = True";
    Результаты = СервисWMI.ExecQuery(Запрос);
    
    ПингУспешен = Ложь;
    Для Каждого ОбъектСтатуса Из Результаты Цикл
        // StatusCode = 0 означает успешный ответ (Success)
        Если ОбъектСтатуса.StatusCode = 0 Тогда
            IP_Адрес = ОбъектСтатуса.ProtocolAddress; // Получаем чистый IP-адрес
            ПингУспешен = Истина;
            Прервать;
        КонецЕсли;
    КонецЦикла;
    
    Возврат ПингУспешен;
    
КонецФункции

Важный момент: Обратите внимание на использование ProtocolAddress вместо ProtocolAddressResolved. Как показала практика, первое свойство надежнее возвращает именно строковое представление IP-адреса (например, "192.168.1.10").

Использование метода Run для скрытого запуска

Если вам все же необходимо использовать именно системную утилиту ping (например, из-за специфических настроек прав доступа к WMI), но вы хотите скрыть окно, следует использовать метод Run объекта WScript.Shell. У него есть второй параметр, отвечающий за стиль окна (0 — скрыть), и третий параметр — ожидание завершения.

Рассмотрим ситуацию: нам нужно просто узнать, «жив» компьютер или нет, не читая текст ответа. В этом случае мы ориентируемся на код возврата процесса:


Shell = Новый COMОбъект("WScript.Shell");
// Параметры: 0 - скрыть окно, Истина - ждать завершения
КодВозврата = Shell.Run("ping -n 1 -w 400 " + ИмяХоста, 0, Истина);

Если КодВозврата = 0 Тогда
    Сообщить("Узел доступен");
Иначе
    Сообщить("Узел недоступен");
КонецЕсли;

Главный недостаток метода Run — невозможность напрямую прочитать текст StdOut. Если вам нужно и скрыть окно, и получить IP-адрес через парсинг текста, придется прибегнуть к промежуточному файлу (перенаправление вывода > temp.txt), что делает код более громоздким и требует очистки временных файлов.

Работа через VBScript (ScriptControl)

Для более гибкого управления можно обернуть команды в VBS-скрипт, который будет исполняться внутри 1С через MSScriptControl.ScriptControl. Это позволяет инкапсулировать логику работы с объектами WScript. Однако помните, что данный объект является 32-битным и может вызвать сложности при работе на 64-битных серверах 1С.


Скрипт = Новый COMОбъект("MSScriptControl.ScriptControl");
Скрипт.Language = "VBScript";
КодСкрипта = 
    "Function GetPingResult(Host)
    |   Set WshShell = CreateObject(""WScript.Shell"")
    |   ' Здесь можно комбинировать методы запуска
    |   GetPingResult = WshShell.Run(""ping -n 1 "" & Host, 0, True)
    |End Function";
Скрипт.AddCode(КодСкрипта);
Результат = Скрипт.Run("GetPingResult", "127.0.0.1");

Выводы и рекомендации

Проанализировав все доступные методы, мы можем составить следующий рейтинг решений:

  1. WMI (Win32_PingStatus) — лучший выбор. Работает быстро, без окон, возвращает IP-адрес и статус как свойства объекта. Не требует парсинга строк и не имеет проблем с кодировкой.
  2. WScript.Shell (Run) — подходит для простой проверки «Да/Нет» без вывода текста. Окно полностью скрыто.
  3. WScript.Shell (Exec) — используется только если критично получить весь текст лога пинга, при этом вы готовы мириться с кратким мельканием окна. Требует ручной смены кодировки через chcp.

Для надежной работы в современных сетях (с поддержкой IPv6 и сложной DNS-структурой) мы рекомендуем использовать WMI, так как это наиболее профессиональный и системный подход, минимизирующий ошибки «человеческого фактора» при разборе текстовых строк.

← На главную