Bug 1567614: Part 2 - Add ShellExecuteByExplorer overload to handle absolute PIDL lists; r=jmathies, a=jcristau
For the URI handling case, we still want to parse the URI to look for any
malformation. OTOH, IShellDispatch2::ShellExecute does not accept PIDLs as
arguments, we we need an overload that converts the absolute PIDL back to a
path for the purposes of passing on to that interface.
Differential Revision:
https://phabricator.services.mozilla.com/D38944
--- a/widget/windows/ShellHeaderOnlyUtils.h
+++ b/widget/windows/ShellHeaderOnlyUtils.h
@@ -142,11 +142,67 @@ inline LauncherVoidResult ShellExecuteBy
# define ShellExecute ShellExecuteA
# endif
# undef MOZ_REDEFINE_SHELLEXECUTE
#endif // defined(MOZ_REDEFINE_SHELLEXECUTE)
return Ok();
}
+using UniqueAbsolutePidl =
+ UniquePtr<RemovePointer<PIDLIST_ABSOLUTE>::Type, CoTaskMemFreeDeleter>;
+
+inline UniqueAbsolutePidl ShellParseDisplayName(const wchar_t* aPath) {
+ PIDLIST_ABSOLUTE rawAbsPidl = nullptr;
+ SFGAOF sfgao;
+ HRESULT hr = ::SHParseDisplayName(aPath, nullptr, &rawAbsPidl, 0, &sfgao);
+ if (FAILED(hr)) {
+ return nullptr;
+ }
+
+ return UniqueAbsolutePidl(rawAbsPidl);
+}
+
+/**
+ * Since IShellDispatch2::ShellExecute does not accept a PIDL as one of its
+ * parameters, we need to convert a PIDL back to a path. This overload handles
+ * that conversion and then proceeds with the ShellExecuteByExplorer call.
+ */
+inline LauncherVoidResult ShellExecuteByExplorer(
+ const UniqueAbsolutePidl& aPath, const _variant_t& aArgs,
+ const _variant_t& aVerb, const _variant_t& aWorkingDir,
+ const _variant_t& aShowCmd) {
+ // |aPath| is an absolute path. IShellFolder::GetDisplayNameOf requires a
+ // valid child ID, so the first thing we need to resolve is the IShellFolder
+ // for |aPath|'s parent, as well as the childId that represents |aPath|.
+ // Fortunately SHBindToParent does exactly that!
+ PCUITEMID_CHILD childId = nullptr;
+ RefPtr<IShellFolder> parentFolder;
+ HRESULT hr = ::SHBindToParent(aPath.get(), IID_IShellFolder,
+ getter_AddRefs(parentFolder), &childId);
+ if (FAILED(hr)) {
+ return LAUNCHER_ERROR_FROM_HRESULT(hr);
+ }
+
+ // Now we retrieve the display name of |childId|, telling the shell that we
+ // plan to have the string parsed.
+ STRRET strret;
+ hr = parentFolder->GetDisplayNameOf(childId, SHGDN_FORPARSING, &strret);
+ if (FAILED(hr)) {
+ return LAUNCHER_ERROR_FROM_HRESULT(hr);
+ }
+
+ // Since ShellExecuteByExplorer wants a BSTR, we convert |strret|. Calling
+ // StrRetToBSTR is advantageous since it automatically takes care of
+ // freeing any dynamically allocated memory in |strret|.
+ _bstr_t bstrPath;
+ hr = ::StrRetToBSTR(&strret, nullptr, bstrPath.GetAddress());
+ if (FAILED(hr)) {
+ return LAUNCHER_ERROR_FROM_HRESULT(hr);
+ }
+
+ // Now we have a bstr_t so we can invoke the overload.
+ return ShellExecuteByExplorer(bstrPath, aArgs, aVerb, aWorkingDir, aShowCmd);
+}
+
} // namespace mozilla
#endif // mozilla_ShellHeaderOnlyUtils_h
--- a/widget/windows/WinHeaderOnlyUtils.h
+++ b/widget/windows/WinHeaderOnlyUtils.h
@@ -6,16 +6,17 @@
#ifndef mozilla_WinHeaderOnlyUtils_h
#define mozilla_WinHeaderOnlyUtils_h
#include <windows.h>
#include <winerror.h>
#include <winnt.h>
#include <winternl.h>
+#include <objbase.h>
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/DynamicallyLinkedFunctionPtr.h"
#include "mozilla/Maybe.h"
#include "mozilla/Result.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/WindowsVersion.h"
@@ -397,11 +398,15 @@ class MOZ_RAII AutoVirtualProtect final
private:
void* mAddress;
size_t mLength;
HANDLE mTargetProcess;
DWORD mPrevProt;
WindowsError mError;
};
+struct CoTaskMemFreeDeleter {
+ void operator()(void* aPtr) { ::CoTaskMemFree(aPtr); }
+};
+
} // namespace mozilla
#endif // mozilla_WinHeaderOnlyUtils_h