Сбой 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);