【问题标题】:ShellExecute fails for local html or file URLs本地 html 或文件 URL 的 ShellExecute 失败
【发布时间】:2014-12-05 23:19:10
【问题描述】:

我们公司正在将我们的帮助系统迁移到 Flare 下的 HTML5 格式。我们还在 URI 命令行上使用 Flare CSHID 的帮助系统添加了基于主题的访问,用于直接访问主题,例如 index.html#CSHID=GettingStarted 以启动 GettingStarted.html 帮助页面。

我们的应用程序是用 C++ 编写的,并利用 Win32 ShellExecute() 函数生成与 HTTP 关联的默认应用程序来显示帮助系统。我们注意到ShellExecute() 在没有指定主题标签时可以正常工作,例如

ShellExecute(NULL, _T("open"), _T("c:\\Help\\index.html"), NULL, NULL, SW_SHOWNORMAL);

此函数将启动与查看 HTML 页面相关的默认浏览器,在这种情况下,File:/// 协议处理程序将启动,浏览器将启动,您将在地址栏中看到 file:///c:/Help/index.html

但是,一旦为主题添加了# 信息,ShellExecute() 将无法打开页面

ShellExecute(NULL,_T("open"),_T("c:\\Help\\index.html#cshid=GettingStarted"),NULL,NULL,SW_SHOWNORMAL);

如果浏览器完全打开,您将被定向到 file:///c:/Help/index.html 而没有 #cshid=GettingStarted 主题标识。

请注意,如果文件协议处理程序通过ShellExecute() 参与,这只是一个问题,如果帮助系统存在于网络上,并且使用了 Http 或 Https 协议处理程序,则一切正常。

对于我们的客户,其中一些在专用 LAN 上,我们不能总是依赖 Internet 访问,因此我们的帮助系统必须随应用程序一起提供。

【问题讨论】:

    标签: http hashtag shellexecute flare


    【解决方案1】:

    在与 Microsoft 的 MSDN 团队反复讨论之后,他们审查了 ShellExecute() 调用的源代码,并确定是的,在 ShellExecute() 中处理基于 File:/// 的 URL 时,ShellExecute( ) 调用将在启动默认浏览器并发送要打开的 HTML 页面之前删除 # 以及它在 # 之后找到的任何数据。 MS 的立场是他们故意这样做是为了防止注入到函数中。

    解决方案是通过在 URL 中搜索 # 来增强 ShellExecute() 调用,如果找到,则我们将使用 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++ 代码还有更多内容,但这种通用设计对我们有用。

    【讨论】:

    • 您是否找到了一种启动 Edge 以使其接受 URL 的 #cshid=<topic-id> 部分的方法?
    【解决方案2】:

    我尝试了 WebDrive 的解决方案,但它并不能真正在 Windows 10 上运行。

    “HTTP\Shell\Open\Command”默认值设置为 Internet Explorer 路径,无论我的默认浏览器设置如何。但是,对于 Internet Explorer,该解决方案确实有效。

    在 Windows 10 上获取默认浏览器路径的过程有点不同 (How to determine the Windows default browser (at the top of the start menu)),但即使这样,也不能保证解决方案能够正常工作,具体取决于浏览器。例如。对我来说,它不适用于 Edge。

    为了让它与 Edge 一起工作,我必须在 URL 中添加“file:///”——但这也使得 URL 与 ShellExecute() 一起工作。所以,至少在 Windows 10 上,我需要做的就是:

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

    更新: 以上停止工作几个月前。我最终所做的是通过临时文件,如下所述:https://forums.madcapsoftware.com/viewtopic.php?f=9&t=28376#p130613

    【讨论】:

    • 您确定ShellExecute 可以与锚片段一起使用吗?我刚刚编写了一个 C++ 控制台应用程序,它打开到 default.html 但正在删除 URL 的 #cshid=... 部分。
    • @KeithHill 让它与 Edge 一起工作的唯一方法似乎是通过临时文件,请参见此处:forums.madcapsoftware.com/viewtopic.php?f=9&t=28376#p130613
    【解决方案3】:

    使用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);
    

    【讨论】:

      【解决方案4】:

      我没有在 Qt 应用程序中使用 ShellExecute 以外的任何方法解决了这个问题

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

      【讨论】:

        猜你喜欢
        • 2023-03-06
        • 1970-01-01
        • 1970-01-01
        • 2012-10-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多