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 
426