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  *              Copyright 2023 Whindmar Saksit (whindsaks@proton.me)
8  */
9 
10 #include "precomp.h"
11 #include "winsvc.h"
12 
13 WINE_DEFAULT_DEBUG_CHANNEL(shell);
14 
15 
16 EXTERN_C DWORD WINAPI SHGetRestriction(LPCWSTR lpSubKey, LPCWSTR lpSubName, LPCWSTR lpValue);
17 
PostTrayCommand(UINT cmd)18 static HRESULT PostTrayCommand(UINT cmd)
19 {
20     HWND hTrayWnd = FindWindowW(L"Shell_TrayWnd", NULL);
21     return hTrayWnd && PostMessageW(hTrayWnd, WM_COMMAND, cmd, 0) ? S_OK : S_FALSE;
22 }
23 
CShellDispatch()24 CShellDispatch::CShellDispatch()
25 {
26 }
27 
~CShellDispatch()28 CShellDispatch::~CShellDispatch()
29 {
30 }
31 
Initialize()32 HRESULT CShellDispatch::Initialize()
33 {
34     return S_OK;
35 }
36 
37 // *** IShellDispatch methods ***
get_Application(IDispatch ** ppid)38 HRESULT STDMETHODCALLTYPE CShellDispatch::get_Application(IDispatch **ppid)
39 {
40     TRACE("(%p, %p)\n", this, ppid);
41 
42     if (!ppid)
43         return E_INVALIDARG;
44 
45     *ppid = this;
46     AddRef();
47 
48     return S_OK;
49 }
50 
get_Parent(IDispatch ** ppid)51 HRESULT STDMETHODCALLTYPE CShellDispatch::get_Parent(IDispatch **ppid)
52 {
53     TRACE("(%p, %p)\n", this, ppid);
54 
55     if (ppid)
56     {
57         *ppid = static_cast<IDispatch*>(this);
58         AddRef();
59     }
60 
61     return S_OK;
62 }
63 
VariantToIdlist(VARIANT * var,LPITEMIDLIST * idlist)64 HRESULT VariantToIdlist(VARIANT* var, LPITEMIDLIST* idlist)
65 {
66     HRESULT hr = E_FAIL;
67     if(V_VT(var) == VT_I4)
68     {
69         hr = SHGetSpecialFolderLocation(NULL, V_I4(var), idlist);
70     }
71     else if(V_VT(var) == VT_BSTR)
72     {
73         hr = SHILCreateFromPathW(V_BSTR(var), idlist, NULL);
74     }
75     return hr;
76 }
77 
NameSpace(VARIANT vDir,Folder ** ppsdf)78 HRESULT STDMETHODCALLTYPE CShellDispatch::NameSpace(VARIANT vDir, Folder **ppsdf)
79 {
80     TRACE("(%p, %s, %p)\n", this, debugstr_variant(&vDir), ppsdf);
81     if (!ppsdf)
82         return E_POINTER;
83     *ppsdf = NULL;
84     HRESULT hr;
85 
86     if (V_VT(&vDir) == VT_I2)
87     {
88         hr = VariantChangeType(&vDir, &vDir, 0, VT_I4);
89         if (FAILED_UNEXPECTEDLY(hr))
90             return hr;
91     }
92 
93     CComHeapPtr<ITEMIDLIST> idlist;
94     hr = VariantToIdlist(&vDir, &idlist);
95     if (!SUCCEEDED(hr))
96         return S_FALSE;
97 
98     return ShellObjectCreatorInit<CFolder>(static_cast<LPITEMIDLIST>(idlist), IID_PPV_ARG(Folder, ppsdf));
99 }
100 
is_optional_argument(const VARIANT * arg)101 static BOOL is_optional_argument(const VARIANT *arg)
102 {
103     return V_VT(arg) == VT_ERROR && V_ERROR(arg) == DISP_E_PARAMNOTFOUND;
104 }
105 
BrowseForFolder(LONG Hwnd,BSTR Title,LONG Options,VARIANT RootFolder,Folder ** ppsdf)106 HRESULT STDMETHODCALLTYPE CShellDispatch::BrowseForFolder(LONG Hwnd, BSTR Title, LONG Options, VARIANT RootFolder, Folder **ppsdf)
107 {
108     TRACE("(%p, %lu, %ls, %lu, %s, %p)\n", this, Hwnd, Title, Options, debugstr_variant(&RootFolder), ppsdf);
109 
110     *ppsdf = NULL;
111 
112     BROWSEINFOW bi = { 0 };
113     bi.hwndOwner = reinterpret_cast<HWND>(LongToHandle(Hwnd));
114     bi.lpszTitle = Title;
115     bi.ulFlags = Options | BIF_NEWDIALOGSTYLE;
116 
117     CComHeapPtr<ITEMIDLIST> idlist;
118     if (!is_optional_argument(&RootFolder) && VariantToIdlist(&RootFolder, &idlist) == S_OK)
119         bi.pidlRoot = idlist;
120 
121     CComHeapPtr<ITEMIDLIST> selection;
122     selection.Attach(SHBrowseForFolderW(&bi));
123     if (!selection)
124         return S_FALSE;
125 
126     return ShellObjectCreatorInit<CFolder>(static_cast<LPITEMIDLIST>(selection), IID_PPV_ARG(Folder, ppsdf));
127 }
128 
Windows(IDispatch ** ppid)129 HRESULT STDMETHODCALLTYPE CShellDispatch::Windows(IDispatch **ppid)
130 {
131     TRACE("(%p, %p)\n", this, ppid);
132     return CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_LOCAL_SERVER, IID_PPV_ARG(IDispatch, ppid));
133 }
134 
SHELL_OpenFolder(LPCITEMIDLIST pidl,LPCWSTR verb=NULL)135 static HRESULT SHELL_OpenFolder(LPCITEMIDLIST pidl, LPCWSTR verb = NULL)
136 {
137     SHELLEXECUTEINFOW sei;
138     sei.cbSize = sizeof(sei);
139     sei.fMask = SEE_MASK_IDLIST | SEE_MASK_FLAG_DDEWAIT;
140     sei.hwnd = NULL;
141     sei.lpVerb = verb;
142     sei.lpFile = sei.lpParameters = sei.lpDirectory = NULL;
143     sei.nShow = SW_SHOW;
144     sei.lpIDList = const_cast<LPITEMIDLIST>(pidl);
145     if (ShellExecuteExW(&sei))
146         return S_OK;
147     DWORD error = GetLastError();
148     return HRESULT_FROM_WIN32(error);
149 }
150 
OpenFolder(VARIANT vDir,LPCWSTR verb=NULL)151 static HRESULT OpenFolder(VARIANT vDir, LPCWSTR verb = NULL)
152 {
153     CComHeapPtr<ITEMIDLIST> idlist;
154     HRESULT hr = VariantToIdlist(&vDir, &idlist);
155     if (hr == S_OK && SHELL_OpenFolder(idlist, verb) == S_OK)
156     {
157         return S_OK;
158     }
159     return S_FALSE;
160 }
161 
Open(VARIANT vDir)162 HRESULT STDMETHODCALLTYPE CShellDispatch::Open(VARIANT vDir)
163 {
164     TRACE("(%p, %s)\n", this, debugstr_variant(&vDir));
165     return OpenFolder(vDir);
166 }
167 
Explore(VARIANT vDir)168 HRESULT STDMETHODCALLTYPE CShellDispatch::Explore(VARIANT vDir)
169 {
170     TRACE("(%p, %s)\n", this, debugstr_variant(&vDir));
171     return OpenFolder(vDir, L"explore");
172 }
173 
MinimizeAll()174 HRESULT STDMETHODCALLTYPE CShellDispatch::MinimizeAll()
175 {
176     TRACE("(%p)\n", this);
177     return PostTrayCommand(TRAYCMD_MINIMIZE_ALL);
178 }
179 
UndoMinimizeALL()180 HRESULT STDMETHODCALLTYPE CShellDispatch::UndoMinimizeALL()
181 {
182     TRACE("(%p)\n", this);
183     return PostTrayCommand(TRAYCMD_RESTORE_ALL);
184 }
185 
FileRun()186 HRESULT STDMETHODCALLTYPE CShellDispatch::FileRun()
187 {
188     TRACE("(%p)\n", this);
189     return PostTrayCommand(TRAYCMD_RUN_DIALOG);
190 }
191 
CascadeWindows()192 HRESULT STDMETHODCALLTYPE CShellDispatch::CascadeWindows()
193 {
194     TRACE("(%p)\n", this);
195     return PostTrayCommand(TRAYCMD_CASCADE);
196 }
197 
TileVertically()198 HRESULT STDMETHODCALLTYPE CShellDispatch::TileVertically()
199 {
200     TRACE("(%p)\n", this);
201     return PostTrayCommand(TRAYCMD_TILE_V);
202 }
203 
TileHorizontally()204 HRESULT STDMETHODCALLTYPE CShellDispatch::TileHorizontally()
205 {
206     TRACE("(%p)\n", this);
207     return PostTrayCommand(TRAYCMD_TILE_H);
208 }
209 
ShutdownWindows()210 HRESULT STDMETHODCALLTYPE CShellDispatch::ShutdownWindows()
211 {
212     ExitWindowsDialog(NULL);
213     return S_OK;
214 }
215 
Suspend()216 HRESULT STDMETHODCALLTYPE CShellDispatch::Suspend()
217 {
218     TRACE("(%p)\n", this);
219     return E_NOTIMPL;
220 }
221 
EjectPC()222 HRESULT STDMETHODCALLTYPE CShellDispatch::EjectPC()
223 {
224     TRACE("(%p)\n", this);
225     return E_NOTIMPL;
226 }
227 
SetTime()228 HRESULT STDMETHODCALLTYPE CShellDispatch::SetTime()
229 {
230     TRACE("(%p)\n", this);
231     return PostTrayCommand(TRAYCMD_DATE_AND_TIME);
232 }
233 
TrayProperties()234 HRESULT STDMETHODCALLTYPE CShellDispatch::TrayProperties()
235 {
236     TRACE("(%p)\n", this);
237     return PostTrayCommand(TRAYCMD_TASKBAR_PROPERTIES);
238 }
239 
Help()240 HRESULT STDMETHODCALLTYPE CShellDispatch::Help()
241 {
242     TRACE("(%p)\n", this);
243     return PostTrayCommand(TRAYCMD_HELP_AND_SUPPORT);
244 }
245 
FindFiles()246 HRESULT STDMETHODCALLTYPE CShellDispatch::FindFiles()
247 {
248     TRACE("(%p)\n", this);
249     return PostTrayCommand(TRAYCMD_SEARCH_FILES);
250 }
251 
FindComputer()252 HRESULT STDMETHODCALLTYPE CShellDispatch::FindComputer()
253 {
254     TRACE("(%p)\n", this);
255     return PostTrayCommand(TRAYCMD_SEARCH_COMPUTERS);
256 }
257 
RefreshMenu()258 HRESULT STDMETHODCALLTYPE CShellDispatch::RefreshMenu()
259 {
260     TRACE("(%p)\n", this);
261     return E_NOTIMPL;
262 }
263 
ControlPanelItem(BSTR szDir)264 HRESULT STDMETHODCALLTYPE CShellDispatch::ControlPanelItem(BSTR szDir)
265 {
266     TRACE("(%p, %ls)\n", this, szDir);
267     return SHRunControlPanel(szDir, NULL) ? S_OK : S_FALSE;
268 }
269 
270 
271 // *** IShellDispatch2 methods ***
IsRestricted(BSTR group,BSTR restriction,LONG * value)272 HRESULT STDMETHODCALLTYPE CShellDispatch::IsRestricted(BSTR group, BSTR restriction, LONG *value)
273 {
274     TRACE("(%p, %ls, %ls, %p)\n", this, group, restriction, value);
275 
276     if (!value)
277         return E_INVALIDARG;
278     *value = SHGetRestriction(NULL, group, restriction);
279     return S_OK;
280 }
281 
ShellExecute(BSTR file,VARIANT v_args,VARIANT v_dir,VARIANT v_op,VARIANT v_show)282 HRESULT STDMETHODCALLTYPE CShellDispatch::ShellExecute(BSTR file, VARIANT v_args, VARIANT v_dir, VARIANT v_op, VARIANT v_show)
283 {
284     CComVariant args_str, dir_str, op_str, show_int;
285     WCHAR *args = NULL, *dir = NULL, *op = NULL;
286     INT show = SW_SHOW;
287     HINSTANCE ret;
288 
289     TRACE("(%s, %s, %s, %s, %s)\n", debugstr_w(file), debugstr_variant(&v_args),
290             debugstr_variant(&v_dir), debugstr_variant(&v_op), debugstr_variant(&v_show));
291 
292     args_str.ChangeType(VT_BSTR, &v_args);
293     if (V_VT(&args_str) == VT_BSTR)
294         args = V_BSTR(&args_str);
295 
296     dir_str.ChangeType(VT_BSTR, &v_dir);
297     if (V_VT(&dir_str) == VT_BSTR)
298         dir = V_BSTR(&dir_str);
299 
300     op_str.ChangeType(VT_BSTR, &v_op);
301     if (V_VT(&op_str) == VT_BSTR)
302         op = V_BSTR(&op_str);
303 
304     show_int.ChangeType(VT_I4, &v_show);
305     if (V_VT(&show_int) == VT_I4)
306         show = V_I4(&show_int);
307 
308     ret = ShellExecuteW(NULL, op, file, args, dir, show);
309 
310     return (ULONG_PTR)ret > 32 ? S_OK : S_FALSE;
311 }
312 
FindPrinter(BSTR name,BSTR location,BSTR model)313 HRESULT STDMETHODCALLTYPE CShellDispatch::FindPrinter(BSTR name, BSTR location, BSTR model)
314 {
315     TRACE("(%p, %ls, %ls, %ls)\n", this, name, location, model);
316     return E_NOTIMPL;
317 }
318 
GetSystemInformation(BSTR name,VARIANT * ret)319 HRESULT STDMETHODCALLTYPE CShellDispatch::GetSystemInformation(BSTR name, VARIANT *ret)
320 {
321     TRACE("(%p, %ls, %p)\n", this, name, ret);
322 
323     if (!lstrcmpiW(name, L"ProcessorArchitecture"))
324     {
325         SYSTEM_INFO si;
326         GetSystemInfo(&si);
327         V_VT(ret) = VT_I4;
328         V_UI4(ret) = si.wProcessorArchitecture;
329         return S_OK;
330     }
331 
332     UINT os = 0;
333     if (!lstrcmpiW(name, L"IsOS_Professional"))
334         os = OS_PROFESSIONAL;
335     else if (!lstrcmpiW(name, L"IsOS_Personal"))
336         os = OS_HOME;
337     else if (!lstrcmpiW(name, L"IsOS_DomainMember"))
338         os = OS_DOMAINMEMBER;
339     if (os)
340     {
341         V_VT(ret) = VT_BOOL;
342         V_BOOL(ret) = IsOS(os) ? VARIANT_TRUE : VARIANT_FALSE;
343         return S_OK;
344     }
345 
346     return E_NOTIMPL;
347 }
348 
OpenServiceHelper(LPCWSTR name,DWORD access,SC_HANDLE & hSvc)349 static HRESULT OpenServiceHelper(LPCWSTR name, DWORD access, SC_HANDLE &hSvc)
350 {
351     hSvc = NULL;
352     SC_HANDLE hScm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
353     if (!hScm)
354         return HResultFromWin32(GetLastError());
355     HRESULT hr = S_OK;
356     hSvc = OpenServiceW(hScm, name, access);
357     if (!hSvc)
358         hr = HResultFromWin32(GetLastError());
359     CloseServiceHandle(hScm);
360     return hr;
361 }
362 
SHELL32_ControlService(BSTR name,DWORD control,VARIANT & persistent)363 static HRESULT SHELL32_ControlService(BSTR name, DWORD control, VARIANT &persistent)
364 {
365     BOOL persist = V_VT(&persistent) == VT_BOOL && V_BOOL(&persistent);
366     DWORD access = persist ? SERVICE_CHANGE_CONFIG : 0;
367     switch (control)
368     {
369         case 0:
370             access |= SERVICE_START;
371             break;
372         case SERVICE_CONTROL_STOP:
373             access |= SERVICE_STOP;
374             break;
375     }
376     SC_HANDLE hSvc;
377     HRESULT hr = OpenServiceHelper(name, access, hSvc);
378     if (SUCCEEDED(hr))
379     {
380         BOOL success;
381         DWORD error, already;
382         if (control)
383         {
384             SERVICE_STATUS ss;
385             success = ControlService(hSvc, control, &ss);
386             error = GetLastError();
387             already = ERROR_SERVICE_NOT_ACTIVE;
388         }
389         else
390         {
391             success = StartService(hSvc, 0, NULL);
392             error = GetLastError();
393             already = ERROR_SERVICE_ALREADY_RUNNING;
394         }
395         hr = success ? S_OK : error == already ? S_FALSE : HRESULT_FROM_WIN32(error);
396         if (SUCCEEDED(hr) && persist)
397         {
398             ChangeServiceConfigW(hSvc, SERVICE_NO_CHANGE,
399                                  control ? SERVICE_DEMAND_START : SERVICE_AUTO_START,
400                                  SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
401         }
402         CloseServiceHandle(hSvc);
403     }
404     return hr;
405 }
406 
ServiceStart(BSTR service,VARIANT persistent,VARIANT * ret)407 HRESULT STDMETHODCALLTYPE CShellDispatch::ServiceStart(BSTR service, VARIANT persistent, VARIANT *ret)
408 {
409     TRACE("(%p, %ls, %s, %p)\n", this, service, wine_dbgstr_variant(&persistent), ret);
410 
411     HRESULT hr = SHELL32_ControlService(service, 0, persistent);
412     V_VT(ret) = VT_BOOL;
413     V_BOOL(ret) = (hr == S_OK ? VARIANT_TRUE : VARIANT_FALSE);
414     return hr == S_OK ? S_OK : S_FALSE;
415 }
416 
ServiceStop(BSTR service,VARIANT persistent,VARIANT * ret)417 HRESULT STDMETHODCALLTYPE CShellDispatch::ServiceStop(BSTR service, VARIANT persistent, VARIANT *ret)
418 {
419     TRACE("(%p, %ls, %s, %p)\n", this, service, wine_dbgstr_variant(&persistent), ret);
420 
421     HRESULT hr = SHELL32_ControlService(service, SERVICE_CONTROL_STOP, persistent);
422     V_VT(ret) = VT_BOOL;
423     V_BOOL(ret) = (hr == S_OK ? VARIANT_TRUE : VARIANT_FALSE);
424     return hr == S_OK ? S_OK : S_FALSE;
425 }
426 
IsServiceRunning(BSTR name,VARIANT * running)427 HRESULT STDMETHODCALLTYPE CShellDispatch::IsServiceRunning(BSTR name, VARIANT *running)
428 {
429     SERVICE_STATUS_PROCESS status;
430     SC_HANDLE scm, service;
431     DWORD dummy;
432 
433     TRACE("(%s, %p)\n", debugstr_w(name), running);
434 
435     V_VT(running) = VT_BOOL;
436     V_BOOL(running) = VARIANT_FALSE;
437 
438     scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
439     if (!scm)
440     {
441         ERR("failed to connect to service manager\n");
442         return S_OK;
443     }
444 
445     service = OpenServiceW(scm, name, SERVICE_QUERY_STATUS);
446     if (!service)
447     {
448         ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
449         CloseServiceHandle(scm);
450         return S_OK;
451     }
452 
453     if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (BYTE *)&status,
454                               sizeof(SERVICE_STATUS_PROCESS), &dummy))
455     {
456         TRACE("failed to query service status (%u)\n", GetLastError());
457         CloseServiceHandle(service);
458         CloseServiceHandle(scm);
459         return S_OK;
460     }
461 
462     if (status.dwCurrentState == SERVICE_RUNNING)
463         V_BOOL(running) = VARIANT_TRUE;
464 
465     CloseServiceHandle(service);
466     CloseServiceHandle(scm);
467 
468     return S_OK;
469 }
470 
CanStartStopService(BSTR service,VARIANT * ret)471 HRESULT STDMETHODCALLTYPE CShellDispatch::CanStartStopService(BSTR service, VARIANT *ret)
472 {
473     TRACE("(%p, %ls, %p)\n", this, service, ret);
474 
475     SC_HANDLE hSvc;
476     HRESULT hr = OpenServiceHelper(service, SERVICE_START | SERVICE_STOP, hSvc);
477     if (SUCCEEDED(hr))
478         CloseServiceHandle(hSvc);
479     V_VT(ret) = VT_BOOL;
480     V_BOOL(ret) = (hr == S_OK ? VARIANT_TRUE : VARIANT_FALSE);
481     return S_OK;
482 }
483 
ShowBrowserBar(BSTR clsid,VARIANT show,VARIANT * ret)484 HRESULT STDMETHODCALLTYPE CShellDispatch::ShowBrowserBar(BSTR clsid, VARIANT show, VARIANT *ret)
485 {
486     TRACE("(%p, %ls, %s, %p)\n", this, clsid, wine_dbgstr_variant(&show), ret);
487     return E_NOTIMPL;
488 }
489 
490 
491 // *** IShellDispatch3 methods ***
AddToRecent(VARIANT file,BSTR category)492 HRESULT STDMETHODCALLTYPE CShellDispatch::AddToRecent(VARIANT file, BSTR category)
493 {
494     TRACE("(%p, %s, %ls)\n", this, wine_dbgstr_variant(&file), category);
495 
496     CComHeapPtr<ITEMIDLIST> idlist;
497     HRESULT hr = VariantToIdlist(&file, &idlist);
498     if (hr == S_OK)
499         SHAddToRecentDocs(SHARD_PIDL, (LPCITEMIDLIST)idlist);
500     else
501         hr = S_FALSE;
502     return hr;
503 }
504 
505 
506 // *** IShellDispatch4 methods ***
507 #define IDM_SECURITY 5001 // From base/shell/explorer/resource.h
WindowsSecurity()508 HRESULT STDMETHODCALLTYPE CShellDispatch::WindowsSecurity()
509 {
510     TRACE("(%p)\n", this);
511     return PostTrayCommand(IDM_SECURITY);
512 }
513 
ToggleDesktop()514 HRESULT STDMETHODCALLTYPE CShellDispatch::ToggleDesktop()
515 {
516     TRACE("(%p)\n", this);
517     return PostTrayCommand(TRAYCMD_TOGGLE_DESKTOP);
518 }
519 
ExplorerPolicy(BSTR policy,VARIANT * value)520 HRESULT STDMETHODCALLTYPE CShellDispatch::ExplorerPolicy(BSTR policy, VARIANT *value)
521 {
522     TRACE("(%p, %ls, %p)\n", this, policy, value);
523     return E_NOTIMPL;
524 }
525 
526 #ifndef SSF_SERVERADMINUI
527 #define SSF_SERVERADMINUI 4
528 #endif
GetSetting(LONG setting,VARIANT_BOOL * result)529 HRESULT STDMETHODCALLTYPE CShellDispatch::GetSetting(LONG setting, VARIANT_BOOL *result)
530 {
531     TRACE("(%p, %lu, %p)\n", this, setting, result);
532 
533     int flag = -1;
534     SHELLSTATE ss = { };
535     SHGetSetSettings(&ss, setting, FALSE);
536     switch (setting)
537     {
538         case SSF_SHOWALLOBJECTS:   flag = ss.fShowAllObjects;     break;
539         case SSF_SHOWEXTENSIONS:   flag = ss.fShowExtensions;     break;
540         case SSF_SHOWSYSFILES:     flag = ss.fShowSysFiles;       break;
541         case SSF_DONTPRETTYPATH:   flag = ss.fDontPrettyPath;     break;
542         case SSF_NOCONFIRMRECYCLE: flag = ss.fNoConfirmRecycle;   break;
543         case SSF_SHOWSUPERHIDDEN:  flag = ss.fShowSuperHidden;    break;
544         case SSF_SEPPROCESS:       flag = ss.fSepProcess;         break;
545         case SSF_STARTPANELON:     flag = ss.fStartPanelOn;       break;
546         case SSF_SERVERADMINUI:    flag = IsOS(OS_SERVERADMINUI); break;
547     }
548     if (flag >= 0)
549     {
550         *result = flag ? VARIANT_TRUE : VARIANT_FALSE;
551         return S_OK;
552     }
553 
554     return S_FALSE;
555 }
556 
557 
558 // *** IObjectSafety methods ***
GetInterfaceSafetyOptions(REFIID riid,DWORD * pdwSupportedOptions,DWORD * pdwEnabledOptions)559 HRESULT STDMETHODCALLTYPE CShellDispatch::GetInterfaceSafetyOptions(REFIID riid, DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions)
560 {
561     TRACE("(%p, %s, %p, %p)\n", this, wine_dbgstr_guid(&riid), pdwSupportedOptions, pdwEnabledOptions);
562     return E_NOTIMPL;
563 }
564 
SetInterfaceSafetyOptions(REFIID riid,DWORD dwOptionSetMask,DWORD dwEnabledOptions)565 HRESULT STDMETHODCALLTYPE CShellDispatch::SetInterfaceSafetyOptions(REFIID riid, DWORD dwOptionSetMask, DWORD dwEnabledOptions)
566 {
567     TRACE("(%p, %s, %lu, %lu)\n", this, wine_dbgstr_guid(&riid), dwOptionSetMask, dwEnabledOptions);
568     return E_NOTIMPL;
569 }
570 
571 
572 // *** IObjectWithSite methods ***
SetSite(IUnknown * pUnkSite)573 HRESULT STDMETHODCALLTYPE CShellDispatch::SetSite(IUnknown *pUnkSite)
574 {
575     TRACE("(%p, %p)\n", this, pUnkSite);
576     return E_NOTIMPL;
577 }
578 
GetSite(REFIID riid,PVOID * ppvSite)579 HRESULT STDMETHODCALLTYPE CShellDispatch::GetSite(REFIID riid, PVOID *ppvSite)
580 {
581     TRACE("(%p, %s, %p)\n", this, wine_dbgstr_guid(&riid), ppvSite);
582     return E_NOTIMPL;
583 }
584 
CShellDispatch_Constructor(REFIID riid,LPVOID * ppvOut)585 HRESULT WINAPI CShellDispatch_Constructor(REFIID riid, LPVOID * ppvOut)
586 {
587     return ShellObjectCreatorInit<CShellDispatch>(riid, ppvOut);
588 }
589 
590