Сбой ShellExecute для локальных URL-адресов HTML или файлов

Наша компания переводит наши справочные системы в формат HTML5 под Flare. Мы также добавили доступ к темам в справочные системы, используя Flare CSHID в командной строке URI для прямого доступа к теме, например index.html#CSHID=GettingStarted, чтобы запустить страницу справки GettingStarted.html.

Наши приложения написаны на C++ и используют функцию Win32 ShellExecute() для запуска приложения по умолчанию, связанного с HTTP, для отображения справочной системы. Мы заметили, что ShellExecute () работает нормально, когда не указан хэштег, например:

ShellExecute(NULL,_T("Открыть"),_T("C:\Help\index.html"),NULL,NULL,SW_SHOWNORMAL);

Эта функция запускает браузер по умолчанию, связанный с просмотром HTML-страниц, и в этом случае запускается обработчик протокола File:///, запускается браузер, и вы видите файл:///c:/Help/index.html в адресной строке.

Однако после добавления информации # для темы ShellExecute () не может открыть страницу

ShellExecute(NULL,_T("Открыть"),_T("C:\Help\index.html#cshid=GettingStarted"),NULL,NULL,SW_SHOWNORMAL);

Если браузер вообще откроется, вы будете перенаправлены на файл:///c:/Help/index.html без указания темы # cshid = GettingStarted.

Обратите внимание, что это проблема только в том случае, если обработчик протокола файла задействован через ShellExecute(), если справочная система работает в Интернете, а обработчик протокола Http или Https задействован, все работает отлично.

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

2 ответа

После нескольких встреч с командой Microsoft MSDN они просмотрели исходный код для вызова ShellExecute(), и было определено, что да, при обработке URL-адресов на основе File:/// в ShellExecute() вызов ShellExecute() удалите # и любые данные, которые он найдет после # перед запуском браузера по умолчанию и отправкой на HTML-странице для открытия. Позиция MS заключается в том, что они делают это намеренно, чтобы предотвратить инъекции в функцию.

Решение состояло в том, чтобы увеличить вызов ShellExecute() путем поиска в URL-адресе символа #, и если он был найден, мы вручную запустили браузер по умолчанию с URL-адресом. Вот псевдокод

void WebDrive_ShellExecute(LPCTSTR szURL)
{
    if ( _tcschr(szURL,_T('#')) )
    {
        //
        //Get Default Browser from Registry, then launch it.
        //
        ::RegGetStr(HKCR,_T("HTTP\\Shell\\Open\\Command"),szBrowser);
        ::CreateProcess ( NULL, szBrowser + _T(" ") + szURL, NULL, NULL, FALSE, 0, NULL, NULL, &sui, &pi);
    }
    else
        ShellExecute(NULL,_T("open"),szURL,NULL,NULL,SW_SHOWNORMAL);
}

Конечно, есть немного больше кода C++, но этот общий дизайн работал для нас.

Я попробовал решение WebDrive, и оно не работало на Windows 10.

В качестве значения по умолчанию для "HTTP\Shell\Open\Command" задан путь к Internet Explorer, независимо от того, какой у меня установлен браузер по умолчанию. Однако для Internet Explorer это решение работает.

Процесс получения пути к браузеру по умолчанию в Windows 10 немного отличается ( Как определить браузер по умолчанию в Windows (вверху меню "Пуск")), но даже в этом случае решение не гарантируется, в зависимости от браузера. Например, для меня это не сработало с Edge.

Чтобы заставить его работать с Edge, мне нужно было добавить "file:///" к URL - но это также заставляет URL работать с ShellExecute(). Итак, по крайней мере, в Windows 10 все, что мне нужно было сделать, это:

ShellExecute (NULL, _T ("Открыть"),_T("Файл: /// C:/Help/Default.html#cshid=1648"),NULL,NULL,NULL);

ОБНОВЛЕНИЕ: вышесказанное перестало работать несколько месяцев назад. В конечном итоге я просмотрел временный файл, как описано здесь: https://forums.madcapsoftware.com/viewtopic.php?f=9&t=28376.

Используйте FindExecutable(), чтобы получить браузер по умолчанию и передать полный путь к файлу справки с его запросами (?) и фрагменты (#) как lpParametersпараметр ShellExecute(). Их там не разденут.
Затем займитесь случаем, если это приложение из магазина (скорее всего, Microsoft Edge).

Псевдо-код C:

if (FindExecutable(_T("c:\Help\index.html"), NULL, szBrowser)
{
    if (szBrowser == _T("C:\WINDOWS\system32\LaunchWinApp.exe"))
    {
        // default browser is a Windows Store App
        szBrowser = _T("shell:AppsFolder\Microsoft.MicrosoftEdge_8wekyb3d8bbwe!MicrosoftEdge");
    }
}
else
{
    szBrowser = szURL;
    szURL = NULL;
}

ShellExecute(NULL, NULL, szBrowser, szURL, NULL, SW_SHOWNORMAL);

Я решил проблему, не используя никаких методов, кроме ShellExecute в приложении Qt

QString currentpath = QDir::currentPath();
QString url = "/help//html/index.html#current";
QString full_url = "file:///" + currentpath + url;
QByteArray full_url_arr= full_url.toLocal8Bit();
LPCSTR lp = LPCSTR(full_url_arr.constData());
ShellExecute(NULL, "open", lp, NULL, NULL, SW_SHOWNORMAL);

Другие вопросы по тегам