Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1146 lines
36 KiB

  1. #include "precomp.h"
  2. #pragma hdrstop
  3. #include "cmnquery.h"
  4. #include "dsquery.h"
  5. #include "startids.h"
  6. #include "dsgetdc.h"
  7. #include "lm.h"
  8. #include "winldap.h"
  9. #include "activeds.h"
  10. #include "shconv.h"
  11. // This is the implementation for the Shell Application level IDispatch
  12. // Currently we will try to maintain only one object per process.
  13. // Note: these define's must match those in explorer\rcids.h
  14. #define IDM_SYSBUTTON 300
  15. #define IDM_FINDBUTTON 301
  16. #define IDM_HELPBUTTON 302
  17. #define IDM_FILERUN 401
  18. #define IDM_CASCADE 403
  19. #define IDM_HORIZTILE 404
  20. #define IDM_VERTTILE 405
  21. #define IDM_DESKTOPARRANGEGRID 406
  22. #define IDM_TOGGLEDESKTOP 407
  23. #define IDM_SETTIME 408
  24. #define IDM_SUSPEND 409
  25. #define IDM_EJECTPC 410
  26. #define IDM_TASKLIST 412
  27. #define IDM_TRAYPROPERTIES 413
  28. #define IDM_EDITSTARTMENU 414
  29. #define IDM_MINIMIZEALL 415
  30. #define IDM_UNDO 416
  31. #define IDM_RETURN 417
  32. #define IDM_PRINTNOTIFY_FOLDER 418
  33. #define IDM_MINIMIZEALLHOTKEY 419
  34. #define IDM_SHOWTASKMAN 420
  35. #define IDM_RECENT 501
  36. #define IDM_FIND 502
  37. #define IDM_PROGRAMS 504
  38. #define IDM_CONTROLS 505
  39. #define IDM_EXITWIN 506
  40. // #define IDM_FONTS 509
  41. #define IDM_PRINTERS 510
  42. #define IDM_STARTMENU 511
  43. #define IDM_MYCOMPUTER 512
  44. #define IDM_PROGRAMSINIT 513
  45. #define IDM_RECENTINIT 514
  46. #define IDM_MENU_FIND 520
  47. #define TRAY_IDM_FINDFIRST 521 // this range
  48. #define TRAY_IDM_FINDLAST 550 // is reserved for find command
  49. #define IDM_RECENTLIST 650
  50. #define IDM_QUICKTIPS 800
  51. #define IDM_HELPCONT 801
  52. #define IDM_WIZARDS 802
  53. #define IDM_USEHELP 803 // REVIEW: probably won't be used
  54. #define IDM_TUTORIAL 804
  55. #define IDM_ABOUT 805
  56. #define IDM_LAST_MENU_ITEM IDM_ABOUT
  57. #define FCIDM_FIRST FCIDM_GLOBALFIRST
  58. #define FCIDM_LAST FCIDM_BROWSERLAST
  59. //#define FCIDM_FINDFILES (FCIDM_BROWSER_TOOLS+0x0005)
  60. #define FCIDM_FINDCOMPUTER (FCIDM_BROWSER_TOOLS+0x0006)
  61. //============================================================================
  62. class CShellDispatch : public IShellDispatch4,
  63. public CObjectSafety,
  64. protected CImpIDispatch,
  65. public CObjectWithSite
  66. {
  67. friend class CAdviseRouter;
  68. friend HRESULT GetApplicationObject(DWORD dwSafetyOptions, IUnknown *punkSite, IDispatch **ppid);
  69. public:
  70. // Non-delegating object IUnknown
  71. STDMETHODIMP QueryInterface(REFIID, void **);
  72. STDMETHODIMP_(ULONG) AddRef(void);
  73. STDMETHODIMP_(ULONG) Release(void);
  74. // IDispatch members
  75. STDMETHODIMP GetTypeInfoCount(UINT * pctinfo)
  76. { return CImpIDispatch::GetTypeInfoCount(pctinfo); }
  77. STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo **pptinfo)
  78. { return CImpIDispatch::GetTypeInfo(itinfo, lcid, pptinfo); }
  79. STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID * rgdispid)
  80. { return CImpIDispatch::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid); }
  81. STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo, UINT * puArgErr)
  82. { return CImpIDispatch::Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr); }
  83. // IShellDispatch
  84. STDMETHODIMP get_Application(IDispatch **ppid);
  85. STDMETHODIMP get_Parent (IDispatch **ppid);
  86. STDMETHOD(Open)(THIS_ VARIANT vDir);
  87. STDMETHOD(Explore)(THIS_ VARIANT vDir);
  88. STDMETHOD(NameSpace)(THIS_ VARIANT vDir, Folder **ppsdf);
  89. STDMETHODIMP BrowseForFolder(long hwnd, BSTR Title, long Options, VARIANT vRoot, Folder **ppsdf);
  90. STDMETHODIMP ControlPanelItem(BSTR szDir);
  91. STDMETHODIMP MinimizeAll(void);
  92. STDMETHODIMP UndoMinimizeALL(void);
  93. STDMETHODIMP FileRun(void);
  94. STDMETHODIMP CascadeWindows(void);
  95. STDMETHODIMP TileVertically(void);
  96. STDMETHODIMP TileHorizontally(void);
  97. STDMETHODIMP ShutdownWindows(void);
  98. STDMETHODIMP Suspend(void);
  99. STDMETHODIMP EjectPC(void);
  100. STDMETHODIMP SetTime(void);
  101. STDMETHODIMP TrayProperties(void);
  102. STDMETHODIMP Help(void);
  103. STDMETHODIMP FindFiles(void);
  104. STDMETHODIMP FindComputer(void);
  105. STDMETHODIMP RefreshMenu(void);
  106. STDMETHODIMP Windows(IDispatch **ppid);
  107. STDMETHODIMP get_ObjectCount(int *pcObjs);
  108. STDMETHODIMP IsRestricted(BSTR Group, BSTR Restriction, long * lpValue);
  109. STDMETHODIMP ShellExecute(BSTR File, VARIANT vArgs, VARIANT vDir, VARIANT vOperation, VARIANT vShow);
  110. STDMETHODIMP FindPrinter(BSTR name, BSTR location, BSTR model);
  111. STDMETHODIMP GetSystemInformation(BSTR name, VARIANT * pvOut);
  112. STDMETHODIMP ServiceStart(BSTR ServiceName, VARIANT Persistent, VARIANT *pSuccess);
  113. STDMETHODIMP ServiceStop(BSTR ServiceName, VARIANT Persistent, VARIANT *pSuccess);
  114. STDMETHODIMP IsServiceRunning(BSTR ServiceName, VARIANT *pRunning);
  115. STDMETHODIMP CanStartStopService(BSTR ServiceName, VARIANT *pCanStartStop);
  116. STDMETHODIMP ShowBrowserBar(BSTR bstrClsid, VARIANT bShow, VARIANT *pSuccess);
  117. // IShellDispatch3
  118. STDMETHODIMP AddToRecent(VARIANT varFile, BSTR bstrCategory);
  119. // IShellDispatch4
  120. STDMETHODIMP WindowsSecurity();
  121. STDMETHODIMP ToggleDesktop();
  122. STDMETHODIMP ExplorerPolicy(BSTR bstrName, VARIANT *pValue);
  123. STDMETHODIMP GetSetting(long lSetting, VARIANT_BOOL *pValue);
  124. // Constructor and the like..
  125. CShellDispatch(void);
  126. protected:
  127. LONG _cRef;
  128. ~CShellDispatch(void);
  129. HRESULT _SecurityCheck(void); // Check if we are in paranoid mode...
  130. HRESULT _TrayCommand(UINT idCmd);
  131. HRESULT ExecuteFolder(VARIANT vDir, LPCTSTR pszVerb);
  132. VARIANT_BOOL _ServiceStartStop(BSTR ServiceName, BOOL fStart, BOOL fPersist);
  133. HWND _GetWindow();
  134. };
  135. STDAPI CShellDispatch_CreateInstance(IUnknown* pUnkOuter, REFIID riid, void **ppvOut)
  136. {
  137. HRESULT hr = E_OUTOFMEMORY;
  138. *ppvOut = NULL;
  139. // aggregation checking is handled in class factory
  140. CShellDispatch * pshd = new CShellDispatch();
  141. if (pshd)
  142. {
  143. hr = pshd->QueryInterface(riid, ppvOut);
  144. pshd->Release();
  145. }
  146. return hr;
  147. }
  148. CShellDispatch::CShellDispatch(void) : _cRef(1), CImpIDispatch(SDSPATCH_TYPELIB, IID_IShellDispatch4)
  149. {
  150. DllAddRef();
  151. }
  152. CShellDispatch::~CShellDispatch(void)
  153. {
  154. DllRelease();
  155. }
  156. HRESULT CShellDispatch::_SecurityCheck(void)
  157. {
  158. return (!_dwSafetyOptions || (IsSafePage(_punkSite) == S_OK)) ? S_OK : E_ACCESSDENIED;
  159. }
  160. STDMETHODIMP CShellDispatch::QueryInterface(REFIID riid, void **ppv)
  161. {
  162. static const QITAB qit[] = {
  163. QITABENT(CShellDispatch, IShellDispatch4),
  164. QITABENTMULTI(CShellDispatch, IShellDispatch3, IShellDispatch4),
  165. QITABENTMULTI(CShellDispatch, IShellDispatch2, IShellDispatch4),
  166. QITABENTMULTI(CShellDispatch, IShellDispatch, IShellDispatch4),
  167. QITABENTMULTI(CShellDispatch, IDispatch, IShellDispatch4),
  168. QITABENT(CShellDispatch, IObjectSafety),
  169. QITABENT(CShellDispatch, IObjectWithSite),
  170. { 0 },
  171. };
  172. return QISearch(this, qit, riid, ppv);
  173. }
  174. STDMETHODIMP_(ULONG) CShellDispatch::AddRef(void)
  175. {
  176. return InterlockedIncrement(&_cRef);
  177. }
  178. STDMETHODIMP_(ULONG) CShellDispatch::Release(void)
  179. {
  180. ASSERT( 0 != _cRef );
  181. ULONG cRef = InterlockedDecrement(&_cRef);
  182. if ( 0 == cRef )
  183. {
  184. delete this;
  185. }
  186. return cRef;
  187. }
  188. // Helper function to process commands to the tray.
  189. HRESULT CShellDispatch::_TrayCommand(UINT idCmd)
  190. {
  191. HRESULT hr = _SecurityCheck();
  192. if (SUCCEEDED(hr))
  193. {
  194. // APPHACK! 221008 DesktopX creates their own window with class
  195. // name "Shell_TrayWnd", so if we're not careful we will end
  196. // posting the messages to the wrong window. They create their
  197. // window with the title "CTrayServer"; ours has a null title.
  198. // Use the null title to find the correct window.
  199. HWND hwndTray = FindWindowA(WNDCLASS_TRAYNOTIFY, "");
  200. if (hwndTray)
  201. PostMessage(hwndTray, WM_COMMAND, idCmd, 0);
  202. hr = NOERROR;
  203. }
  204. return hr;
  205. }
  206. STDMETHODIMP CShellDispatch::get_Application(IDispatch **ppid)
  207. {
  208. return QueryInterface(IID_PPV_ARG(IDispatch, ppid));
  209. }
  210. STDMETHODIMP CShellDispatch::get_Parent(IDispatch **ppid)
  211. {
  212. return QueryInterface(IID_PPV_ARG(IDispatch, ppid));
  213. }
  214. HRESULT CShellDispatch::ExecuteFolder(VARIANT vDir, LPCTSTR pszVerb)
  215. {
  216. // Check to see if we allow the user to do this...
  217. HRESULT hr = _SecurityCheck();
  218. if (SUCCEEDED(hr))
  219. {
  220. SHELLEXECUTEINFO sei = { sizeof(sei), 0 };
  221. sei.lpIDList = (void *)VariantToIDList(&vDir);
  222. if (sei.lpIDList)
  223. {
  224. // Everything should have been initialize to 0
  225. // BUGBUG:: Should be invoke idlist but that is failing when
  226. // explore
  227. sei.fMask = SEE_MASK_IDLIST;
  228. sei.nShow = SW_SHOWNORMAL;
  229. sei.lpVerb = pszVerb;
  230. hr = ShellExecuteEx(&sei) ? NOERROR : S_FALSE;
  231. ILFree((LPITEMIDLIST)sei.lpIDList);
  232. }
  233. else
  234. {
  235. hr = S_FALSE; // bad dir
  236. }
  237. }
  238. return hr;
  239. }
  240. STDMETHODIMP CShellDispatch::Open(VARIANT vDir)
  241. {
  242. return ExecuteFolder(vDir, NULL);
  243. }
  244. STDMETHODIMP CShellDispatch::Explore(VARIANT vDir)
  245. {
  246. return ExecuteFolder(vDir, TEXT("explore"));
  247. }
  248. STDMETHODIMP CShellDispatch::NameSpace(VARIANT vDir, Folder **ppsdf)
  249. {
  250. *ppsdf = NULL;
  251. HRESULT hr = _SecurityCheck();
  252. if (SUCCEEDED(hr))
  253. {
  254. LPITEMIDLIST pidl = VariantToIDList(&vDir);
  255. if (pidl)
  256. {
  257. hr = CFolder_Create(NULL, pidl, NULL, IID_PPV_ARG(Folder, ppsdf));
  258. if (SUCCEEDED(hr))
  259. {
  260. IUnknown_SetSite(*ppsdf, _punkSite);
  261. if (_dwSafetyOptions)
  262. {
  263. hr = MakeSafeForScripting((IUnknown**)ppsdf);
  264. }
  265. }
  266. ILFree(pidl);
  267. }
  268. else
  269. hr = S_FALSE; // bad dir
  270. }
  271. return hr;
  272. }
  273. STDMETHODIMP CShellDispatch::IsRestricted(BSTR Group, BSTR Restriction, long * lpValue)
  274. {
  275. HRESULT hr = _SecurityCheck();
  276. if (SUCCEEDED(hr))
  277. {
  278. if (lpValue)
  279. *lpValue = SHGetRestriction(NULL, Group, Restriction);
  280. }
  281. return hr;
  282. }
  283. STDMETHODIMP CShellDispatch::ShellExecute(BSTR File, VARIANT vArgs, VARIANT vDir, VARIANT vOperation, VARIANT vShow)
  284. {
  285. SHELLEXECUTEINFO sei = {sizeof(SHELLEXECUTEINFO)};
  286. TCHAR szFile[MAX_PATH];
  287. TCHAR szDir[MAX_PATH];
  288. TCHAR szOper[128]; // don't think any verb longer than this...
  289. // Check to see if we allow the user to do this...
  290. HRESULT hr = _SecurityCheck();
  291. if (SUCCEEDED(hr))
  292. {
  293. // Initialize the shellexecute structure...
  294. sei.nShow = SW_SHOWNORMAL;
  295. // Ok setup the FileName.
  296. SHUnicodeToTChar(File, szFile, ARRAYSIZE(szFile));
  297. sei.lpFile = szFile;
  298. // Now the Args
  299. sei.lpParameters = VariantToStr(&vArgs, NULL, 0);
  300. sei.lpDirectory = VariantToStr(&vDir, szDir, ARRAYSIZE(szDir));
  301. sei.lpVerb = VariantToStr(&vOperation, szOper, ARRAYSIZE(szOper));
  302. // Finally the show -- Could use convert, but that takes 3 calls...
  303. if (vShow.vt == (VT_BYREF|VT_VARIANT) && vShow.pvarVal)
  304. vShow = *vShow.pvarVal;
  305. switch (vShow.vt)
  306. {
  307. case VT_I2:
  308. sei.nShow = (int)vShow.iVal;
  309. break;
  310. case VT_I4:
  311. sei.nShow = (int)vShow.lVal;
  312. }
  313. hr = ShellExecuteEx(&sei) ? NOERROR : S_FALSE;
  314. // Cleanup anything we allocated
  315. if (sei.lpParameters)
  316. LocalFree((HLOCAL)sei.lpParameters);
  317. }
  318. return hr;
  319. }
  320. //
  321. // These next few methods deal with NT services in general, and the
  322. // Content Indexing Service in particular, so they're stubbed out
  323. // to return E_NOTIMPL on Win9x.
  324. //
  325. //
  326. // Helper function for ServiceStart and ServiceStop
  327. //
  328. VARIANT_BOOL CShellDispatch::_ServiceStartStop(BSTR ServiceName, BOOL fStart, BOOL fPersistent)
  329. {
  330. VARIANT_BOOL fRetVal = VARIANT_FALSE;
  331. #ifdef WINNT
  332. SC_HANDLE hSc = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  333. if (hSc)
  334. {
  335. SC_HANDLE hSvc = OpenServiceW(hSc, ServiceName,
  336. (fStart ? SERVICE_START : SERVICE_STOP) | (fPersistent ? SERVICE_CHANGE_CONFIG : 0));
  337. if (hSvc)
  338. {
  339. if (fPersistent)
  340. {
  341. ChangeServiceConfig(hSvc, SERVICE_NO_CHANGE,
  342. (fStart ? SERVICE_AUTO_START : SERVICE_DEMAND_START),
  343. SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
  344. }
  345. if (fStart)
  346. {
  347. if (StartService(hSvc, 0, NULL))
  348. fRetVal = VARIANT_TRUE;
  349. }
  350. else
  351. {
  352. SERVICE_STATUS ServiceStatus;
  353. if (ControlService(hSvc, SERVICE_CONTROL_STOP, &ServiceStatus))
  354. fRetVal = VARIANT_TRUE;
  355. }
  356. CloseServiceHandle(hSvc);
  357. }
  358. CloseServiceHandle(hSc);
  359. }
  360. #endif // WINNT
  361. return fRetVal;
  362. }
  363. STDMETHODIMP CShellDispatch::ServiceStart(BSTR ServiceName, VARIANT Persistent, VARIANT *pSuccess)
  364. {
  365. // Check to see if we allow the user to do this...
  366. HRESULT hr = _SecurityCheck();
  367. if (SUCCEEDED(hr))
  368. {
  369. if (VT_BOOL != Persistent.vt)
  370. {
  371. hr = E_INVALIDARG;
  372. }
  373. else
  374. {
  375. VariantClear(pSuccess);
  376. pSuccess->vt = VT_BOOL;
  377. pSuccess->boolVal = _ServiceStartStop(ServiceName, TRUE, Persistent.boolVal);
  378. }
  379. }
  380. return hr;
  381. }
  382. STDMETHODIMP CShellDispatch::ServiceStop(BSTR ServiceName, VARIANT Persistent, VARIANT *pSuccess)
  383. {
  384. // Check to see if we allow the user to do this...
  385. HRESULT hr = _SecurityCheck();
  386. if (SUCCEEDED(hr))
  387. {
  388. if (VT_BOOL != Persistent.vt)
  389. {
  390. hr = E_INVALIDARG;
  391. }
  392. else
  393. {
  394. VariantClear(pSuccess);
  395. pSuccess->vt = VT_BOOL;
  396. pSuccess->boolVal = _ServiceStartStop(ServiceName, FALSE, Persistent.boolVal);
  397. }
  398. }
  399. return hr;
  400. }
  401. STDMETHODIMP CShellDispatch::IsServiceRunning(BSTR ServiceName, VARIANT *pIsRunning)
  402. {
  403. VariantClear(pIsRunning);
  404. pIsRunning->vt = VT_BOOL;
  405. pIsRunning->boolVal = VARIANT_FALSE;
  406. HRESULT hr = _SecurityCheck();
  407. if (SUCCEEDED(hr))
  408. {
  409. SC_HANDLE hSc = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  410. if (hSc)
  411. {
  412. SC_HANDLE hSvc = OpenService(hSc, ServiceName, SERVICE_QUERY_STATUS);
  413. if (hSvc)
  414. {
  415. SERVICE_STATUS ServiceStatus;
  416. if (QueryServiceStatus(hSvc, &ServiceStatus))
  417. {
  418. switch (ServiceStatus.dwCurrentState)
  419. {
  420. case SERVICE_START_PENDING:
  421. case SERVICE_RUNNING:
  422. case SERVICE_CONTINUE_PENDING:
  423. pIsRunning->boolVal = VARIANT_TRUE;
  424. break;
  425. }
  426. }
  427. CloseServiceHandle(hSvc);
  428. }
  429. CloseServiceHandle(hSc);
  430. }
  431. }
  432. return hr;
  433. }
  434. STDMETHODIMP CShellDispatch::CanStartStopService(BSTR ServiceName, VARIANT *pCanStartStop)
  435. {
  436. VariantClear(pCanStartStop);
  437. pCanStartStop->vt = VT_BOOL;
  438. pCanStartStop->boolVal = VARIANT_FALSE;
  439. HRESULT hr = _SecurityCheck();
  440. if (SUCCEEDED(hr))
  441. {
  442. SC_HANDLE hSc = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  443. if (hSc)
  444. {
  445. SC_HANDLE hSvc = OpenService(hSc, ServiceName, SERVICE_START | SERVICE_STOP | SERVICE_CHANGE_CONFIG);
  446. if (hSvc)
  447. {
  448. pCanStartStop->boolVal = VARIANT_TRUE;
  449. CloseServiceHandle(hSvc);
  450. }
  451. else
  452. {
  453. DWORD dwErr = GetLastError();
  454. }
  455. CloseServiceHandle(hSc);
  456. }
  457. }
  458. return hr;
  459. }
  460. STDMETHODIMP CShellDispatch::ShowBrowserBar(BSTR bstrClsid, VARIANT varShow, VARIANT *pSuccess)
  461. {
  462. if (!(bstrClsid && *bstrClsid && pSuccess))
  463. return E_INVALIDARG ;
  464. pSuccess->vt = VT_BOOL ;
  465. pSuccess->boolVal = VARIANT_FALSE ;
  466. IWebBrowser2* pb2;
  467. HRESULT hr = _SecurityCheck();
  468. if (SUCCEEDED(hr))
  469. {
  470. hr = IUnknown_QueryServiceForWebBrowserApp(_punkSite, IID_PPV_ARG(IWebBrowser2, &pb2));
  471. if (SUCCEEDED(hr))
  472. {
  473. VARIANT varGuid;
  474. VARIANT varNil = {0};
  475. varGuid.vt = VT_BSTR ;
  476. varGuid.bstrVal = bstrClsid ;
  477. hr = pb2->ShowBrowserBar(&varGuid, &varShow, &varNil) ;
  478. if (SUCCEEDED(hr))
  479. pSuccess->boolVal = VARIANT_TRUE;
  480. pb2->Release();
  481. }
  482. }
  483. return hr;
  484. }
  485. HWND CShellDispatch::_GetWindow()
  486. {
  487. HWND hwnd = NULL;
  488. // NOTE: very container specific, but works in .HTM pages. generalize for other
  489. // containers. note that this is not a OLE Control, so we don't have a client
  490. // site. jscript is typically the provider of _punkSite.
  491. IShellBrowser* psb;
  492. if (SUCCEEDED(IUnknown_QueryService(_punkSite, SID_SShellBrowser, IID_PPV_ARG(IShellBrowser, &psb))))
  493. {
  494. IUnknown_GetWindow(psb, &hwnd);
  495. psb->Release();
  496. }
  497. return hwnd;
  498. }
  499. // NOTICE:
  500. // the hwnd param is bogus, no script/vb client has access to this. pass 0 and this
  501. // code will compute this from the site.
  502. STDMETHODIMP CShellDispatch::BrowseForFolder(long hwnd, BSTR Title, long Options,
  503. VARIANT vRoot, Folder **ppsdf)
  504. {
  505. *ppsdf = NULL;
  506. HRESULT hr = _SecurityCheck();
  507. if (SUCCEEDED(hr))
  508. {
  509. BROWSEINFO bi = {0};
  510. TCHAR szTitle[MAX_PATH];
  511. SHUnicodeToTChar(Title, szTitle, ARRAYSIZE(szTitle));
  512. bi.lpszTitle = szTitle;
  513. bi.hwndOwner = hwnd ? (HWND)LongToHandle(hwnd) : _GetWindow();
  514. bi.ulFlags = (ULONG)Options | BIF_NEWDIALOGSTYLE | BIF_NOTRANSLATETARGETS;
  515. bi.pidlRoot = VariantToIDList(&vRoot);
  516. // REVIEW: need to do IUnknown_EnableModeless() around here
  517. LPITEMIDLIST pidl = SHBrowseForFolder(&bi);
  518. if (pidl)
  519. {
  520. hr = CFolder_Create(NULL, pidl, NULL, IID_PPV_ARG(Folder, ppsdf));
  521. if (SUCCEEDED(hr))
  522. {
  523. IUnknown_SetSite(*ppsdf, _punkSite);
  524. if (_dwSafetyOptions)
  525. {
  526. hr = MakeSafeForScripting((IUnknown**)ppsdf);
  527. }
  528. }
  529. ILFree(pidl);
  530. }
  531. else
  532. hr = S_FALSE; // Not a strong error (might be user cancel)
  533. ILFree((LPITEMIDLIST)bi.pidlRoot); // NULL accepted
  534. }
  535. return hr;
  536. }
  537. STDMETHODIMP CShellDispatch::ControlPanelItem(BSTR bszDir)
  538. {
  539. HRESULT hr = _SecurityCheck();
  540. if (SUCCEEDED(hr))
  541. {
  542. SHRunControlPanel(bszDir, NULL);
  543. hr = NOERROR;
  544. }
  545. return hr;
  546. }
  547. STDMETHODIMP CShellDispatch::MinimizeAll(void)
  548. {
  549. return _TrayCommand(IDM_MINIMIZEALL);
  550. }
  551. STDMETHODIMP CShellDispatch::UndoMinimizeALL(void)
  552. {
  553. return _TrayCommand(IDM_UNDO);
  554. }
  555. STDMETHODIMP CShellDispatch::FileRun(void)
  556. {
  557. return _TrayCommand(IDM_FILERUN);
  558. }
  559. STDMETHODIMP CShellDispatch::CascadeWindows(void)
  560. {
  561. return _TrayCommand(IDM_CASCADE);
  562. }
  563. STDMETHODIMP CShellDispatch::TileVertically(void)
  564. {
  565. return _TrayCommand(IDM_VERTTILE);
  566. }
  567. STDMETHODIMP CShellDispatch::TileHorizontally(void)
  568. {
  569. return _TrayCommand(IDM_HORIZTILE);
  570. }
  571. STDMETHODIMP CShellDispatch::ShutdownWindows(void)
  572. {
  573. return _TrayCommand(IDM_EXITWIN);
  574. }
  575. STDMETHODIMP CShellDispatch::Suspend(void)
  576. {
  577. return _TrayCommand(IDM_SUSPEND);
  578. }
  579. STDMETHODIMP CShellDispatch::EjectPC(void)
  580. {
  581. return _TrayCommand(IDM_EJECTPC);
  582. }
  583. STDMETHODIMP CShellDispatch::SetTime(void)
  584. {
  585. return _TrayCommand(IDM_SETTIME);
  586. }
  587. STDMETHODIMP CShellDispatch::TrayProperties(void)
  588. {
  589. return _TrayCommand(IDM_TRAYPROPERTIES);
  590. }
  591. STDMETHODIMP CShellDispatch::Help(void)
  592. {
  593. return _TrayCommand(IDM_HELPSEARCH);
  594. }
  595. STDMETHODIMP CShellDispatch::FindFiles(void)
  596. {
  597. return _TrayCommand(FCIDM_FINDFILES);
  598. }
  599. STDMETHODIMP CShellDispatch::FindComputer(void)
  600. {
  601. return _TrayCommand(FCIDM_FINDCOMPUTER);
  602. }
  603. STDMETHODIMP CShellDispatch::RefreshMenu(void)
  604. {
  605. return _TrayCommand(FCIDM_REFRESH);
  606. }
  607. STDMETHODIMP CShellDispatch::ToggleDesktop(void)
  608. {
  609. return _TrayCommand(IDM_TOGGLEDESKTOP);
  610. }
  611. STDMETHODIMP CShellDispatch::Windows(IDispatch **ppid)
  612. {
  613. HRESULT hr = _SecurityCheck();
  614. if (SUCCEEDED(hr))
  615. {
  616. // Note: CLSID_ShellWindows does not support IObjectSafety.
  617. hr = CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_LOCAL_SERVER, IID_PPV_ARG(IDispatch, ppid));
  618. }
  619. return hr;
  620. }
  621. //
  622. // the "FindPrinter" method on the application object invokes the DS query to find a printer given
  623. // the name, location and model. Because the query UI is a blocking API we spin this onto a seperate
  624. // thread before calling "OpenQueryWindow".
  625. //
  626. typedef struct
  627. {
  628. LPWSTR pszName;
  629. LPWSTR pszLocation;
  630. LPWSTR pszModel;
  631. } FINDPRINTERINFO;
  632. void _FreeFindPrinterInfo(FINDPRINTERINFO *pfpi)
  633. {
  634. if (pfpi)
  635. {
  636. Str_SetPtrW(&pfpi->pszName, NULL);
  637. Str_SetPtrW(&pfpi->pszLocation, NULL);
  638. Str_SetPtrW(&pfpi->pszModel, NULL);
  639. LocalFree(pfpi); // free the parameters we were given
  640. }
  641. }
  642. HRESULT _GetPrintPropertyBag(FINDPRINTERINFO *pfpi, IPropertyBag **pppb)
  643. {
  644. HRESULT hr = S_OK;
  645. IPropertyBag *ppb = NULL;
  646. // if we have properties that need to be passed then lets package them up
  647. // into a property bag.
  648. if (pfpi->pszName || pfpi->pszLocation || pfpi->pszModel)
  649. {
  650. hr = SHCreatePropertyBag(IID_PPV_ARG(IPropertyBag, &ppb));
  651. if (SUCCEEDED(hr))
  652. {
  653. if (pfpi->pszName)
  654. hr = SHPropertyBag_WriteStr(ppb, L"printName", pfpi->pszName);
  655. if (pfpi->pszLocation && SUCCEEDED(hr))
  656. hr = SHPropertyBag_WriteStr(ppb, L"printLocation", pfpi->pszLocation);
  657. if (pfpi->pszModel && SUCCEEDED(hr))
  658. hr = SHPropertyBag_WriteStr(ppb, L"printModel", pfpi->pszModel);
  659. }
  660. }
  661. if (FAILED(hr) && ppb)
  662. ppb->Release();
  663. else
  664. *pppb = ppb;
  665. return hr;
  666. }
  667. DWORD WINAPI _FindPrinterThreadProc(void *ptp)
  668. {
  669. FINDPRINTERINFO *pfpi = (FINDPRINTERINFO*)ptp;
  670. ICommonQuery *pcq;
  671. if (SUCCEEDED(CoCreateInstance(CLSID_CommonQuery, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(ICommonQuery, &pcq))))
  672. {
  673. OPENQUERYWINDOW oqw = { 0 };
  674. oqw.cbStruct = sizeof(oqw);
  675. oqw.dwFlags = OQWF_DEFAULTFORM | OQWF_REMOVEFORMS | OQWF_PARAMISPROPERTYBAG;
  676. oqw.clsidHandler = CLSID_DsQuery;
  677. oqw.clsidDefaultForm = CLSID_DsFindPrinter;
  678. if (SUCCEEDED(_GetPrintPropertyBag(pfpi, &oqw.ppbFormParameters)))
  679. pcq->OpenQueryWindow(NULL, &oqw, NULL);
  680. if (oqw.pFormParameters)
  681. oqw.ppbFormParameters->Release();
  682. pcq->Release();
  683. }
  684. _FreeFindPrinterInfo(pfpi);
  685. return 0;
  686. }
  687. STDMETHODIMP CShellDispatch::FindPrinter(BSTR name, BSTR location, BSTR model)
  688. {
  689. HRESULT hr = _SecurityCheck();
  690. if (SUCCEEDED(hr))
  691. {
  692. // bundle the parameters to pass over to the bg thread which will issue the query
  693. FINDPRINTERINFO *pfpi = (FINDPRINTERINFO*)LocalAlloc(LPTR, sizeof(FINDPRINTERINFO));
  694. if (!pfpi)
  695. return E_OUTOFMEMORY;
  696. if (Str_SetPtrW(&pfpi->pszName, name) &&
  697. Str_SetPtrW(&pfpi->pszLocation, location) &&
  698. Str_SetPtrW(&pfpi->pszModel, model))
  699. {
  700. if (SHCreateThread(_FindPrinterThreadProc, pfpi, CTF_PROCESS_REF | CTF_COINIT, NULL))
  701. {
  702. pfpi = NULL; // thread owns
  703. }
  704. }
  705. // either close the thread handle, or release the parameter block. we assume
  706. // that if the thread was created it will handle discarding the block.
  707. if (pfpi)
  708. _FreeFindPrinterInfo(pfpi);
  709. }
  710. return hr;
  711. }
  712. STDMETHODIMP CShellDispatch::GetSystemInformation(BSTR bstrName, VARIANT * pvOut)
  713. {
  714. HRESULT hr = _SecurityCheck();
  715. if (SUCCEEDED(hr))
  716. {
  717. TCHAR szName[MAX_PATH];
  718. SHUnicodeToTChar(bstrName, szName, ARRAYSIZE(szName));
  719. if (!lstrcmpi(szName, TEXT("DirectoryServiceAvailable")))
  720. {
  721. pvOut->vt = VT_BOOL;
  722. V_BOOL(pvOut) = GetEnvironmentVariable(TEXT("USERDNSDOMAIN"), NULL, 0) > 0;
  723. hr = S_OK;
  724. }
  725. else if (!lstrcmpi(szName, TEXT("DoubleClickTime")))
  726. {
  727. pvOut->vt = VT_UI4;
  728. V_UI4(pvOut) = GetDoubleClickTime();
  729. hr = S_OK;
  730. }
  731. else if (!lstrcmpi(szName, TEXT("ProcessorLevel")))
  732. {
  733. SYSTEM_INFO info;
  734. GetSystemInfo(&info);
  735. pvOut->vt = VT_I4;
  736. V_UI4(pvOut) = info.wProcessorLevel;
  737. hr = S_OK;
  738. }
  739. else if (!lstrcmpi(szName, TEXT("ProcessorSpeed")))
  740. {
  741. HKEY hkey;
  742. if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  743. TEXT("Hardware\\Description\\System\\CentralProcessor\\0"),
  744. 0, KEY_QUERY_VALUE, &hkey))
  745. {
  746. hr = E_FAIL;
  747. }
  748. else
  749. {
  750. DWORD dwValue = 0;
  751. DWORD cb = sizeof(dwValue);
  752. if (ERROR_SUCCESS != SHQueryValueEx(hkey, TEXT("~Mhz"), NULL, NULL, (LPBYTE) &dwValue, &cb) == ERROR_SUCCESS)
  753. {
  754. RegCloseKey(hkey);
  755. hr = E_FAIL;
  756. }
  757. else
  758. {
  759. RegCloseKey(hkey);
  760. pvOut->vt = VT_I4;
  761. V_UI4(pvOut) = dwValue;
  762. hr = S_OK;
  763. }
  764. }
  765. }
  766. else if (!lstrcmpi(szName, TEXT("ProcessorArchitecture")))
  767. {
  768. SYSTEM_INFO info;
  769. GetSystemInfo(&info);
  770. pvOut->vt = VT_I4;
  771. V_UI4(pvOut) = info.wProcessorArchitecture;
  772. hr = S_OK;
  773. }
  774. else if (!lstrcmpi(szName, TEXT("PhysicalMemoryInstalled")))
  775. {
  776. MEMORYSTATUSEX MemoryStatus;
  777. MemoryStatus.dwLength = sizeof(MEMORYSTATUSEX);
  778. GlobalMemoryStatusEx(&MemoryStatus);
  779. pvOut->vt = VT_R8;
  780. V_R8(pvOut) = (double)(signed __int64) MemoryStatus.ullTotalPhys;
  781. hr = S_OK;
  782. }
  783. else if (!lstrcmpi(szName, TEXT("IsOS_Professional")))
  784. {
  785. pvOut->vt = VT_BOOL;
  786. V_BOOL(pvOut) = IsOS(OS_PROFESSIONAL) ? VARIANT_TRUE : VARIANT_FALSE;
  787. hr = S_OK;
  788. }
  789. else if (!lstrcmpi(szName, TEXT("IsOS_Personal")))
  790. {
  791. pvOut->vt = VT_BOOL;
  792. V_BOOL(pvOut) = IsOS(OS_PERSONAL) ? VARIANT_TRUE : VARIANT_FALSE;
  793. hr = S_OK;
  794. }
  795. else if (!lstrcmpi(szName, TEXT("IsOS_DomainMember")))
  796. {
  797. pvOut->vt = VT_BOOL;
  798. V_BOOL(pvOut) = IsOS(OS_DOMAINMEMBER) ? VARIANT_TRUE : VARIANT_FALSE;
  799. hr = S_OK;
  800. }
  801. else
  802. {
  803. hr = E_INVALIDARG;
  804. }
  805. }
  806. return hr;
  807. }
  808. STDMETHODIMP CShellDispatch::AddToRecent(VARIANT varFile, BSTR bstrCategory)
  809. {
  810. // BUGBUG: ignore bstrCategory (daviddv 8/20/99)
  811. HRESULT hr = _SecurityCheck();
  812. if (SUCCEEDED(hr))
  813. {
  814. LPITEMIDLIST pidl = VariantToIDList(&varFile);
  815. if (!pidl)
  816. {
  817. hr = E_INVALIDARG;
  818. }
  819. else
  820. {
  821. SHAddToRecentDocs(SHARD_PIDL, pidl);
  822. ILFree(pidl);
  823. }
  824. }
  825. return hr;
  826. }
  827. STDMETHODIMP CShellDispatch::WindowsSecurity()
  828. {
  829. return _TrayCommand(IDM_MU_SECURITY);
  830. }
  831. #define REGSTR_POLICIES_EXPLORER TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer")
  832. STDMETHODIMP CShellDispatch::ExplorerPolicy(BSTR bstrName, VARIANT *pValue)
  833. {
  834. HRESULT hr = _SecurityCheck();
  835. if (SUCCEEDED(hr))
  836. {
  837. hr = S_FALSE;
  838. DWORD dwType;
  839. TCHAR szName[MAX_PATH];
  840. BYTE abData[MAX_PATH];
  841. DWORD cbData = ARRAYSIZE(abData);
  842. SHUnicodeToTChar(bstrName, szName, ARRAYSIZE(szName));
  843. if (ERROR_SUCCESS == SHRegGetUSValue(REGSTR_POLICIES_EXPLORER,
  844. szName,
  845. &dwType,
  846. (LPVOID) abData,
  847. &cbData,
  848. FALSE,
  849. (LPVOID) NULL,
  850. 0))
  851. {
  852. switch(dwType)
  853. {
  854. case REG_SZ:
  855. case REG_EXPAND_SZ:
  856. hr = InitVariantFromStr(pValue, (LPCTSTR) abData);
  857. break;
  858. case REG_DWORD:
  859. pValue->vt = VT_I4; // 4 byte integer
  860. pValue->lVal = *((LONG *) abData);
  861. hr = S_OK;
  862. break;
  863. }
  864. }
  865. }
  866. return hr;
  867. }
  868. //
  869. // Mapping between settings and corresponding bitfields.
  870. //
  871. typedef struct SETTINGMAPPING {
  872. LONG lSetting; // SSF_* flag
  873. LONG lFlag; // bit position
  874. SIZE_T cbOffset; // offset to bit
  875. } SETTINGMAPPING;
  876. typedef const SETTINGMAPPING *PCSETTINGMAPPING;
  877. //
  878. // Most annoying: Our bitfields are split in two groups.
  879. //
  880. #define GROUP0 0
  881. #define GROUP1 (FIELD_OFFSET(SHELLSTATE, uNotUsed) + sizeof(UINT))
  882. //
  883. // This table is generated by hand by counting up the BITBOOL's in the
  884. // SHELLSTATE structure. Be careful, since they don't agree with the
  885. // BITBOOLs in the SHELLFLAGSTATE structure, nor do they even agree
  886. // with the SSF_ values themselves! Since this so error-prone, there
  887. // is bonus code in DEBUG to verify that the values are correct.
  888. //
  889. const SETTINGMAPPING c_rglSettingMapping[] = {
  890. { SSF_SHOWALLOBJECTS ,0x00000001 ,GROUP0 },
  891. { SSF_SHOWEXTENSIONS ,0x00000002 ,GROUP0 },
  892. // SSF_HIDDENFILEEXTS -- not supported
  893. { SSF_SHOWCOMPCOLOR ,0x00000010 ,GROUP0 },
  894. // SSF_SORTCOLUMNS -- not supported
  895. { SSF_SHOWSYSFILES ,0x00000008 ,GROUP0 },
  896. { SSF_DOUBLECLICKINWEBVIEW ,0x00000020 ,GROUP0 },
  897. { SSF_SHOWATTRIBCOL ,0x00000200 ,GROUP0 },
  898. { SSF_DESKTOPHTML ,0x00000040 ,GROUP0 },
  899. { SSF_WIN95CLASSIC ,0x00000080 ,GROUP0 },
  900. { SSF_DONTPRETTYPATH ,0x00000100 ,GROUP0 },
  901. { SSF_SHOWINFOTIP ,0x00000800 ,GROUP0 },
  902. { SSF_MAPNETDRVBUTTON ,0x00000400 ,GROUP0 },
  903. { SSF_NOCONFIRMRECYCLE ,0x00000004 ,GROUP0 },
  904. { SSF_HIDEICONS ,0x00001000 ,GROUP0 },
  905. { SSF_FILTER ,0x00004000 ,GROUP0 },
  906. { SSF_WEBVIEW ,0x00002000 ,GROUP0 },
  907. { SSF_SHOWSUPERHIDDEN ,0x00008000 ,GROUP0 },
  908. { SSF_SEPPROCESS ,0x00000001 ,GROUP1 },
  909. { SSF_NONETCRAWLING ,0x00010000 ,GROUP0 },
  910. { SSF_STARTPANELON ,0x00000002 ,GROUP1 },
  911. { SSF_SHOWSTARTPAGE ,0x00000004 ,GROUP1 },
  912. };
  913. #ifdef DEBUG
  914. // Verify that the above table is correct
  915. STDAPI_(void) _SetSettingFlag(SHELLSTATE *pss, LONG ssf)
  916. {
  917. int i;
  918. for (i = 0; i < ARRAYSIZE(c_rglSettingMapping); i++)
  919. {
  920. if (c_rglSettingMapping[i].lSetting == ssf) {
  921. LPDWORD pdw = (LPDWORD)((LPBYTE)pss + c_rglSettingMapping[i].cbOffset);
  922. // Flag shouldn't be set yet; if it is, then there is a conflict in the table
  923. ASSERT(!(*pdw & c_rglSettingMapping[i].lFlag));
  924. *pdw |= c_rglSettingMapping[i].lFlag;
  925. return;
  926. }
  927. }
  928. TraceMsg(TF_ERROR, "SSF flag %08x not in c_rglSettingMapping table", ssf);
  929. }
  930. #define _CheckSetting(ssf, field) \
  931. ASSERT(!ss.field); \
  932. _SetSettingFlag(&ss, ssf); \
  933. ASSERT(ss.field); \
  934. STDAPI_(void) _VerifyDispatchGetSetting()
  935. {
  936. // Make sure the group offsets are DWORD-aligned since we use them
  937. // to suck out a dword. If these asserts fire, then you will have to
  938. // change the table to use bytes instead of dwords.
  939. COMPILETIME_ASSERT(GROUP0 % sizeof(DWORD) == 0);
  940. COMPILETIME_ASSERT(GROUP1 % sizeof(DWORD) == 0);
  941. SHELLSTATE ss = { 0 };
  942. _CheckSetting(SSF_SHOWALLOBJECTS, fShowAllObjects);
  943. _CheckSetting(SSF_SHOWEXTENSIONS, fShowExtensions);
  944. _CheckSetting(SSF_SHOWCOMPCOLOR, fShowCompColor);
  945. _CheckSetting(SSF_SHOWSYSFILES, fShowSysFiles);
  946. _CheckSetting(SSF_DOUBLECLICKINWEBVIEW, fDoubleClickInWebView);
  947. _CheckSetting(SSF_SHOWATTRIBCOL, fShowAttribCol);
  948. _CheckSetting(SSF_DESKTOPHTML, fDesktopHTML);
  949. _CheckSetting(SSF_WIN95CLASSIC, fWin95Classic);
  950. _CheckSetting(SSF_DONTPRETTYPATH, fDontPrettyPath);
  951. _CheckSetting(SSF_SHOWINFOTIP, fShowInfoTip);
  952. _CheckSetting(SSF_MAPNETDRVBUTTON, fMapNetDrvBtn);
  953. _CheckSetting(SSF_NOCONFIRMRECYCLE, fNoConfirmRecycle);
  954. _CheckSetting(SSF_HIDEICONS, fHideIcons);
  955. _CheckSetting(SSF_FILTER, fFilter);
  956. _CheckSetting(SSF_WEBVIEW, fWebView);
  957. _CheckSetting(SSF_SHOWSUPERHIDDEN, fShowSuperHidden);
  958. _CheckSetting(SSF_SEPPROCESS, fSepProcess);
  959. _CheckSetting(SSF_NONETCRAWLING, fNoNetCrawling);
  960. _CheckSetting(SSF_STARTPANELON, fStartPanelOn);
  961. _CheckSetting(SSF_SHOWSTARTPAGE, fShowStartPage);
  962. // Now make sure that every setting was checked
  963. int i;
  964. for (i = 0; i < ARRAYSIZE(c_rglSettingMapping); i++)
  965. {
  966. LPDWORD pdw = (LPDWORD)((LPBYTE)&ss + c_rglSettingMapping[i].cbOffset);
  967. ASSERT(*pdw & c_rglSettingMapping[i].lFlag);
  968. }
  969. }
  970. #undef _CheckSetting
  971. #endif // DEBUG
  972. STDMETHODIMP CShellDispatch::GetSetting(long lSetting, VARIANT_BOOL *pValue)
  973. {
  974. HRESULT hr = _SecurityCheck();
  975. if (SUCCEEDED(hr))
  976. {
  977. BOOL bDone = FALSE;
  978. int i;
  979. for (i = 0; i < ARRAYSIZE(c_rglSettingMapping); i++)
  980. {
  981. if (lSetting == c_rglSettingMapping[i].lSetting)
  982. {
  983. SHELLSTATE ss = { 0 };
  984. SHGetSetSettings(&ss, lSetting, FALSE);
  985. LPDWORD pdw = (LPDWORD)((LPBYTE)&ss + c_rglSettingMapping[i].cbOffset);
  986. *pValue = (*pdw & c_rglSettingMapping[i].lFlag) ? VARIANT_TRUE : VARIANT_FALSE;
  987. bDone = TRUE;
  988. break;
  989. }
  990. }
  991. if (!bDone)
  992. {
  993. if (lSetting == SSF_SERVERADMINUI)
  994. {
  995. *pValue = IsOS(OS_SERVERADMINUI) ? VARIANT_TRUE : VARIANT_FALSE;
  996. }
  997. else
  998. {
  999. // Unsupported settings result in VARIANT_FALSE for forwards compatibility
  1000. *pValue = VARIANT_FALSE;
  1001. }
  1002. }
  1003. }
  1004. return hr;
  1005. }