Bug 1567614: Part 2 - Add ShellExecuteByExplorer overload to handle absolute PIDL lists; r=jmathies, a=jcristau
authorAaron Klotz <aklotz@mozilla.com>
Tue, 23 Jul 2019 20:18:07 +0000
changeset 537279 51aa10f2e418efada7ba24bc47cf63a8664d6955
parent 537278 05634b24b8ef1c5808998710ea1375f7cac95981
child 537280 cb3f768f7cd8d65be5234efa064b21a45a95c261
push id2122
push userarchaeopteryx@coole-files.de
push dateWed, 07 Aug 2019 14:22:14 +0000
treeherdermozilla-release@02d9056ba76c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjmathies, jcristau
bugs1567614
milestone68.0.2
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
widget/windows/ShellHeaderOnlyUtils.h
widget/windows/WinHeaderOnlyUtils.h
--- 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