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.

1123 lines
31 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 2000
  6. //
  7. // File: cpaction.cpp
  8. //
  9. // This module implements the various 'action' objects used by the
  10. // Control Panel's 'category' view. Each 'link' in the UI has an
  11. // associated 'action'. The action objects are defined in cpnamespc.cpp.
  12. // All 'action' objects are designed so that object construction is
  13. // very cheap and that minimal processing is performed until the action
  14. // is invoked.
  15. //
  16. //--------------------------------------------------------------------------
  17. #include "shellprv.h"
  18. #include <idhidden.h>
  19. #include "cpviewp.h"
  20. #include "cpaction.h"
  21. #include "cpguids.h"
  22. #include "cpuiele.h"
  23. #include "cputil.h"
  24. //// from shell\sdspatch\sdfolder.cpp
  25. VARIANT_BOOL GetBarricadeStatus(LPCTSTR pszValueName);
  26. //
  27. // Disable warning. ShellExecute uses SEH.
  28. // "nonstandard extension used: 'Execute' uses SEH and 'se' has destructor".
  29. //
  30. #pragma warning( push )
  31. #pragma warning( disable:4509 )
  32. using namespace CPL;
  33. //
  34. // Helper to append a bare file name to the system directory.
  35. //
  36. HRESULT
  37. AppendToSysDir(
  38. LPCWSTR pszToAppend, // Append this
  39. LPWSTR pszPath, // [out] Contains concatenated result
  40. size_t cchPath
  41. )
  42. {
  43. HRESULT hr = E_FAIL;
  44. WCHAR szTemp[MAX_PATH];
  45. if (0 != GetSystemDirectory(szTemp, ARRAYSIZE(szTemp)))
  46. {
  47. if (PathAppend(szTemp, pszToAppend))
  48. {
  49. hr = StringCchCopy(pszPath, cchPath, szTemp);
  50. }
  51. else
  52. {
  53. hr = E_FAIL;
  54. }
  55. }
  56. else
  57. {
  58. hr = ResultFromLastError();
  59. }
  60. return THR(hr);
  61. }
  62. HRESULT
  63. CRestrictApplet::IsRestricted(
  64. ICplNamespace *pns
  65. ) const
  66. {
  67. UNREFERENCED_PARAMETER(pns);
  68. DBG_ENTER(FTF_CPANEL, "RestrictApplet");
  69. HRESULT hr = S_FALSE;
  70. if (!IsAppletEnabled(m_pszFile, m_pszApplet))
  71. {
  72. hr = S_OK;
  73. }
  74. DBG_EXIT_HRES(FTF_CPANEL, "RestrictApplet", hr);
  75. return hr;
  76. }
  77. //--------------------------------------------------------------------------
  78. // CAction implementation
  79. //--------------------------------------------------------------------------
  80. CAction::CAction(
  81. const CPL::IRestrict *pRestrict // optional. default = NULL
  82. ) : m_pRestrict(pRestrict)
  83. {
  84. }
  85. //
  86. // Returns:
  87. // S_FALSE - Not restricted.
  88. // S_OK - Restricted.
  89. // Failure - Cannot determine.
  90. //
  91. HRESULT
  92. CAction::IsRestricted(
  93. ICplNamespace *pns
  94. ) const
  95. {
  96. HRESULT hr = S_FALSE; // Assume not restricted.
  97. if (NULL != m_pRestrict)
  98. {
  99. hr = m_pRestrict->IsRestricted(pns);
  100. }
  101. return THR(hr);
  102. }
  103. //--------------------------------------------------------------------------
  104. // COpenUserMgrApplet implementation
  105. //--------------------------------------------------------------------------
  106. COpenUserMgrApplet::COpenUserMgrApplet(
  107. const CPL::IRestrict *pRestrict // optional. default = NULL
  108. ): CAction(pRestrict)
  109. {
  110. }
  111. HRESULT
  112. COpenUserMgrApplet::Execute(
  113. HWND hwndParent,
  114. IUnknown *punkSite
  115. ) const
  116. {
  117. DBG_ENTER(FTF_CPANEL, "COpenUserMgrApplet::Execute");
  118. HRESULT hr = E_FAIL;
  119. if (IsOsServer())
  120. {
  121. CShellExecuteSysDir action(L"lusrmgr.msc");
  122. hr = action.Execute(hwndParent, punkSite);
  123. }
  124. else
  125. {
  126. COpenCplAppletSysDir action(L"nusrmgr.cpl");
  127. hr = action.Execute(hwndParent, punkSite);
  128. }
  129. DBG_EXIT_HRES(FTF_CPANEL, "COpenUserMgrApplet::Execute", hr);
  130. return THR(hr);
  131. }
  132. //--------------------------------------------------------------------------
  133. // COpenCplApplet implementation
  134. //--------------------------------------------------------------------------
  135. COpenCplApplet::COpenCplApplet(
  136. LPCWSTR pszApplet,
  137. const CPL::IRestrict *pRestrict // optional. default = NULL
  138. ) : CAction(pRestrict),
  139. m_pszApplet(pszApplet)
  140. {
  141. ASSERT(NULL != pszApplet);
  142. }
  143. HRESULT
  144. COpenCplApplet::Execute(
  145. HWND hwndParent,
  146. IUnknown *punkSite
  147. ) const
  148. {
  149. DBG_ENTER(FTF_CPANEL, "COpenCplApplet::Execute");
  150. ASSERT(NULL != m_pszApplet);
  151. ASSERT(NULL == hwndParent || IsWindow(hwndParent));
  152. UNREFERENCED_PARAMETER(punkSite);
  153. //
  154. // Build a path consisting of the system directory, the
  155. // "%SystemDir%\shell32,Control_RunDLL" string and the
  156. // applet name. i.e.:
  157. //
  158. // "c:\windows\system32\shell32,Control_RundLL desk.cpl"
  159. //
  160. WCHAR szArgs[MAX_PATH * 2];
  161. HRESULT hr = AppendToSysDir(L"shell32.dll,Control_RunDLL ", szArgs, ARRAYSIZE(szArgs));
  162. if (SUCCEEDED(hr))
  163. {
  164. hr = StringCchCat(szArgs, ARRAYSIZE(szArgs), m_pszApplet);
  165. if (SUCCEEDED(hr))
  166. {
  167. //
  168. // Build a path to rundll32.exe.
  169. // i.e.:
  170. // "c:\windows\system32\rundll32.exe"
  171. //
  172. WCHAR szRunDll32[MAX_PATH];
  173. hr = AppendToSysDir(L"rundll32.exe", szRunDll32, ARRAYSIZE(szRunDll32));
  174. if (SUCCEEDED(hr))
  175. {
  176. TraceMsg(TF_CPANEL, "Executing: \"%s %s\"", szRunDll32, szArgs);
  177. SHELLEXECUTEINFOW sei = {
  178. sizeof(sei), // cbSize;
  179. 0, // fMask
  180. hwndParent, // hwnd
  181. NULL, // lpVerb
  182. szRunDll32, // lpFile
  183. szArgs, // lpParameters
  184. NULL, // lpDirectory
  185. SW_SHOWNORMAL, // nShow
  186. 0, // hInstApp
  187. NULL, // lpIDList
  188. NULL, // lpClass
  189. NULL, // hkeyClass
  190. 0, // dwHotKey
  191. NULL, // hIcon
  192. NULL // hProcess
  193. };
  194. if (!ShellExecuteExW(&sei))
  195. {
  196. hr = ResultFromLastError();
  197. }
  198. }
  199. }
  200. }
  201. DBG_EXIT_HRES(FTF_CPANEL, "COpenCplApplet::Execute", hr);
  202. return THR(hr);
  203. }
  204. //--------------------------------------------------------------------------
  205. // COpenCplAppletSysDir implementation
  206. //
  207. // Minor extension of COpenCplApplet that assumes the applet is in
  208. // %SystemRoot%\System32 directory.
  209. //
  210. //--------------------------------------------------------------------------
  211. COpenCplAppletSysDir::COpenCplAppletSysDir(
  212. LPCWSTR pszApplet,
  213. const CPL::IRestrict *pRestrict // optional. default = NULL
  214. ) : COpenCplApplet(pszApplet, pRestrict)
  215. {
  216. ASSERT(NULL != pszApplet);
  217. }
  218. HRESULT
  219. COpenCplAppletSysDir::Execute(
  220. HWND hwndParent,
  221. IUnknown *punkSite
  222. ) const
  223. {
  224. DBG_ENTER(FTF_CPANEL, "COpenCplAppletSysDir::Execute");
  225. ASSERT(NULL != m_pszApplet);
  226. ASSERT(NULL == hwndParent || IsWindow(hwndParent));
  227. UNREFERENCED_PARAMETER(punkSite);
  228. //
  229. // Build a path consisting of the system directory and the
  230. // applet name. i.e.:
  231. //
  232. // "c:\windows\system32\desk.cpl"
  233. //
  234. WCHAR szAppletPath[MAX_PATH];
  235. HRESULT hr = AppendToSysDir(m_pszApplet, szAppletPath, ARRAYSIZE(szAppletPath));
  236. if (SUCCEEDED(hr))
  237. {
  238. COpenCplApplet oca(szAppletPath);
  239. hr = oca.Execute(hwndParent, punkSite);
  240. }
  241. DBG_EXIT_HRES(FTF_CPANEL, "COpenCplAppletSysDir::Execute", hr);
  242. return THR(hr);
  243. }
  244. //--------------------------------------------------------------------------
  245. // COpenDeskCpl implementation
  246. //--------------------------------------------------------------------------
  247. COpenDeskCpl::COpenDeskCpl(
  248. eDESKCPLTAB eCplTab,
  249. const CPL::IRestrict *pRestrict // optional. default = NULL
  250. ) : CAction(pRestrict),
  251. m_eCplTab(eCplTab)
  252. {
  253. }
  254. HRESULT
  255. COpenDeskCpl::Execute(
  256. HWND hwndParent,
  257. IUnknown *punkSite
  258. ) const
  259. {
  260. DBG_ENTER(FTF_CPANEL, "COpenDeskCpl::Execute");
  261. TraceMsg(TF_CPANEL, "Desk CPL tab ID = %d", m_eCplTab);
  262. ASSERT(NULL == hwndParent || IsWindow(hwndParent));
  263. UNREFERENCED_PARAMETER(punkSite);
  264. HRESULT hr = E_FAIL;
  265. WCHAR szTab[MAX_PATH];
  266. const int iTab = CPL::DeskCPL_GetTabIndex(m_eCplTab, szTab, ARRAYSIZE(szTab));
  267. if (CPLTAB_ABSENT != iTab)
  268. {
  269. WCHAR szArgs[MAX_PATH];
  270. hr = StringCchPrintfW(szArgs, ARRAYSIZE(szArgs), L"desk.cpl ,@%ls", szTab);
  271. if (SUCCEEDED(hr))
  272. {
  273. COpenCplAppletSysDir oca(szArgs);
  274. hr = oca.Execute(hwndParent, punkSite);
  275. }
  276. }
  277. DBG_EXIT_HRES(FTF_CPANEL, "COpenDeskCpl::Execute", hr);
  278. return THR(hr);
  279. }
  280. //--------------------------------------------------------------------------
  281. // CNavigateURL implementation
  282. //--------------------------------------------------------------------------
  283. CNavigateURL::CNavigateURL(
  284. LPCWSTR pszURL,
  285. const CPL::IRestrict *pRestrict // optional. default = NULL
  286. ) : CAction(pRestrict),
  287. m_pszURL(pszURL)
  288. {
  289. ASSERT(NULL != pszURL);
  290. }
  291. HRESULT
  292. CNavigateURL::Execute(
  293. HWND hwndParent,
  294. IUnknown *punkSite
  295. ) const
  296. {
  297. DBG_ENTER(FTF_CPANEL, "CNavigateURL::Execute");
  298. ASSERT(NULL != m_pszURL);
  299. ASSERT(NULL == hwndParent || IsWindow(hwndParent));
  300. UNREFERENCED_PARAMETER(hwndParent);
  301. TraceMsg(TF_CPANEL, "URL = \"%s\"", m_pszURL);
  302. IWebBrowser2 *pwb;
  303. HRESULT hr = IUnknown_QueryService(punkSite, SID_SWebBrowserApp, IID_IWebBrowser2, (void **)&pwb);
  304. if (SUCCEEDED(hr))
  305. {
  306. LPTSTR pszExpanded;
  307. hr = CPL::ExpandEnvironmentVars(m_pszURL, &pszExpanded);
  308. if (SUCCEEDED(hr))
  309. {
  310. VARIANT varURL;
  311. hr = InitVariantFromStr(&varURL, pszExpanded);
  312. if (SUCCEEDED(hr))
  313. {
  314. VARIANT varEmpty;
  315. VariantInit(&varEmpty);
  316. VARIANT varFlags;
  317. varFlags.vt = VT_UINT;
  318. varFlags.uintVal = 0;
  319. hr = pwb->Navigate2(&varURL, &varFlags, &varEmpty, &varEmpty, &varEmpty);
  320. VariantClear(&varURL);
  321. }
  322. LocalFree(pszExpanded);
  323. }
  324. pwb->Release();
  325. }
  326. DBG_EXIT_HRES(FTF_CPANEL, "CNavigateURL::Execute", hr);
  327. return THR(hr);
  328. }
  329. //--------------------------------------------------------------------------
  330. // COpenTroubleshooter implementation
  331. //--------------------------------------------------------------------------
  332. COpenTroubleshooter::COpenTroubleshooter(
  333. LPCWSTR pszTs,
  334. const CPL::IRestrict *pRestrict // optional. default = NULL
  335. ) : CAction(pRestrict),
  336. m_pszTs(pszTs)
  337. {
  338. ASSERT(NULL != pszTs);
  339. }
  340. HRESULT
  341. COpenTroubleshooter::Execute(
  342. HWND hwndParent,
  343. IUnknown *punkSite
  344. ) const
  345. {
  346. DBG_ENTER(FTF_CPANEL, "COpenTroubleshooter::Execute");
  347. ASSERT(NULL != m_pszTs);
  348. ASSERT(NULL == hwndParent || IsWindow(hwndParent));
  349. UNREFERENCED_PARAMETER(punkSite);
  350. WCHAR szPath[MAX_PATH];
  351. HRESULT hr = StringCchPrintfW(szPath, ARRAYSIZE(szPath), L"hcp://help/tshoot/%s", m_pszTs);
  352. if (SUCCEEDED(hr))
  353. {
  354. CNavigateURL actionURL(szPath);
  355. hr = actionURL.Execute(hwndParent, punkSite);
  356. }
  357. DBG_EXIT_HRES(FTF_CPANEL, "COpenTroubleshooter::Execute", hr);
  358. return THR(hr);
  359. }
  360. //--------------------------------------------------------------------------
  361. // CShellExecute implementation
  362. //--------------------------------------------------------------------------
  363. CShellExecute::CShellExecute(
  364. LPCWSTR pszExe,
  365. LPCWSTR pszArgs, // optional. default = NULL.
  366. const CPL::IRestrict *pRestrict // optional. default = NULL
  367. ) : CAction(pRestrict),
  368. m_pszExe(pszExe),
  369. m_pszArgs(pszArgs)
  370. {
  371. ASSERT(NULL != pszExe);
  372. }
  373. HRESULT
  374. CShellExecute::Execute(
  375. HWND hwndParent,
  376. IUnknown *punkSite
  377. ) const
  378. {
  379. DBG_ENTER(FTF_CPANEL, "CShellExecute::Execute");
  380. ASSERT(NULL != m_pszExe);
  381. ASSERT(NULL == hwndParent || IsWindow(hwndParent));
  382. UNREFERENCED_PARAMETER(punkSite);
  383. TraceMsg(TF_CPANEL, "ShellExecute: \"%s %s\"", m_pszExe, m_pszArgs ? m_pszArgs : L"<no args>");
  384. SHELLEXECUTEINFOW sei = {
  385. sizeof(sei), // cbSize;
  386. SEE_MASK_DOENVSUBST, // fMask
  387. hwndParent, // hwnd
  388. L"open", // lpVerb
  389. m_pszExe, // lpFile
  390. m_pszArgs, // lpParameters
  391. NULL, // lpDirectory
  392. SW_SHOWNORMAL, // nShow
  393. 0, // hInstApp
  394. NULL, // lpIDList
  395. NULL, // lpClass
  396. NULL, // hkeyClass
  397. 0, // dwHotKey
  398. NULL, // hIcon
  399. NULL // hProcess
  400. };
  401. HRESULT hr = S_OK;
  402. if (!ShellExecuteExW(&sei))
  403. {
  404. hr = ResultFromLastError();
  405. }
  406. DBG_EXIT_HRES(FTF_CPANEL, "CShellExecute::Execute", hr);
  407. return THR(hr);
  408. }
  409. //--------------------------------------------------------------------------
  410. // CShellExecuteSysDir implementation
  411. // Simply wraps CShellExecute assuming that the EXE exists in the
  412. // SYSTEM32 directory.
  413. //--------------------------------------------------------------------------
  414. CShellExecuteSysDir::CShellExecuteSysDir(
  415. LPCWSTR pszExe,
  416. LPCWSTR pszArgs, // optional. default = NULL.
  417. const CPL::IRestrict *pRestrict // optional. default = NULL
  418. ) : CShellExecute(pszExe, pszArgs, pRestrict)
  419. {
  420. ASSERT(NULL != pszExe);
  421. }
  422. HRESULT
  423. CShellExecuteSysDir::Execute(
  424. HWND hwndParent,
  425. IUnknown *punkSite
  426. ) const
  427. {
  428. DBG_ENTER(FTF_CPANEL, "CShellExecuteSysDir::Execute");
  429. ASSERT(NULL != m_pszExe);
  430. ASSERT(NULL == hwndParent || IsWindow(hwndParent));
  431. UNREFERENCED_PARAMETER(punkSite);
  432. TraceMsg(TF_CPANEL, "ShellExecuteSysDir: \"%s %s\"", m_pszExe, m_pszArgs ? m_pszArgs : L"<no args>");
  433. //
  434. // Build a path consisting of the system directory and the
  435. // EXE name. i.e.:
  436. //
  437. // "c:\windows\system32\myapp.exe"
  438. //
  439. WCHAR szExePath[MAX_PATH];
  440. HRESULT hr = AppendToSysDir(m_pszExe, szExePath, ARRAYSIZE(szExePath));
  441. if (SUCCEEDED(hr))
  442. {
  443. CShellExecute se(szExePath, m_pszArgs);
  444. hr = se.Execute(hwndParent, punkSite);
  445. }
  446. DBG_EXIT_HRES(FTF_CPANEL, "CShellExecuteSysDir::Execute", hr);
  447. return THR(hr);
  448. }
  449. //--------------------------------------------------------------------------
  450. // CRundll32 implementation
  451. // This is a simple wrapper around CShellExecute that saves an instance
  452. // definition from having to type L"%SystemRoot%\\system32\\rundll32.exe".
  453. //--------------------------------------------------------------------------
  454. CRunDll32::CRunDll32(
  455. LPCWSTR pszArgs,
  456. const CPL::IRestrict *pRestrict // optional. default = NULL
  457. ) : CAction(pRestrict),
  458. m_pszArgs(pszArgs)
  459. {
  460. ASSERT(NULL != pszArgs);
  461. }
  462. HRESULT
  463. CRunDll32::Execute(
  464. HWND hwndParent,
  465. IUnknown *punkSite
  466. ) const
  467. {
  468. DBG_ENTER(FTF_CPANEL, "CRunDll32::Execute");
  469. ASSERT(NULL != m_pszArgs);
  470. ASSERT(NULL == hwndParent || IsWindow(hwndParent));
  471. TraceMsg(TF_CPANEL, "CRunDll32: \"%s\"", m_pszArgs);
  472. WCHAR szPath[MAX_PATH];
  473. HRESULT hr = AppendToSysDir(L"rundll32.exe", szPath, ARRAYSIZE(szPath));
  474. if (SUCCEEDED(hr))
  475. {
  476. CShellExecute se(szPath, m_pszArgs);
  477. hr = se.Execute(hwndParent, punkSite);
  478. }
  479. DBG_EXIT_HRES(FTF_CPANEL, "CRunDll32::Execute", hr);
  480. return THR(hr);
  481. }
  482. //--------------------------------------------------------------------------
  483. // CExecDiskUtil implementation
  484. //--------------------------------------------------------------------------
  485. CExecDiskUtil::CExecDiskUtil(
  486. eDISKUTILS eUtil,
  487. const CPL::IRestrict *pRestrict // optional. default = NULL
  488. ) : CAction(pRestrict),
  489. m_eUtil(eUtil)
  490. {
  491. ASSERT(eDISKUTIL_NUMUTILS > m_eUtil);
  492. }
  493. HRESULT
  494. CExecDiskUtil::Execute(
  495. HWND hwndParent,
  496. IUnknown *punkSite
  497. ) const
  498. {
  499. DBG_ENTER(FTF_CPANEL, "CExecDiskUtil::Execute");
  500. TCHAR szValue[MAX_PATH];
  501. DWORD dwType;
  502. DWORD cbValue = sizeof(szValue);
  503. //
  504. // These strings must remain in sync with the eDISKUTILS enumeration.
  505. //
  506. static LPCTSTR rgpszRegNames[] = {
  507. TEXT("MyComputer\\backuppath"), // eDISKUTIL_BACKUP
  508. TEXT("MyComputer\\defragpath"), // eDISKUTIL_DEFRAG
  509. TEXT("MyComputer\\cleanuppath"), // eDISKUTIL_CLEANUP
  510. };
  511. HRESULT hr = SKGetValue(SHELLKEY_HKLM_EXPLORER,
  512. rgpszRegNames[int(m_eUtil)],
  513. NULL,
  514. &dwType,
  515. szValue,
  516. &cbValue);
  517. if (SUCCEEDED(hr))
  518. {
  519. LPTSTR pszExpanded = NULL;
  520. //
  521. // Expand environment strings.
  522. // According to the code in shell32\drvx.cpp, some apps
  523. // use embedded env vars even if the value type is REG_SZ.
  524. //
  525. hr = CPL::ExpandEnvironmentVars(szValue, &pszExpanded);
  526. if (SUCCEEDED(hr))
  527. {
  528. //
  529. // The drive utility command strings were designed to be
  530. // invoked from the drives property page. They therefore
  531. // accept a drive letter. Since control panel launches
  532. // the utilities for no particular drive, we need to remove
  533. // the "%c:" format specifier.
  534. //
  535. hr = _RemoveDriveLetterFmtSpec(pszExpanded);
  536. if (SUCCEEDED(hr))
  537. {
  538. TCHAR szArgs[MAX_PATH] = {0};
  539. PathRemoveBlanks(pszExpanded);
  540. hr = PathSeperateArgs(pszExpanded, szArgs, ARRAYSIZE(szArgs), NULL);
  541. if (SUCCEEDED(hr))
  542. {
  543. //
  544. // Note that it's valid to use a NULL restriction here.
  545. // If there's a restriction on the CExecDiskUtil object
  546. // we won't get this far (i.e. Execute isn't called).
  547. //
  548. CShellExecute exec(pszExpanded, szArgs);
  549. hr = exec.Execute(hwndParent, punkSite);
  550. }
  551. }
  552. LocalFree(pszExpanded);
  553. }
  554. }
  555. DBG_EXIT_HRES(FTF_CPANEL, "CExecDiskUtil::Execute", hr);
  556. return THR(hr);
  557. }
  558. //
  559. // The command line strings for the backup, defrag and disk cleanup utilities
  560. // can contain a format specifier for the drive letter. That's because
  561. // they're designed to be opened from a particular volume's "Tools" property
  562. // page. Control Panel launches these from outside the context of any particular
  563. // volume. Therefore, the drive letter is not available and the the format
  564. // specifier is unused. This function removes that format specifier if it exists.
  565. //
  566. // i.e.: "c:\windows\system32\ntbackup.exe" -> "c:\windows\system32\ntbackpu.exe"
  567. // "c:\windows\system32\cleanmgr.exe /D %c:" -> "c:\windows\system32\cleanmgr.exe"
  568. // "c:\windows\system32\defrg.msc %c:" -> "c:\windows\system32\defrg.msc"
  569. //
  570. HRESULT
  571. CExecDiskUtil::_RemoveDriveLetterFmtSpec( // [static]
  572. LPTSTR pszCmdLine
  573. )
  574. {
  575. LPCTSTR pszRead = pszCmdLine;
  576. LPTSTR pszWrite = pszCmdLine;
  577. while(*pszRead)
  578. {
  579. if (TEXT('%') == *pszRead && TEXT('c') == *(pszRead + 1))
  580. {
  581. //
  582. // Skip over the "%c" or "%c:" fmt specifier.
  583. //
  584. pszRead += 2;
  585. if (TEXT(':') == *pszRead)
  586. {
  587. pszRead++;
  588. }
  589. }
  590. if (*pszRead)
  591. {
  592. *pszWrite++ = *pszRead++;
  593. }
  594. }
  595. *pszWrite = *pszRead; // pick up null terminator.
  596. return S_OK;
  597. }
  598. //--------------------------------------------------------------------------
  599. // COpenCplCategory implementation
  600. //--------------------------------------------------------------------------
  601. COpenCplCategory::COpenCplCategory(
  602. eCPCAT eCategory,
  603. const CPL::IRestrict *pRestrict // optional. default = NULL
  604. ) : CAction(pRestrict),
  605. m_eCategory(eCategory)
  606. {
  607. }
  608. HRESULT
  609. COpenCplCategory::Execute(
  610. HWND hwndParent,
  611. IUnknown *punkSite
  612. ) const
  613. {
  614. DBG_ENTER(FTF_CPANEL, "COpenCplCategory::Execute");
  615. TraceMsg(TF_CPANEL, "Category ID = %d", m_eCategory);
  616. ASSERT(NULL != punkSite);
  617. UNREFERENCED_PARAMETER(hwndParent);
  618. IShellBrowser *psb;
  619. HRESULT hr = CPL::ShellBrowserFromSite(punkSite, &psb);
  620. if (SUCCEEDED(hr))
  621. {
  622. LPITEMIDLIST pidlFolder;
  623. hr = SHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidlFolder);
  624. if (SUCCEEDED(hr))
  625. {
  626. WCHAR szCategory[10];
  627. hr = StringCchPrintfW(szCategory, ARRAYSIZE(szCategory), L"%d", m_eCategory);
  628. if (SUCCEEDED(hr))
  629. {
  630. LPITEMIDLIST pidlTemp = ILAppendHiddenStringW(pidlFolder, IDLHID_NAVIGATEMARKER, szCategory);
  631. if (NULL == pidlTemp)
  632. {
  633. hr = E_OUTOFMEMORY;
  634. }
  635. else
  636. {
  637. pidlFolder = pidlTemp;
  638. pidlTemp = NULL;
  639. hr = CPL::BrowseIDListInPlace(pidlFolder, psb);
  640. }
  641. ILFree(pidlFolder);
  642. }
  643. }
  644. psb->Release();
  645. }
  646. DBG_EXIT_HRES(FTF_CPANEL, "COpenCplCategory::Execute", hr);
  647. return THR(hr);
  648. }
  649. //--------------------------------------------------------------------------
  650. // COpenCplCategory2 implementation
  651. //--------------------------------------------------------------------------
  652. COpenCplCategory2::COpenCplCategory2(
  653. eCPCAT eCategory,
  654. const IAction *pDefAction,
  655. const CPL::IRestrict *pRestrict // optional. default = NULL
  656. ) : CAction(pRestrict),
  657. m_eCategory(eCategory),
  658. m_pDefAction(pDefAction)
  659. {
  660. }
  661. HRESULT
  662. COpenCplCategory2::Execute(
  663. HWND hwndParent,
  664. IUnknown *punkSite
  665. ) const
  666. {
  667. DBG_ENTER(FTF_CPANEL, "COpenCplCategory2::Execute");
  668. TraceMsg(TF_CPANEL, "Category ID = %d", m_eCategory);
  669. ASSERT(NULL != punkSite);
  670. bool bOpenCategory = false;
  671. HRESULT hr = _ExecuteActionOnSingleCplApplet(hwndParent, punkSite, &bOpenCategory);
  672. if (SUCCEEDED(hr))
  673. {
  674. if (bOpenCategory)
  675. {
  676. //
  677. // Category has more than one CPL.
  678. // Open the category page.
  679. //
  680. COpenCplCategory action(m_eCategory);
  681. hr = action.Execute(hwndParent, punkSite);
  682. }
  683. }
  684. DBG_EXIT_HRES(FTF_CPANEL, "COpenCplCategory2::Execute", hr);
  685. return THR(hr);
  686. }
  687. HRESULT
  688. COpenCplCategory2::_ExecuteActionOnSingleCplApplet(
  689. HWND hwndParent,
  690. IUnknown *punkSite,
  691. bool *pbOpenCategory // optional. Can be NULL
  692. ) const
  693. {
  694. DBG_ENTER(FTF_CPANEL, "COpenCplCategory2::_ExecuteActionOnSingleCplApplet");
  695. bool bOpenCategory = true;
  696. ICplView *pview;
  697. HRESULT hr = CPL::ControlPanelViewFromSite(punkSite, &pview);
  698. if (SUCCEEDED(hr))
  699. {
  700. IServiceProvider *psp;
  701. hr = pview->QueryInterface(IID_IServiceProvider, (void **)&psp);
  702. if (SUCCEEDED(hr))
  703. {
  704. ICplNamespace *pns;
  705. hr = psp->QueryService(SID_SControlPanelView, IID_ICplNamespace, (void **)&pns);
  706. if (SUCCEEDED(hr))
  707. {
  708. ICplCategory *pCategory;
  709. hr = pns->GetCategory(m_eCategory, &pCategory);
  710. if (SUCCEEDED(hr))
  711. {
  712. IEnumUICommand *penum;
  713. hr = pCategory->EnumCplApplets(&penum);
  714. if (SUCCEEDED(hr))
  715. {
  716. //
  717. // See if the category has more than one CPL applet
  718. // assigned to it.
  719. //
  720. ULONG cApplets = 0;
  721. IUICommand *rgpuic[2] = {0};
  722. if (SUCCEEDED(hr = penum->Next(ARRAYSIZE(rgpuic), rgpuic, &cApplets)))
  723. {
  724. for (int i = 0; i < ARRAYSIZE(rgpuic); i++)
  725. {
  726. ATOMICRELEASE(rgpuic[i]);
  727. }
  728. if (2 > cApplets)
  729. {
  730. //
  731. // There's zero or one CPLs registered for this category.
  732. // Simply execute the default action. If there's one
  733. // we assume it's the "default" applet (i.e. ARP or
  734. // User Accounts).
  735. //
  736. hr = m_pDefAction->IsRestricted(pns);
  737. if (SUCCEEDED(hr))
  738. {
  739. if (S_FALSE == hr)
  740. {
  741. bOpenCategory = false;
  742. hr = m_pDefAction->Execute(hwndParent, punkSite);
  743. }
  744. else
  745. {
  746. //
  747. // Default action is restricted.
  748. // Open the category page. Note that the
  749. // category page may be displayed as a 'barrier'
  750. // if no tasks or CPL applets are available.
  751. //
  752. ASSERT(bOpenCategory);
  753. }
  754. }
  755. }
  756. }
  757. penum->Release();
  758. }
  759. pCategory->Release();
  760. }
  761. pns->Release();
  762. }
  763. psp->Release();
  764. }
  765. pview->Release();
  766. }
  767. if (NULL != pbOpenCategory)
  768. {
  769. *pbOpenCategory = bOpenCategory;
  770. }
  771. DBG_EXIT_HRES(FTF_CPANEL, "COpenCplCategory2::_ExecuteActionOnSingleCplApplet", hr);
  772. return THR(hr);
  773. }
  774. //--------------------------------------------------------------------------
  775. // COpenCplView implementation
  776. //--------------------------------------------------------------------------
  777. COpenCplView::COpenCplView(
  778. eCPVIEWTYPE eViewType,
  779. const CPL::IRestrict *pRestrict // optional. default = NULL
  780. ) : CAction(pRestrict),
  781. m_eViewType(eViewType)
  782. {
  783. }
  784. HRESULT
  785. COpenCplView::Execute(
  786. HWND hwndParent,
  787. IUnknown *punkSite
  788. ) const
  789. {
  790. UNREFERENCED_PARAMETER(hwndParent);
  791. ASSERT(NULL != punkSite);
  792. HRESULT hr = _SetFolderBarricadeStatus();
  793. if (SUCCEEDED(hr))
  794. {
  795. IShellBrowser *psb;
  796. hr = CPL::ShellBrowserFromSite(punkSite, &psb);
  797. if (SUCCEEDED(hr))
  798. {
  799. LPITEMIDLIST pidlFolder;
  800. hr = SHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidlFolder);
  801. if (SUCCEEDED(hr))
  802. {
  803. hr = CPL::BrowseIDListInPlace(pidlFolder, psb);
  804. ILFree(pidlFolder);
  805. }
  806. psb->Release();
  807. }
  808. }
  809. return THR(hr);
  810. }
  811. HRESULT
  812. COpenCplView::_SetFolderBarricadeStatus(
  813. void
  814. ) const
  815. {
  816. VARIANT_BOOL vtb = VARIANT_FALSE;
  817. if (eCPVIEWTYPE_CATEGORY == m_eViewType)
  818. {
  819. vtb = VARIANT_TRUE;
  820. }
  821. else
  822. {
  823. ASSERT(eCPVIEWTYPE_CLASSIC == m_eViewType);
  824. }
  825. HRESULT hr = CPL::SetControlPanelBarricadeStatus(vtb);
  826. return THR(hr);
  827. }
  828. //--------------------------------------------------------------------------
  829. // CAddPrinter implementation
  830. //--------------------------------------------------------------------------
  831. CAddPrinter::CAddPrinter(
  832. const CPL::IRestrict *pRestrict // optional. default = NULL
  833. ) : CAction(pRestrict)
  834. {
  835. }
  836. HRESULT
  837. CAddPrinter::Execute(
  838. HWND hwndParent,
  839. IUnknown *punkSite
  840. ) const
  841. {
  842. DBG_ENTER(FTF_CPANEL, "CAddPrinter::Execute");
  843. ASSERT(NULL == hwndParent || IsWindow(hwndParent));
  844. UNREFERENCED_PARAMETER(punkSite);
  845. HRESULT hr = E_FAIL;
  846. if (SHInvokePrinterCommandW(hwndParent,
  847. PRINTACTION_OPEN,
  848. L"WinUtils_NewObject",
  849. NULL,
  850. FALSE))
  851. {
  852. //
  853. // Navigate to the printers folder after invoking the add-printer wizard.
  854. // This gives the user visual feedback when a printer is added. We navigate
  855. // even if the user cancels the wizard because we cannot determine if the
  856. // wizard was cancelled. We've determined this is acceptable.
  857. //
  858. CNavigateURL prnfldr(L"shell:::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{2227A280-3AEA-1069-A2DE-08002B30309D}");
  859. hr = prnfldr.Execute(hwndParent, punkSite);
  860. }
  861. DBG_EXIT_HRES(FTF_CPANEL, "CAddPrinter::Execute", hr);
  862. return THR(hr);
  863. }
  864. //--------------------------------------------------------------------------
  865. // CTrayCommand implementation
  866. //--------------------------------------------------------------------------
  867. CTrayCommand::CTrayCommand(
  868. UINT idm,
  869. const CPL::IRestrict *pRestrict // optional. default = NULL
  870. ) : CAction(pRestrict),
  871. m_idm(idm)
  872. {
  873. }
  874. HRESULT
  875. CTrayCommand::Execute(
  876. HWND hwndParent,
  877. IUnknown *punkSite
  878. ) const
  879. {
  880. UNREFERENCED_PARAMETER(hwndParent);
  881. UNREFERENCED_PARAMETER(punkSite);
  882. // APPHACK! 221008 DesktopX creates their own window with class
  883. // name "Shell_TrayWnd", so if we're not careful we will end
  884. // posting the messages to the wrong window. They create their
  885. // window with the title "CTrayServer"; ours has a null title.
  886. // Use the null title to find the correct window.
  887. HWND hwndTray = FindWindowA(WNDCLASS_TRAYNOTIFY, "");
  888. if (hwndTray)
  889. {
  890. PostMessage(hwndTray, WM_COMMAND, m_idm, 0);
  891. }
  892. return S_OK;
  893. }
  894. //--------------------------------------------------------------------------
  895. // CActionNYI implementation
  896. //--------------------------------------------------------------------------
  897. CActionNYI::CActionNYI(
  898. LPCWSTR pszText
  899. ) : m_pszText(pszText)
  900. {
  901. }
  902. HRESULT
  903. CActionNYI::Execute(
  904. HWND hwndParent,
  905. IUnknown *punkSite
  906. ) const
  907. {
  908. ASSERT(NULL == hwndParent || IsWindow(hwndParent));
  909. UNREFERENCED_PARAMETER(punkSite);
  910. HRESULT hr = E_OUTOFMEMORY;
  911. if (NULL != m_pszText)
  912. {
  913. MessageBoxW(hwndParent, m_pszText, L"Action Not Yet Implemented", MB_OK);
  914. hr = S_OK;
  915. }
  916. return THR(hr);
  917. }
  918. #pragma warning( pop )