ShellExecute fails for local html or file URLs

怎甘沉沦 提交于 2019-12-05 18:16:42

After some back-and-forth with Microsoft's MSDN team, they reviewed the source code to the ShellExecute() call and it was determined that yes, when processing File:/// based URLs in ShellExecute(), the ShellExecute() call will strip off the # and any data it finds after the # before launching the default browser and sending in the HTML page to open. MS's stance is that they do this deliberately to prevent injections into the function.

The solution was to beef up the ShellExecute() call by searching the URL for a # and if one was found, then we would manually launch the default browser with the URL. Here's the pseudocode

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);
}

Granted there's a bit more to the c++ code, but this general design worked for us.

I tried WebDrive's solution and it didn't really work on Windows 10.

"HTTP\Shell\Open\Command" default value is set to Internet Explorer path, regardless of what my default browser setting. However, for Internet Explorer that solution DOES work.

Process to fetch default browser path on Windows 10 is a bit different (How to determine the Windows default browser (at the top of the start menu)) but even then the solution is not guaranteed to work, depending on the browser. E.g. for me it didn't work with Edge.

To get it to work with Edge I had to add "file:///" to the URL -- but that also makes the URL work with ShellExecute(). So, at least on Windows 10, all I needed to do was this:

ShellExecute(NULL,_T("open"),_T("file:///c:/Help/Default.html#cshid=1648"),NULL,NULL,NULL);

UPDATE: The above stopped working months ago. What I eventually did was go through temporary file, as described here: https://forums.madcapsoftware.com/viewtopic.php?f=9&t=28376#p130613

Use FindExecutable() to get the default browser and pass the full help file path with its queries (?) and fragments (#) as the lpParameters parameter to ShellExecute(). They won't get stripped off there.
Then handle the case if it is a Store App (most likely Microsoft Edge).

Pseudo C code:

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);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!