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