При разработке систем помощи, интеграции документации или открытии отчетов в формате HTML программисты 1С часто сталкиваются с неприятной особенностью платформенной функции ЗапуститьПриложение(). Суть проблемы заключается в том, что при попытке открыть адрес вида file://C:/docs/help.html#anchor_1 операционная система Windows интерпретирует символ решетки # как недопустимый символ в пути к файлу и просто отсекает его. В итоге браузер открывает документ с самого начала, игнорируя указанную метку.
В этой статье мы подробно разберем, почему это происходит, и проанализируем несколько надежных способов решения задачи, которые позволят вашим пользователям попадать именно в нужный раздел документации.
Разберем ситуацию: функция ЗапуститьПриложение() на уровне операционной системы обращается к механизму ShellExecute. Когда Windows видит протокол file://, она пытается разрешить этот путь как путь к локальной файловой системе. Согласно правилам именования файлов в Windows, символ # не является стандартным разделителем для путей (в отличие от протоколов http или https, где это часть стандарта URI). Система «очищает» строку, чтобы найти файл на диске, и передает браузеру уже усеченную ссылку.
Выясним, как мы можем обойти это ограничение, используя альтернативные подходы.
Это один из самых элегантных и надежных способов «обмануть» систему. Вместо того чтобы передавать строку с якорем напрямую в ЗапуститьПриложение(), мы создадим временный файл с расширением .url. Операционная система обрабатывает такие файлы через специальный обработчик, который корректно передает всю строку URL браузеру по умолчанию, не обрезая якоря.
Рассмотрим реализацию этого метода на языке 1С:
Процедура ОткрытьФайлСЯкоремЧерезЯрлык(ПутьКФайлу, ИмяЯкоря)
// Формируем полный URL
ПолныйАдрес = "file:///" + СтрЗаменить(ПутьКФайлу, "\", "/") + "#" + ИмяЯкоря;
// Создаем текст файла ярлыка
ТекстЯрлыка = "[InternetShortcut]
|URL=" + ПолныйАдрес;
// Сохраняем во временный файл
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("url");
ТекстовыйДокумент = Новый ТекстовыйДокумент;
ТекстовыйДокумент.УстановитьТекст(ТекстЯрлыка);
ТекстовыйДокумент.Записать(ИмяВременногоФайла, КодировкаТекста.ANSI);
// Запускаем ярлык
ЗапуститьПриложение(ИмяВременногоФайла);
КонецПроцедуры
Обратите внимание, что для корректной работы ярлыка крайне важно использовать кодировку ANSI и правильно экранировать символы в пути. Мы используем СтрЗаменить, чтобы привести путь к формату с прямыми слешами, что более предпочтительно для протокола file.
Если мы передадим URL как аргумент командной строки непосредственно исполняемому файлу браузера (например, chrome.exe), то никакой обрезки не произойдет, так как браузер получит строку целиком. Однако здесь возникает сложность: как узнать, какой браузер установлен у пользователя по умолчанию, и где находится его исполняемый файл?
Проанализируем алгоритм поиска браузера в системном реестре Windows 10/11. Нам нужно пройти по следующей цепочке:
ProgId браузера по умолчанию в ветке HKEY_CURRENT_USER\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\https\UserChoice (параметр ProgId).ProgId, найти команду запуска в HKEY_CLASSES_ROOT\[ProgId]\shell\open\command.Посмотрим на пример кода, который выполняет такой поиск:
Функция ПолучитьПутьКБраузеруПоУмолчанию()
Попытка
Shell = Новый COMОбъект("WScript.Shell");
// Читаем ProgId для протокола https
ProgId = Shell.RegRead("HKEY_CURRENT_USER\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\https\UserChoice\ProgId");
// Читаем команду открытия для этого ProgId
Команда = Shell.RegRead("HKEY_CLASSES_ROOT\" + ProgId + "\shell\open\command\");
// Команда обычно выглядит как "C:\Path\To\browser.exe" -- "%1"
// Нам нужно извлечь только путь к exe
Поз = Найти(Команда, """ ");
Если Поз > 0 Тогда
Возврат Сред(Команда, 2, Поз - 2);
КонецЕсли;
Возврат Команда;
Исключение
Возврат "";
КонецПопытки;
КонецФункции
После того как путь к браузеру получен, мы можем запустить его с нашим URL:
ПутьКБраузеру = ПолучитьПутьКБраузеруПоУмолчанию();
Если ЗначениеЗаполнено(ПутьКБраузеру) Тогда
ПараметрыЗапуска = """" + ПолныйАдресСЯкорем + """";
ЗапуститьПриложение(ПутьКБраузеру + " " + ПараметрыЗапуска);
КонецЕсли;
Если мы не хотим глубоко погружаться в работу с реестром, можно воспользоваться мощью PowerShell. Он умеет более интеллектуально обрабатывать запуск процессов. Однако стоит помнить, что прямой вызов Start-Process без указания конкретного приложения может столкнуться с той же проблемой ShellExecute.
Эффективнее всего вызвать PowerShell, чтобы он сам нашел браузер и передал ему аргумент:
КомандаPS = "powershell -command ""Start-Process 'cmd' -ArgumentList '/c start " + ПолныйАдресСЯкорем + "'""";
ЗапуститьПриложение(КомандаPS, , Истина);
Важный нюанс: при формировании ПолныйАдресСЯкорем убедитесь, что все пробелы в пути заменены на %20. Но будьте осторожны: сам символ решетки # экранировать (превращать в %23) нельзя, иначе браузер будет искать файл с таким именем на диске, а не метку внутри файла.
При работе с протоколом file:// современные браузеры (особенно на движке Chromium: Chrome, Edge, Opera) накладывают серьезные ограничения безопасности. Например, если вы пытаетесь открыть локальный файл из веб-клиента 1С (запущенного в браузере), браузер заблокирует такой переход по соображениям безопасности (Cross-Origin Policy). Эти методы гарантированно работают только в тонком или толстом клиенте 1С, запущенном локально на компьютере пользователя.
Также стоит учитывать, что если у пользователя уже открыто окно браузера с этим файлом, поведение может отличаться: некоторые браузеры просто переключатся на вкладку и перейдут к якорю, а другие могут открыть новую вкладку или проигнорировать якорь. Наиболее стабильно переход к якорю отрабатывает при использовании способа с .url файлом или при прямой передаче пути в командную строку конкретного браузера.
Подведем итог: использование временного .url файла является наиболее предпочтительным методом, так как он не требует ручного разбора веток реестра и корректно обрабатывается стандартными средствами Windows, обеспечивая пользователю ожидаемый результат при открытии документации.