[EXPLORER][SHELL32][USER32] Implement 'Show the Desktop' action of Task Bar (#668)
[reactos.git] / dll / win32 / shell32 / CShellDispatch.cpp
1 /*
2 * PROJECT: shell32
3 * LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+)
4 * PURPOSE: IShellDispatch implementation
5 * COPYRIGHT: Copyright 2015-2018 Mark Jansen (mark.jansen@reactos.org)
6 * Copyright 2018 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
7 */
8
9 #include "precomp.h"
10 #include "winsvc.h"
11 #include <traycmd.h> // tray commands
12
13 WINE_DEFAULT_DEBUG_CHANNEL(shell);
14
15
16 CShellDispatch::CShellDispatch()
17 {
18 }
19
20 CShellDispatch::~CShellDispatch()
21 {
22 }
23
24 HRESULT CShellDispatch::Initialize()
25 {
26 return S_OK;
27 }
28
29 // *** IShellDispatch methods ***
30 HRESULT STDMETHODCALLTYPE CShellDispatch::get_Application(IDispatch **ppid)
31 {
32 TRACE("(%p, %p)\n", this, ppid);
33
34 if (!ppid)
35 return E_INVALIDARG;
36
37 *ppid = this;
38 AddRef();
39
40 return S_OK;
41 }
42
43 HRESULT STDMETHODCALLTYPE CShellDispatch::get_Parent(IDispatch **ppid)
44 {
45 TRACE("(%p, %p)\n", this, ppid);
46
47 if (ppid)
48 {
49 *ppid = static_cast<IDispatch*>(this);
50 AddRef();
51 }
52
53 return S_OK;
54 }
55
56 HRESULT VariantToIdlist(VARIANT* var, LPITEMIDLIST* idlist)
57 {
58 HRESULT hr = S_FALSE;
59 if(V_VT(var) == VT_I4)
60 {
61 hr = SHGetSpecialFolderLocation(NULL, V_I4(var), idlist);
62 }
63 else if(V_VT(var) == VT_BSTR)
64 {
65 hr = SHILCreateFromPathW(V_BSTR(var), idlist, NULL);
66 }
67 return hr;
68 }
69
70 HRESULT STDMETHODCALLTYPE CShellDispatch::NameSpace(VARIANT vDir, Folder **ppsdf)
71 {
72 TRACE("(%p, %s, %p)\n", this, debugstr_variant(&vDir), ppsdf);
73 if (!ppsdf)
74 return E_POINTER;
75 *ppsdf = NULL;
76 HRESULT hr;
77
78 if (V_VT(&vDir) == VT_I2)
79 {
80 hr = VariantChangeType(&vDir, &vDir, 0, VT_I4);
81 if (FAILED_UNEXPECTEDLY(hr))
82 return hr;
83 }
84
85 CComHeapPtr<ITEMIDLIST> idlist;
86 hr = VariantToIdlist(&vDir, &idlist);
87 if (!SUCCEEDED(hr) || !idlist)
88 return S_FALSE;
89
90 return ShellObjectCreatorInit<CFolder>(static_cast<LPITEMIDLIST>(idlist), IID_PPV_ARG(Folder, ppsdf));
91 }
92
93 static BOOL is_optional_argument(const VARIANT *arg)
94 {
95 return V_VT(arg) == VT_ERROR && V_ERROR(arg) == DISP_E_PARAMNOTFOUND;
96 }
97
98 HRESULT STDMETHODCALLTYPE CShellDispatch::BrowseForFolder(LONG Hwnd, BSTR Title, LONG Options, VARIANT RootFolder, Folder **ppsdf)
99 {
100 TRACE("(%p, %lu, %ls, %lu, %s, %p)\n", this, Hwnd, Title, Options, debugstr_variant(&RootFolder), ppsdf);
101
102 *ppsdf = NULL;
103
104 if (!is_optional_argument(&RootFolder))
105 FIXME("root folder is ignored\n");
106
107 BROWSEINFOW bi = { 0 };
108 bi.hwndOwner = reinterpret_cast<HWND>(LongToHandle(Hwnd));
109 bi.lpszTitle = Title;
110 bi.ulFlags = Options;
111
112 CComHeapPtr<ITEMIDLIST> selection;
113 selection.Attach(SHBrowseForFolderW(&bi));
114 if (!selection)
115 return S_FALSE;
116
117 return ShellObjectCreatorInit<CFolder>(static_cast<LPITEMIDLIST>(selection), IID_PPV_ARG(Folder, ppsdf));
118 }
119
120 HRESULT STDMETHODCALLTYPE CShellDispatch::Windows(IDispatch **ppid)
121 {
122 TRACE("(%p, %p)\n", this, ppid);
123
124 *ppid = NULL;
125
126 return E_NOTIMPL;
127 }
128
129 HRESULT STDMETHODCALLTYPE CShellDispatch::Open(VARIANT vDir)
130 {
131 TRACE("(%p, %s)\n", this, debugstr_variant(&vDir));
132 return E_NOTIMPL;
133 }
134
135 HRESULT STDMETHODCALLTYPE CShellDispatch::Explore(VARIANT vDir)
136 {
137 TRACE("(%p, %s)\n", this, debugstr_variant(&vDir));
138 return E_NOTIMPL;
139 }
140
141 HRESULT STDMETHODCALLTYPE CShellDispatch::MinimizeAll()
142 {
143 TRACE("(%p)\n", this);
144 return E_NOTIMPL;
145 }
146
147 HRESULT STDMETHODCALLTYPE CShellDispatch::UndoMinimizeALL()
148 {
149 TRACE("(%p)\n", this);
150 return E_NOTIMPL;
151 }
152
153 HRESULT STDMETHODCALLTYPE CShellDispatch::FileRun()
154 {
155 TRACE("(%p)\n", this);
156 return E_NOTIMPL;
157 }
158
159 HRESULT STDMETHODCALLTYPE CShellDispatch::CascadeWindows()
160 {
161 TRACE("(%p)\n", this);
162 return E_NOTIMPL;
163 }
164
165 HRESULT STDMETHODCALLTYPE CShellDispatch::TileVertically()
166 {
167 TRACE("(%p)\n", this);
168 return E_NOTIMPL;
169 }
170
171 HRESULT STDMETHODCALLTYPE CShellDispatch::TileHorizontally()
172 {
173 TRACE("(%p)\n", this);
174 return E_NOTIMPL;
175 }
176
177 HRESULT STDMETHODCALLTYPE CShellDispatch::ShutdownWindows()
178 {
179 ExitWindowsDialog(NULL);
180 return S_OK;
181 }
182
183 HRESULT STDMETHODCALLTYPE CShellDispatch::Suspend()
184 {
185 TRACE("(%p)\n", this);
186 return E_NOTIMPL;
187 }
188
189 HRESULT STDMETHODCALLTYPE CShellDispatch::EjectPC()
190 {
191 TRACE("(%p)\n", this);
192 return E_NOTIMPL;
193 }
194
195 HRESULT STDMETHODCALLTYPE CShellDispatch::SetTime()
196 {
197 TRACE("(%p)\n", this);
198 return E_NOTIMPL;
199 }
200
201 HRESULT STDMETHODCALLTYPE CShellDispatch::TrayProperties()
202 {
203 TRACE("(%p)\n", this);
204 return E_NOTIMPL;
205 }
206
207 HRESULT STDMETHODCALLTYPE CShellDispatch::Help()
208 {
209 TRACE("(%p)\n", this);
210 return E_NOTIMPL;
211 }
212
213 HRESULT STDMETHODCALLTYPE CShellDispatch::FindFiles()
214 {
215 TRACE("(%p)\n", this);
216 return E_NOTIMPL;
217 }
218
219 HRESULT STDMETHODCALLTYPE CShellDispatch::FindComputer()
220 {
221 TRACE("(%p)\n", this);
222 return E_NOTIMPL;
223 }
224
225 HRESULT STDMETHODCALLTYPE CShellDispatch::RefreshMenu()
226 {
227 TRACE("(%p)\n", this);
228 return E_NOTIMPL;
229 }
230
231 HRESULT STDMETHODCALLTYPE CShellDispatch::ControlPanelItem(BSTR szDir)
232 {
233 TRACE("(%p, %ls)\n", this, szDir);
234 return E_NOTIMPL;
235 }
236
237
238 // *** IShellDispatch2 methods ***
239 HRESULT STDMETHODCALLTYPE CShellDispatch::IsRestricted(BSTR group, BSTR restriction, LONG *value)
240 {
241 TRACE("(%p, %ls, %ls, %p)\n", this, group, restriction, value);
242 return E_NOTIMPL;
243 }
244
245 HRESULT STDMETHODCALLTYPE CShellDispatch::ShellExecute(BSTR file, VARIANT v_args, VARIANT v_dir, VARIANT v_op, VARIANT v_show)
246 {
247 CComVariant args_str, dir_str, op_str, show_int;
248 WCHAR *args = NULL, *dir = NULL, *op = NULL;
249 INT show = 0;
250 HINSTANCE ret;
251
252 TRACE("(%s, %s, %s, %s, %s)\n", debugstr_w(file), debugstr_variant(&v_args),
253 debugstr_variant(&v_dir), debugstr_variant(&v_op), debugstr_variant(&v_show));
254
255 args_str.ChangeType(VT_BSTR, &v_args);
256 if (V_VT(&args_str) == VT_BSTR)
257 args = V_BSTR(&args_str);
258
259 dir_str.ChangeType(VT_BSTR, &v_dir);
260 if (V_VT(&dir_str) == VT_BSTR)
261 dir = V_BSTR(&dir_str);
262
263 op_str.ChangeType(VT_BSTR, &v_op);
264 if (V_VT(&op_str) == VT_BSTR)
265 op = V_BSTR(&op_str);
266
267 show_int.ChangeType(VT_I4, &v_show);
268 if (V_VT(&show_int) == VT_I4)
269 show = V_I4(&show_int);
270
271 ret = ShellExecuteW(NULL, op, file, args, dir, show);
272
273 return (ULONG_PTR)ret > 32 ? S_OK : S_FALSE;
274 }
275
276 HRESULT STDMETHODCALLTYPE CShellDispatch::FindPrinter(BSTR name, BSTR location, BSTR model)
277 {
278 TRACE("(%p, %ls, %ls, %ls)\n", this, name, location, model);
279 return E_NOTIMPL;
280 }
281
282 HRESULT STDMETHODCALLTYPE CShellDispatch::GetSystemInformation(BSTR name, VARIANT *ret)
283 {
284 TRACE("(%p, %ls, %p)\n", this, name, ret);
285 return E_NOTIMPL;
286 }
287
288 HRESULT STDMETHODCALLTYPE CShellDispatch::ServiceStart(BSTR service, VARIANT persistent, VARIANT *ret)
289 {
290 TRACE("(%p, %ls, %s, %p)\n", this, service, wine_dbgstr_variant(&persistent), ret);
291 return E_NOTIMPL;
292 }
293
294 HRESULT STDMETHODCALLTYPE CShellDispatch::ServiceStop(BSTR service, VARIANT persistent, VARIANT *ret)
295 {
296 TRACE("(%p, %ls, %s, %p)\n", this, service, wine_dbgstr_variant(&persistent), ret);
297 return E_NOTIMPL;
298 }
299
300 HRESULT STDMETHODCALLTYPE CShellDispatch::IsServiceRunning(BSTR name, VARIANT *running)
301 {
302 SERVICE_STATUS_PROCESS status;
303 SC_HANDLE scm, service;
304 DWORD dummy;
305
306 TRACE("(%s, %p)\n", debugstr_w(name), running);
307
308 V_VT(running) = VT_BOOL;
309 V_BOOL(running) = VARIANT_FALSE;
310
311 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
312 if (!scm)
313 {
314 ERR("failed to connect to service manager\n");
315 return S_OK;
316 }
317
318 service = OpenServiceW(scm, name, SERVICE_QUERY_STATUS);
319 if (!service)
320 {
321 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
322 CloseServiceHandle(scm);
323 return S_OK;
324 }
325
326 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (BYTE *)&status,
327 sizeof(SERVICE_STATUS_PROCESS), &dummy))
328 {
329 TRACE("failed to query service status (%u)\n", GetLastError());
330 CloseServiceHandle(service);
331 CloseServiceHandle(scm);
332 return S_OK;
333 }
334
335 if (status.dwCurrentState == SERVICE_RUNNING)
336 V_BOOL(running) = VARIANT_TRUE;
337
338 CloseServiceHandle(service);
339 CloseServiceHandle(scm);
340
341 return S_OK;
342 }
343
344 HRESULT STDMETHODCALLTYPE CShellDispatch::CanStartStopService(BSTR service, VARIANT *ret)
345 {
346 TRACE("(%p, %ls, %p)\n", this, service, ret);
347 return E_NOTIMPL;
348 }
349
350 HRESULT STDMETHODCALLTYPE CShellDispatch::ShowBrowserBar(BSTR clsid, VARIANT show, VARIANT *ret)
351 {
352 TRACE("(%p, %ls, %s, %p)\n", this, clsid, wine_dbgstr_variant(&show), ret);
353 return E_NOTIMPL;
354 }
355
356
357 // *** IShellDispatch3 methods ***
358 HRESULT STDMETHODCALLTYPE CShellDispatch::AddToRecent(VARIANT file, BSTR category)
359 {
360 TRACE("(%p, %s, %ls)\n", this, wine_dbgstr_variant(&file), category);
361 return E_NOTIMPL;
362 }
363
364
365 // *** IShellDispatch4 methods ***
366 HRESULT STDMETHODCALLTYPE CShellDispatch::WindowsSecurity()
367 {
368 TRACE("(%p)\n", this);
369 return E_NOTIMPL;
370 }
371
372 HRESULT STDMETHODCALLTYPE CShellDispatch::ToggleDesktop()
373 {
374 TRACE("(%p)\n", this);
375
376 HWND hTrayWnd = FindWindowW(L"Shell_TrayWnd", NULL);
377 PostMessageW(hTrayWnd, WM_COMMAND, TRAYCMD_TOGGLE_DESKTOP, 0);
378
379 return S_OK;
380 }
381
382 HRESULT STDMETHODCALLTYPE CShellDispatch::ExplorerPolicy(BSTR policy, VARIANT *value)
383 {
384 TRACE("(%p, %ls, %p)\n", this, policy, value);
385 return E_NOTIMPL;
386 }
387
388 HRESULT STDMETHODCALLTYPE CShellDispatch::GetSetting(LONG setting, VARIANT_BOOL *result)
389 {
390 TRACE("(%p, %lu, %p)\n", this, setting, result);
391 return E_NOTIMPL;
392 }
393
394
395 // *** IObjectSafety methods ***
396 HRESULT STDMETHODCALLTYPE CShellDispatch::GetInterfaceSafetyOptions(REFIID riid, DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions)
397 {
398 TRACE("(%p, %s, %p, %p)\n", this, wine_dbgstr_guid(&riid), pdwSupportedOptions, pdwEnabledOptions);
399 return E_NOTIMPL;
400 }
401
402 HRESULT STDMETHODCALLTYPE CShellDispatch::SetInterfaceSafetyOptions(REFIID riid, DWORD dwOptionSetMask, DWORD dwEnabledOptions)
403 {
404 TRACE("(%p, %s, %lu, %lu)\n", this, wine_dbgstr_guid(&riid), dwOptionSetMask, dwEnabledOptions);
405 return E_NOTIMPL;
406 }
407
408
409 // *** IObjectWithSite methods ***
410 HRESULT STDMETHODCALLTYPE CShellDispatch::SetSite(IUnknown *pUnkSite)
411 {
412 TRACE("(%p, %p)\n", this, pUnkSite);
413 return E_NOTIMPL;
414 }
415
416 HRESULT STDMETHODCALLTYPE CShellDispatch::GetSite(REFIID riid, PVOID *ppvSite)
417 {
418 TRACE("(%p, %s, %p)\n", this, wine_dbgstr_guid(&riid), ppvSite);
419 return E_NOTIMPL;
420 }
421
422 HRESULT WINAPI CShellDispatch_Constructor(REFIID riid, LPVOID * ppvOut)
423 {
424 return ShellObjectCreatorInit<CShellDispatch>(riid, ppvOut);
425 }
426