Backed out changeset 2450366cf7ca (bug 1891629) for causing win msix mochitest failures
[gecko.git] / widget / windows / ShellHeaderOnlyUtils.h
blobea95077fb3f94ccdfbb48b49f43ff7bd342e4602
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_ShellHeaderOnlyUtils_h
8 #define mozilla_ShellHeaderOnlyUtils_h
10 #if defined(LIBXUL) && !defined(UNICODE)
11 # error \
12 "UNICODE not set - must be set to prevent compile failure in `comdef.h` due to us deleting `FormatMessage` when absent."
13 #endif
15 #include "mozilla/WinHeaderOnlyUtils.h"
17 #include <objbase.h>
19 #include <exdisp.h>
20 #include <shldisp.h>
21 #include <shlobj.h>
22 #include <shlwapi.h>
23 #include <shobjidl.h>
24 #include <shtypes.h>
25 // NB: include this after shldisp.h so its macros do not conflict with COM
26 // interfaces defined by shldisp.h
27 #include <shellapi.h>
28 #include <type_traits>
30 #include <comdef.h>
31 #include <comutil.h>
33 #include "mozilla/RefPtr.h"
34 #include "mozilla/UniquePtr.h"
36 namespace mozilla {
38 /**
39 * Ask the current user's Desktop to ShellExecute on our behalf, thus causing
40 * the resulting launched process to inherit its security priviliges from
41 * Explorer instead of our process.
43 * This is useful in two scenarios, in particular:
44 * * We are running as an elevated user and we want to start something as the
45 * "normal" user;
46 * * We are starting a process that is incompatible with our process's
47 * process mitigation policies. By delegating to Explorer, the child process
48 * will not be affected by our process mitigations.
50 * Since this communication happens over DCOM, Explorer's COM DACL governs
51 * whether or not we can execute against it, thus avoiding privilege escalation.
53 inline LauncherVoidResult ShellExecuteByExplorer(const _bstr_t& aPath,
54 const _variant_t& aArgs,
55 const _variant_t& aVerb,
56 const _variant_t& aWorkingDir,
57 const _variant_t& aShowCmd) {
58 // NB: Explorer may be a local server, not an inproc server
59 RefPtr<IShellWindows> shellWindows;
60 HRESULT hr = ::CoCreateInstance(
61 CLSID_ShellWindows, nullptr, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
62 IID_IShellWindows, getter_AddRefs(shellWindows));
63 if (FAILED(hr)) {
64 return LAUNCHER_ERROR_FROM_HRESULT(hr);
67 // 1. Find the shell view for the desktop.
68 _variant_t loc(int(CSIDL_DESKTOP));
69 _variant_t empty;
70 long hwnd;
71 RefPtr<IDispatch> dispDesktop;
72 hr = shellWindows->FindWindowSW(&loc, &empty, SWC_DESKTOP, &hwnd,
73 SWFO_NEEDDISPATCH,
74 getter_AddRefs(dispDesktop));
75 if (FAILED(hr)) {
76 return LAUNCHER_ERROR_FROM_HRESULT(hr);
79 if (hr == S_FALSE) {
80 // The call succeeded but the window was not found.
81 return LAUNCHER_ERROR_FROM_WIN32(ERROR_NOT_FOUND);
84 RefPtr<IServiceProvider> servProv;
85 hr = dispDesktop->QueryInterface(IID_IServiceProvider,
86 getter_AddRefs(servProv));
87 if (FAILED(hr)) {
88 return LAUNCHER_ERROR_FROM_HRESULT(hr);
91 RefPtr<IShellBrowser> browser;
92 hr = servProv->QueryService(SID_STopLevelBrowser, IID_IShellBrowser,
93 getter_AddRefs(browser));
94 if (FAILED(hr)) {
95 return LAUNCHER_ERROR_FROM_HRESULT(hr);
98 RefPtr<IShellView> activeShellView;
99 hr = browser->QueryActiveShellView(getter_AddRefs(activeShellView));
100 if (FAILED(hr)) {
101 return LAUNCHER_ERROR_FROM_HRESULT(hr);
104 // 2. Get the automation object for the desktop.
105 RefPtr<IDispatch> dispView;
106 hr = activeShellView->GetItemObject(SVGIO_BACKGROUND, IID_IDispatch,
107 getter_AddRefs(dispView));
108 if (FAILED(hr)) {
109 return LAUNCHER_ERROR_FROM_HRESULT(hr);
112 RefPtr<IShellFolderViewDual> folderView;
113 hr = dispView->QueryInterface(IID_IShellFolderViewDual,
114 getter_AddRefs(folderView));
115 if (FAILED(hr)) {
116 return LAUNCHER_ERROR_FROM_HRESULT(hr);
119 // 3. Get the interface to IShellDispatch2
120 RefPtr<IDispatch> dispShell;
121 hr = folderView->get_Application(getter_AddRefs(dispShell));
122 if (FAILED(hr)) {
123 return LAUNCHER_ERROR_FROM_HRESULT(hr);
126 RefPtr<IShellDispatch2> shellDisp;
127 hr =
128 dispShell->QueryInterface(IID_IShellDispatch2, getter_AddRefs(shellDisp));
129 if (FAILED(hr)) {
130 return LAUNCHER_ERROR_FROM_HRESULT(hr);
133 // Passing the foreground privilege so that the shell can launch an
134 // application in the foreground. This fails with E_ACCESSDENIED if the
135 // current window is shown in the background. We keep a soft assert for
136 // the other failures to investigate how it happened.
137 hr = ::CoAllowSetForegroundWindow(shellDisp, nullptr);
138 MOZ_ASSERT(SUCCEEDED(hr) || hr == E_ACCESSDENIED);
140 // shellapi.h macros interfere with the correct naming of the method being
141 // called on IShellDispatch2. Temporarily remove that definition.
142 #if defined(ShellExecute)
143 # define MOZ_REDEFINE_SHELLEXECUTE
144 # undef ShellExecute
145 #endif // defined(ShellExecute)
147 // 4. Now call IShellDispatch2::ShellExecute to ask Explorer to execute.
148 hr = shellDisp->ShellExecute(aPath, aArgs, aWorkingDir, aVerb, aShowCmd);
149 if (FAILED(hr)) {
150 return LAUNCHER_ERROR_FROM_HRESULT(hr);
153 // Restore the macro that was removed prior to IShellDispatch2::ShellExecute
154 #if defined(MOZ_REDEFINE_SHELLEXECUTE)
155 # if defined(UNICODE)
156 # define ShellExecute ShellExecuteW
157 # else
158 # define ShellExecute ShellExecuteA
159 # endif
160 # undef MOZ_REDEFINE_SHELLEXECUTE
161 #endif // defined(MOZ_REDEFINE_SHELLEXECUTE)
163 return Ok();
166 using UniqueAbsolutePidl =
167 UniquePtr<std::remove_pointer_t<PIDLIST_ABSOLUTE>, CoTaskMemFreeDeleter>;
169 inline LauncherResult<UniqueAbsolutePidl> ShellParseDisplayName(
170 const wchar_t* aPath) {
171 PIDLIST_ABSOLUTE rawAbsPidl = nullptr;
172 SFGAOF sfgao;
173 HRESULT hr = ::SHParseDisplayName(aPath, nullptr, &rawAbsPidl, 0, &sfgao);
174 if (FAILED(hr)) {
175 return LAUNCHER_ERROR_FROM_HRESULT(hr);
178 return UniqueAbsolutePidl(rawAbsPidl);
181 } // namespace mozilla
183 #endif // mozilla_ShellHeaderOnlyUtils_h