diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2018-11-28 10:13:56 +0100 |
---|---|---|
committer | Oliver Wolff <oliver.wolff@qt.io> | 2022-08-26 08:53:41 +0200 |
commit | 7e89e6bfe83761bb3dd80dddf4ccc1c332cae80d (patch) | |
tree | 7aecbd95e68f2a92be199dd0122f29108430325b /src/plugins/platforms/windows/qwindowsservices.cpp | |
parent | b9053b55f8e0f1750526e117d9c059a0bd883baf (diff) |
Windows QPA/QPlatformServices::openUrl(): Add work around for anchors on local file URLs
Retrieve the browser executable and pass the URL as command line argument
in this case to work around ShellExecute() failing to handle anchors.
Pick-to: 6.4 6.3 6.2 5.15
Fixes: QTBUG-14460
Change-Id: I44ccd1126d5db6a387b36729837edc045908a670
Reviewed-by: André de la Rocha <andre.rocha@qt.io>
Diffstat (limited to 'src/plugins/platforms/windows/qwindowsservices.cpp')
-rw-r--r-- | src/plugins/platforms/windows/qwindowsservices.cpp | 67 |
1 files changed, 61 insertions, 6 deletions
diff --git a/src/plugins/platforms/windows/qwindowsservices.cpp b/src/plugins/platforms/windows/qwindowsservices.cpp index fbad934a05..f2bd90f4bd 100644 --- a/src/plugins/platforms/windows/qwindowsservices.cpp +++ b/src/plugins/platforms/windows/qwindowsservices.cpp @@ -14,6 +14,7 @@ #include <QtCore/private/qwinregistry_p.h> #include <shlobj.h> +#include <shlwapi.h> #include <intshcut.h> QT_BEGIN_NAMESPACE @@ -25,12 +26,17 @@ enum { debug = 0 }; class QWindowsShellExecuteThread : public QThread { public: - explicit QWindowsShellExecuteThread(const wchar_t *path) : m_path(path) { } + explicit QWindowsShellExecuteThread(const wchar_t *operation, const wchar_t *file, + const wchar_t *parameters) + : m_operation(operation) + , m_file(file) + , m_parameters(parameters) { } void run() override { if (SUCCEEDED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE))) { - m_result = ShellExecute(nullptr, nullptr, m_path, nullptr, nullptr, SW_SHOWNORMAL); + m_result = ShellExecute(nullptr, m_operation, m_file, m_parameters, nullptr, + SW_SHOWNORMAL); CoUninitialize(); } } @@ -39,9 +45,55 @@ public: private: HINSTANCE m_result = nullptr; - const wchar_t *m_path; + const wchar_t *m_operation; + const wchar_t *m_file; + const wchar_t *m_parameters; }; +static QString msgShellExecuteFailed(const QUrl &url, quintptr code) +{ + QString result; + QTextStream(&result) <<"ShellExecute '" << url.toString() << "' failed (error " << code << ")."; + return result; +} + +// Retrieve the web browser and open the URL. This should be used for URLs with +// fragments which don't work when using ShellExecute() directly (QTBUG-14460, +// QTBUG-55300). +static bool openWebBrowser(const QUrl &url) +{ + WCHAR browserExecutable[MAX_PATH] = {}; + const wchar_t operation[] = L"open"; + DWORD browserExecutableSize = MAX_PATH; + if (FAILED(AssocQueryString(0, ASSOCSTR_EXECUTABLE, L"http", operation, + browserExecutable, &browserExecutableSize))) { + return false; + } + QString browser = QString::fromWCharArray(browserExecutable, browserExecutableSize - 1); + // Workaround for "old" MS Edge entries. Instead of LaunchWinApp.exe we can just use msedge.exe + if (browser.contains("LaunchWinApp.exe"_L1, Qt::CaseInsensitive)) + browser = "msedge.exe"_L1; + const QString urlS = url.toString(QUrl::FullyEncoded); + + // Run ShellExecute() in a thread since it may spin the event loop. + // Prevent it from interfering with processing of posted events (QTBUG-85676). + QWindowsShellExecuteThread thread(operation, + reinterpret_cast<const wchar_t *>(browser.utf16()), + reinterpret_cast<const wchar_t *>(urlS.utf16())); + thread.start(); + thread.wait(); + + const auto result = reinterpret_cast<quintptr>(thread.result()); + if (debug) + qDebug() << __FUNCTION__ << urlS << QString::fromWCharArray(browserExecutable) << result; + // ShellExecute returns a value greater than 32 if successful + if (result <= 32) { + qWarning("%s", qPrintable(msgShellExecuteFailed(url, result))); + return false; + } + return true; +} + static inline bool shellExecute(const QUrl &url) { const QString nativeFilePath = url.isLocalFile() && !url.hasFragment() && !url.hasQuery() @@ -51,7 +103,9 @@ static inline bool shellExecute(const QUrl &url) // Run ShellExecute() in a thread since it may spin the event loop. // Prevent it from interfering with processing of posted events (QTBUG-85676). - QWindowsShellExecuteThread thread(reinterpret_cast<const wchar_t *>(nativeFilePath.utf16())); + QWindowsShellExecuteThread thread(nullptr, + reinterpret_cast<const wchar_t *>(nativeFilePath.utf16()), + nullptr); thread.start(); thread.wait(); @@ -59,7 +113,7 @@ static inline bool shellExecute(const QUrl &url) // ShellExecute returns a value greater than 32 if successful if (result <= 32) { - qWarning("ShellExecute '%ls' failed (error %zu).", qUtf16Printable(url.toString()), result); + qWarning("%s", qPrintable(msgShellExecuteFailed(url, result))); return false; } return true; @@ -136,7 +190,8 @@ bool QWindowsServices::openUrl(const QUrl &url) const QString scheme = url.scheme(); if (scheme == u"mailto" && launchMail(url)) return true; - return shellExecute(url); + return url.isLocalFile() && url.hasFragment() + ? openWebBrowser(url) : shellExecute(url); } bool QWindowsServices::openDocument(const QUrl &url) |