Source code of Windows XP (NT5)
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.

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