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.

1654 lines
45 KiB

  1. #include "stdafx.h"
  2. #include "PageStartup.h"
  3. #include "MSConfigState.h"
  4. #ifdef _DEBUG
  5. #define new DEBUG_NEW
  6. #undef THIS_FILE
  7. static char THIS_FILE[] = __FILE__;
  8. #endif
  9. /////////////////////////////////////////////////////////////////////////////
  10. // CPageStartup property page
  11. IMPLEMENT_DYNCREATE(CPageStartup, CPropertyPage)
  12. CPageStartup::CPageStartup() : CPropertyPage(CPageStartup::IDD)
  13. {
  14. //{{AFX_DATA_INIT(CPageStartup)
  15. // NOTE: the ClassWizard will add member initialization here
  16. //}}AFX_DATA_INIT
  17. }
  18. CPageStartup::~CPageStartup()
  19. {
  20. }
  21. void CPageStartup::DoDataExchange(CDataExchange* pDX)
  22. {
  23. CPropertyPage::DoDataExchange(pDX);
  24. //{{AFX_DATA_MAP(CPageStartup)
  25. // NOTE: the ClassWizard will add DDX and DDV calls here
  26. //}}AFX_DATA_MAP
  27. }
  28. BEGIN_MESSAGE_MAP(CPageStartup, CPropertyPage)
  29. //{{AFX_MSG_MAP(CPageStartup)
  30. ON_WM_DESTROY()
  31. ON_NOTIFY(LVN_ITEMCHANGED, IDC_LISTSTARTUP, OnItemChangedList)
  32. ON_BN_CLICKED(IDC_BUTTONSUDISABLEALL, OnButtonDisableAll)
  33. ON_BN_CLICKED(IDC_BUTTONSUENABLEALL, OnButtonEnableAll)
  34. ON_NOTIFY(NM_SETFOCUS, IDC_LISTSTARTUP, OnSetFocusList)
  35. ON_BN_CLICKED(IDC_BUTTONSURESTORE, OnButtonRestore)
  36. //}}AFX_MSG_MAP
  37. END_MESSAGE_MAP()
  38. /////////////////////////////////////////////////////////////////////////////
  39. // CPageStartup message handlers
  40. //-----------------------------------------------------------------------------
  41. // Load the list of startup items.
  42. //-----------------------------------------------------------------------------
  43. void CPageStartup::LoadStartupList()
  44. {
  45. m_fIgnoreListChanges = TRUE;
  46. EmptyList(FALSE);
  47. m_iNextPosition = 0;
  48. LoadStartupListLiveItems();
  49. LoadStartupListDisabledItems();
  50. m_fIgnoreListChanges = FALSE;
  51. }
  52. //-----------------------------------------------------------------------------
  53. // Load the list of items which are actually being started on this system.
  54. //-----------------------------------------------------------------------------
  55. void CPageStartup::LoadStartupListLiveItems()
  56. {
  57. LoadStartupListLiveItemsRunKey();
  58. LoadStartupListLiveItemsStartup();
  59. LoadStartupListLiveItemsWinIniKey();
  60. }
  61. //-----------------------------------------------------------------------------
  62. // Look under the Run registry key for startup items.
  63. //-----------------------------------------------------------------------------
  64. void CPageStartup::LoadStartupListLiveItemsRunKey()
  65. {
  66. LPCTSTR szRunKey = _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run");
  67. HKEY ahkey[] = { HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER, NULL };
  68. TCHAR szValueName[MAX_PATH], szValue[MAX_PATH];
  69. DWORD dwSize;
  70. CRegKey regkey;
  71. for (int i = 0; ahkey[i] != NULL; i++)
  72. {
  73. // Try to open the Run registry key.
  74. if (ERROR_SUCCESS != regkey.Open(ahkey[i], szRunKey, KEY_READ))
  75. continue;
  76. // Get the number of keys under the Run key and look at each one.
  77. DWORD dwValueCount;
  78. if (ERROR_SUCCESS != ::RegQueryInfoKey((HKEY)regkey, NULL, NULL, NULL, NULL, NULL, NULL, &dwValueCount, NULL, NULL, NULL, NULL))
  79. {
  80. regkey.Close();
  81. continue;
  82. }
  83. for (DWORD dwKey = 0; dwKey < dwValueCount; dwKey++)
  84. {
  85. dwSize = MAX_PATH;
  86. if (ERROR_SUCCESS != ::RegEnumValue((HKEY)regkey, dwKey, szValueName, &dwSize, NULL, NULL, NULL, NULL))
  87. continue;
  88. dwSize = MAX_PATH;
  89. if (ERROR_SUCCESS != regkey.QueryValue(szValue, szValueName, &dwSize))
  90. continue;
  91. // We don't want to show MSConfig in the startup item list.
  92. CString strTemp(szValue);
  93. strTemp.MakeLower();
  94. if (strTemp.Find(_T("msconfig.exe")) != -1)
  95. continue;
  96. // TBD - verify that the file exists?
  97. // To get the name of this startup item, we'll take the command and
  98. // strip off everything but the filename (without the extension).
  99. CString strName(szValue);
  100. GetCommandName(strName);
  101. // Create the startup item and insert it in the list.
  102. CStartupItemRegistry * pItem = new CStartupItemRegistry(ahkey[i], szRunKey, strName, szValueName, szValue);
  103. InsertStartupItem(pItem);
  104. }
  105. regkey.Close();
  106. }
  107. }
  108. //-----------------------------------------------------------------------------
  109. // Look under the registry for the mapped win.ini file and check out its run
  110. // and load items.
  111. //-----------------------------------------------------------------------------
  112. void CPageStartup::LoadStartupListLiveItemsWinIniKey()
  113. {
  114. LPCTSTR aszValueNames[] = { _T("Run"), _T("Load"), NULL };
  115. CRegKey regkey;
  116. TCHAR szValue[MAX_PATH * 4];
  117. DWORD dwSize;
  118. LPCTSTR szKeyName = _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows");
  119. HKEY hkey = HKEY_CURRENT_USER;
  120. if (ERROR_SUCCESS != regkey.Open(hkey, szKeyName, KEY_READ))
  121. return;
  122. for (int i = 0; aszValueNames[i] != NULL; i++)
  123. {
  124. dwSize = MAX_PATH * 4;
  125. if (ERROR_SUCCESS != regkey.QueryValue(szValue, aszValueNames[i], &dwSize))
  126. continue;
  127. // The string we get back is a comma delimited list of programs. We need
  128. // to parse them into individual programs.
  129. CString strLine(szValue);
  130. while (!strLine.IsEmpty())
  131. {
  132. CString strItem = strLine.SpanExcluding(_T(","));
  133. if (!strItem.IsEmpty())
  134. {
  135. // Create the startup item and insert it in the list.
  136. CString strCommandName(strItem);
  137. GetCommandName(strCommandName);
  138. CStartupItemRegistry * pItem = new CStartupItemRegistry(szKeyName, strCommandName, aszValueNames[i], strItem);
  139. InsertStartupItem(pItem);
  140. // Trim the item of the line.
  141. strLine = strLine.Mid(strItem.GetLength());
  142. }
  143. strLine.TrimLeft(_T(" ,"));
  144. }
  145. }
  146. regkey.Close();
  147. }
  148. //-----------------------------------------------------------------------------
  149. // Look in the startup folder for items.
  150. //-----------------------------------------------------------------------------
  151. void CPageStartup::LoadStartupListLiveItemsStartup()
  152. {
  153. LPCTSTR szRunKey = _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders");
  154. HKEY ahkey[] = { HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER, NULL };
  155. LPCTSTR aszRunValue[] = { _T("Common Startup"), _T("Startup"), NULL };
  156. CRegKey regkey;
  157. TCHAR szStartupFolderDir[MAX_PATH];
  158. TCHAR szStartupFileSpec[MAX_PATH];
  159. DWORD dwSize;
  160. for (int i = 0; ahkey[i] != NULL; i++)
  161. {
  162. // Try to open the registry key.
  163. if (ERROR_SUCCESS != regkey.Open(ahkey[i], szRunKey, KEY_READ))
  164. continue;
  165. // Get the path for the startup item folder.
  166. dwSize = MAX_PATH;
  167. if (aszRunValue[i] == NULL || ERROR_SUCCESS != regkey.QueryValue(szStartupFolderDir, aszRunValue[i], &dwSize))
  168. {
  169. regkey.Close();
  170. continue;
  171. }
  172. regkey.Close();
  173. // Append the filespec on the end of the directory.
  174. _tmakepath(szStartupFileSpec, NULL, szStartupFolderDir, _T("*.*"), NULL);
  175. // Examine all of the files in the directory.
  176. WIN32_FIND_DATA fd;
  177. HANDLE hFind = FindFirstFile(szStartupFileSpec, &fd);
  178. if (hFind != INVALID_HANDLE_VALUE)
  179. {
  180. do
  181. {
  182. // We want to ignore the desktop.ini file which might appear in startup.
  183. if ((fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) == 0 || _tcsicmp(fd.cFileName, _T("desktop.ini")) != 0)
  184. {
  185. // We only want to examine files which aren't directories.
  186. if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
  187. {
  188. CStartupItemFolder * pItem = new CStartupItemFolder;
  189. if (pItem)
  190. {
  191. if (pItem->Create(fd, ahkey[i], szRunKey, aszRunValue[i], szStartupFolderDir))
  192. this->InsertStartupItem(pItem);
  193. else
  194. delete pItem;
  195. }
  196. }
  197. }
  198. } while (FindNextFile(hFind, &fd));
  199. FindClose(hFind);
  200. }
  201. }
  202. }
  203. //-----------------------------------------------------------------------------
  204. // Load the list of items which were being started on this system, but which
  205. // we've disabled. This list is maintained in the registry.
  206. //-----------------------------------------------------------------------------
  207. void CPageStartup::LoadStartupListDisabledItems()
  208. {
  209. CRegKey regkey;
  210. regkey.Attach(GetRegKey(_T("startupreg")));
  211. if ((HKEY)regkey != NULL)
  212. {
  213. DWORD dwKeyCount, dwSize;
  214. TCHAR szKeyName[MAX_PATH];
  215. if (ERROR_SUCCESS == ::RegQueryInfoKey((HKEY)regkey, NULL, NULL, NULL, &dwKeyCount, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
  216. {
  217. for (DWORD dwKey = 0; dwKey < dwKeyCount; dwKey++)
  218. {
  219. dwSize = MAX_PATH;
  220. if (ERROR_SUCCESS != ::RegEnumKeyEx((HKEY)regkey, dwKey, szKeyName, &dwSize, NULL, NULL, NULL, NULL))
  221. continue;
  222. CRegKey regkeyItem;
  223. if (ERROR_SUCCESS == regkeyItem.Open((HKEY)regkey, szKeyName, KEY_READ))
  224. {
  225. CStartupItemRegistry * pItem = new CStartupItemRegistry;
  226. if (pItem->Create(szKeyName, (HKEY)regkeyItem))
  227. InsertStartupItem(pItem);
  228. else
  229. delete pItem;
  230. regkeyItem.Close();
  231. }
  232. }
  233. }
  234. regkey.Close();
  235. }
  236. regkey.Attach(GetRegKey(_T("startupfolder")));
  237. if ((HKEY)regkey != NULL)
  238. {
  239. DWORD dwKeyCount, dwSize;
  240. TCHAR szKeyName[MAX_PATH];
  241. if (ERROR_SUCCESS == ::RegQueryInfoKey((HKEY)regkey, NULL, NULL, NULL, &dwKeyCount, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
  242. {
  243. for (DWORD dwKey = 0; dwKey < dwKeyCount; dwKey++)
  244. {
  245. dwSize = MAX_PATH;
  246. if (ERROR_SUCCESS != ::RegEnumKeyEx((HKEY)regkey, dwKey, szKeyName, &dwSize, NULL, NULL, NULL, NULL))
  247. continue;
  248. CRegKey regkeyItem;
  249. if (ERROR_SUCCESS == regkeyItem.Open((HKEY)regkey, szKeyName, KEY_READ))
  250. {
  251. CStartupItemFolder * pItem = new CStartupItemFolder;
  252. if (pItem->Create(szKeyName, (HKEY)regkeyItem))
  253. InsertStartupItem(pItem);
  254. else
  255. delete pItem;
  256. regkeyItem.Close();
  257. }
  258. }
  259. }
  260. regkey.Close();
  261. }
  262. }
  263. //-----------------------------------------------------------------------------
  264. // Take a command line and strip off everything except the command name.
  265. //-----------------------------------------------------------------------------
  266. void CPageStartup::GetCommandName(CString & strCommand)
  267. {
  268. // Strip off the path information.
  269. int iLastBackslash = strCommand.ReverseFind(_T('\\'));
  270. if (iLastBackslash != -1)
  271. strCommand = strCommand.Mid(iLastBackslash + 1);
  272. // Strip off the extension and any flags.
  273. int iDot = strCommand.Find(_T('.'));
  274. if (iDot != -1)
  275. {
  276. if (iDot != 0)
  277. strCommand = strCommand.Left(iDot);
  278. else
  279. strCommand.Empty();
  280. }
  281. }
  282. //-----------------------------------------------------------------------------
  283. // Insert the specified item in the startup list. The caller is then not
  284. // responsible for deleting the item.
  285. //-----------------------------------------------------------------------------
  286. void CPageStartup::InsertStartupItem(CStartupItem * pItem)
  287. {
  288. ASSERT(pItem);
  289. if (pItem == NULL)
  290. return;
  291. // Get the strings to add to the list view.
  292. CString strItem, strLocation, strCommand;
  293. pItem->GetDisplayInfo(strItem, strLocation, strCommand);
  294. // Insert the item in the list view.
  295. LV_ITEM lvi;
  296. memset(&lvi, 0, sizeof(lvi));
  297. lvi.mask = LVIF_TEXT | LVIF_PARAM;
  298. lvi.iItem = m_iNextPosition;
  299. lvi.pszText = (LPTSTR)(LPCTSTR)strItem;
  300. lvi.iSubItem = 0;
  301. lvi.lParam = (LPARAM)pItem;
  302. m_iNextPosition = ListView_InsertItem(m_list.m_hWnd, &lvi);
  303. ListView_SetItemText(m_list.m_hWnd, m_iNextPosition, 1, (LPTSTR)(LPCTSTR)strCommand);
  304. ListView_SetItemText(m_list.m_hWnd, m_iNextPosition, 2, (LPTSTR)(LPCTSTR)strLocation);
  305. ListView_SetCheckState(m_list.m_hWnd, m_iNextPosition, pItem->IsLive());
  306. m_iNextPosition++;
  307. }
  308. //-----------------------------------------------------------------------------
  309. // Remove all the items from the list view (freeing the objects pointed to
  310. // by the LPARAM).
  311. //-----------------------------------------------------------------------------
  312. void CPageStartup::EmptyList(BOOL fFreeMemoryOnly)
  313. {
  314. LVITEM lvi;
  315. lvi.mask = LVIF_PARAM;
  316. lvi.iSubItem = 0;
  317. for (int i = ListView_GetItemCount(m_list.m_hWnd) - 1; i >= 0; i--)
  318. {
  319. lvi.iItem = i;
  320. if (ListView_GetItem(m_list.m_hWnd, &lvi))
  321. {
  322. CStartupItem * pItem = (CStartupItem *)lvi.lParam;
  323. if (pItem)
  324. delete pItem;
  325. // If we're leaving the list with these items, we better
  326. // not do a double delete.
  327. if (fFreeMemoryOnly)
  328. {
  329. lvi.lParam = 0;
  330. ListView_SetItem(m_list.m_hWnd, &lvi);
  331. }
  332. }
  333. }
  334. if (!fFreeMemoryOnly)
  335. ListView_DeleteAllItems(m_list.m_hWnd);
  336. }
  337. //-----------------------------------------------------------------------------
  338. // Set the state of all of the items in the list.
  339. //-----------------------------------------------------------------------------
  340. void CPageStartup::SetEnableForList(BOOL fEnable)
  341. {
  342. HWND hwndFocus = ::GetFocus();
  343. LVITEM lvi;
  344. lvi.mask = LVIF_PARAM;
  345. lvi.iSubItem = 0;
  346. for (int i = ListView_GetItemCount(m_list.m_hWnd) - 1; i >= 0; i--)
  347. ListView_SetCheckState(m_list.m_hWnd, i, fEnable);
  348. ::EnableWindow(GetDlgItemHWND(IDC_BUTTONSUDISABLEALL), fEnable);
  349. if (!fEnable && hwndFocus == GetDlgItemHWND(IDC_BUTTONSUDISABLEALL))
  350. PrevDlgCtrl();
  351. ::EnableWindow(GetDlgItemHWND(IDC_BUTTONSUENABLEALL), !fEnable);
  352. if (fEnable && hwndFocus == GetDlgItemHWND(IDC_BUTTONSUENABLEALL))
  353. NextDlgCtrl();
  354. }
  355. //============================================================================
  356. // The CStartupItemRegistry class is used to encapsulate an individual startup
  357. // stored in the registry.
  358. //============================================================================
  359. //----------------------------------------------------------------------------
  360. // Construct this flavor of startup item.
  361. //----------------------------------------------------------------------------
  362. CStartupItemRegistry::CStartupItemRegistry()
  363. {
  364. m_hkey = NULL;
  365. m_fIniMapping = FALSE;
  366. }
  367. CStartupItemRegistry::CStartupItemRegistry(HKEY hkey, LPCTSTR szKey, LPCTSTR szName, LPCTSTR szValueName, LPCTSTR szValue)
  368. {
  369. m_fIniMapping = FALSE;
  370. m_fLive = TRUE;
  371. m_strItem = szName;
  372. m_strLocation = szKey;
  373. m_strCommand = szValue;
  374. // Add the HKEY to the location.
  375. if (hkey == HKEY_LOCAL_MACHINE)
  376. m_strLocation = CString(_T("HKLM\\")) + m_strLocation;
  377. else if (hkey == HKEY_CURRENT_USER)
  378. m_strLocation = CString(_T("HKCU\\")) + m_strLocation;
  379. m_hkey = hkey;
  380. m_strKey = szKey;
  381. m_strValueName = szValueName;
  382. }
  383. //----------------------------------------------------------------------------
  384. // This constructor is specifically for items under the INI file registry
  385. // mapping.
  386. //----------------------------------------------------------------------------
  387. CStartupItemRegistry::CStartupItemRegistry(LPCTSTR szKey, LPCTSTR szName, LPCTSTR szValueName, LPCTSTR szValue)
  388. {
  389. m_fIniMapping = TRUE;
  390. m_fLive = TRUE;
  391. m_strItem = szName;
  392. m_strLocation = szKey;
  393. m_strCommand = szValue;
  394. m_strLocation = CString(_T("HKCU\\")) + m_strLocation + CString(_T(":")) + szValueName;
  395. m_hkey = HKEY_CURRENT_USER;
  396. m_strKey = szKey;
  397. m_strValueName = szValueName;
  398. }
  399. //----------------------------------------------------------------------------
  400. // Enable or disable the startup item in the registry.
  401. //----------------------------------------------------------------------------
  402. BOOL CStartupItemRegistry::SetEnable(BOOL fEnable)
  403. {
  404. if (fEnable == IsLive())
  405. return FALSE;
  406. CRegKey regkey;
  407. if (ERROR_SUCCESS != regkey.Open(m_hkey, m_strKey, KEY_ALL_ACCESS))
  408. return FALSE;
  409. LONG lReturnCode = ERROR_SUCCESS + 1; // need to initialize it to not ERROR_SUCCESS
  410. if (m_fIniMapping == FALSE)
  411. {
  412. // Create or delete the registry key from the data stored in
  413. // this object.
  414. if (fEnable)
  415. lReturnCode = regkey.SetValue(m_strCommand, m_strValueName);
  416. else
  417. lReturnCode = regkey.DeleteValue(m_strValueName);
  418. }
  419. else
  420. {
  421. // This item is an INI file mapping item (which means there
  422. // might be more than one item on this line).
  423. TCHAR szValue[MAX_PATH * 4];
  424. DWORD dwSize = MAX_PATH * 4;
  425. if (ERROR_SUCCESS == regkey.QueryValue(szValue, m_strValueName, &dwSize))
  426. {
  427. CString strValue(szValue);
  428. if (fEnable)
  429. {
  430. if (!strValue.IsEmpty())
  431. strValue += CString(_T(", "));
  432. strValue += m_strCommand;
  433. }
  434. else
  435. {
  436. // The harder case - we need to remove the item, and possibly commas.
  437. int iCommand = strValue.Find(m_strCommand);
  438. if (iCommand != -1)
  439. {
  440. CString strNewValue;
  441. if (iCommand > 0)
  442. {
  443. strNewValue = strValue.Left(iCommand);
  444. strNewValue.TrimRight(_T(", "));
  445. }
  446. if (strValue.GetLength() > (m_strCommand.GetLength() + iCommand))
  447. {
  448. if (!strNewValue.IsEmpty())
  449. strNewValue += CString(_T(", "));
  450. CString strRemainder(strValue.Mid(iCommand + m_strCommand.GetLength()));
  451. strRemainder.TrimLeft(_T(", "));
  452. strNewValue += strRemainder;
  453. }
  454. strValue = strNewValue;
  455. }
  456. }
  457. lReturnCode = regkey.SetValue(strValue, m_strValueName);
  458. }
  459. }
  460. regkey.Close();
  461. if (lReturnCode != ERROR_SUCCESS)
  462. return FALSE;
  463. // Delete or create the registry representation of this item.
  464. // This representation persists the startup item when it has
  465. // been deleted.
  466. regkey.Attach(GetRegKey(_T("startupreg")));
  467. if ((HKEY)regkey != NULL)
  468. {
  469. if (fEnable)
  470. regkey.DeleteSubKey(m_strValueName);
  471. else
  472. {
  473. regkey.SetKeyValue(m_strValueName, m_strKey, _T("key"));
  474. regkey.SetKeyValue(m_strValueName, m_strItem, _T("item"));
  475. if (m_hkey == HKEY_LOCAL_MACHINE)
  476. regkey.SetKeyValue(m_strValueName, _T("HKLM"), _T("hkey"));
  477. else
  478. regkey.SetKeyValue(m_strValueName, _T("HKCU"), _T("hkey"));
  479. regkey.SetKeyValue(m_strValueName, m_strCommand, _T("command"));
  480. regkey.SetKeyValue(m_strValueName, m_fIniMapping ? _T("1") : _T("0"), _T("inimapping"));
  481. }
  482. regkey.Close();
  483. }
  484. m_fLive = fEnable;
  485. return TRUE;
  486. }
  487. //----------------------------------------------------------------------------
  488. // Create the startup item from the registry representation of the item.
  489. //----------------------------------------------------------------------------
  490. BOOL CStartupItemRegistry::Create(LPCTSTR szKeyName, HKEY hkey)
  491. {
  492. if (hkey == NULL)
  493. return FALSE;
  494. CRegKey regkey;
  495. regkey.Attach(hkey);
  496. if ((HKEY)regkey == NULL)
  497. return FALSE;
  498. // Restore all of the values from the registry.
  499. TCHAR szValue[MAX_PATH];
  500. DWORD dwSize;
  501. dwSize = MAX_PATH;
  502. if (ERROR_SUCCESS != regkey.QueryValue(szValue, _T("key"), &dwSize))
  503. {
  504. regkey.Detach();
  505. return FALSE;
  506. }
  507. m_strKey = szValue;
  508. dwSize = MAX_PATH;
  509. if (ERROR_SUCCESS != regkey.QueryValue(szValue, _T("command"), &dwSize))
  510. {
  511. regkey.Detach();
  512. return FALSE;
  513. }
  514. m_strCommand = szValue;
  515. dwSize = MAX_PATH;
  516. if (ERROR_SUCCESS != regkey.QueryValue(szValue, _T("item"), &dwSize))
  517. {
  518. regkey.Detach();
  519. return FALSE;
  520. }
  521. m_strItem = szValue;
  522. dwSize = MAX_PATH;
  523. if (ERROR_SUCCESS != regkey.QueryValue(szValue, _T("hkey"), &dwSize))
  524. {
  525. regkey.Detach();
  526. return FALSE;
  527. }
  528. if (_tcscmp(szValue, _T("HKLM")) == 0)
  529. m_hkey = HKEY_LOCAL_MACHINE;
  530. else
  531. m_hkey = HKEY_CURRENT_USER;
  532. dwSize = MAX_PATH;
  533. if (ERROR_SUCCESS != regkey.QueryValue(szValue, _T("inimapping"), &dwSize))
  534. {
  535. regkey.Detach();
  536. return FALSE;
  537. }
  538. if (_tcscmp(szValue, _T("0")) == 0)
  539. m_fIniMapping = FALSE;
  540. else
  541. m_fIniMapping = TRUE;
  542. regkey.Detach();
  543. m_strLocation = m_strKey;
  544. m_strValueName = szKeyName;
  545. m_fLive = FALSE;
  546. return TRUE;
  547. }
  548. //----------------------------------------------------------------------------
  549. // Remove all the entries persisted in the registry.
  550. //----------------------------------------------------------------------------
  551. void CStartupItemRegistry::RemovePersistedEntries()
  552. {
  553. CRegKey regkey;
  554. regkey.Attach(GetRegKey());
  555. if ((HKEY)regkey != NULL)
  556. regkey.RecurseDeleteKey(_T("startupreg"));
  557. }
  558. //============================================================================
  559. // The CStartupItemFolder class is used to encapsulate an individual startup
  560. // stored in the startup folder.
  561. //============================================================================
  562. CStartupItemFolder::CStartupItemFolder()
  563. {
  564. }
  565. //----------------------------------------------------------------------------
  566. // Enable or disable this startup item. Since the item is an actual file in
  567. // a folder, disabling it will mean copying that file to a backup folder and
  568. // creating a registry entry for it. Enabling will mean copying the file
  569. // back to the appropriate startup folder and deleting the registry entry.
  570. //----------------------------------------------------------------------------
  571. BOOL CStartupItemFolder::SetEnable(BOOL fEnable)
  572. {
  573. if (fEnable == IsLive())
  574. return FALSE;
  575. // Copy the file (from or to the backup directory).
  576. if (fEnable)
  577. {
  578. m_strBackupPath = GetBackupName(m_strFilePath, m_strLocation);
  579. ::CopyFile(m_strBackupPath, m_strFilePath, FALSE);
  580. }
  581. else
  582. {
  583. BackupFile(m_strFilePath, m_strLocation, TRUE);
  584. m_strBackupPath = GetBackupName(m_strFilePath, m_strLocation);
  585. }
  586. // Update the registry for the new state. If we are making the file
  587. // disabled, then we need to save both the original path and the
  588. // backed up path (and the standard startup item stuff). Otherwise
  589. // just delete the key.
  590. CRegKey regkey;
  591. regkey.Attach(GetRegKey(_T("startupfolder")));
  592. if ((HKEY)regkey == NULL)
  593. return FALSE;
  594. // The name for the registry key just needs to be unique. And not
  595. // have any backslashes in it.
  596. CString strRegkey(m_strFilePath);
  597. strRegkey.Replace(_T("\\"), _T("^"));
  598. if (fEnable)
  599. {
  600. regkey.DeleteSubKey(strRegkey);
  601. ::DeleteFile(m_strBackupPath);
  602. }
  603. else
  604. {
  605. regkey.SetKeyValue(strRegkey, m_strFilePath, _T("path"));
  606. regkey.SetKeyValue(strRegkey, m_strBackupPath, _T("backup"));
  607. regkey.SetKeyValue(strRegkey, m_strLocation, _T("location"));
  608. regkey.SetKeyValue(strRegkey, m_strCommand, _T("command"));
  609. regkey.SetKeyValue(strRegkey, m_strItem, _T("item"));
  610. ::DeleteFile(m_strFilePath);
  611. }
  612. m_fLive = fEnable;
  613. return TRUE;
  614. }
  615. //----------------------------------------------------------------------------
  616. // Load the disabled startup item from the registry.
  617. //----------------------------------------------------------------------------
  618. BOOL CStartupItemFolder::Create(LPCTSTR szKeyName, HKEY hkey)
  619. {
  620. if (hkey == NULL)
  621. return FALSE;
  622. CRegKey regkey;
  623. regkey.Attach(hkey);
  624. if ((HKEY)regkey == NULL)
  625. return FALSE;
  626. // Restore all of the values from the registry.
  627. TCHAR szValue[MAX_PATH];
  628. DWORD dwSize;
  629. dwSize = MAX_PATH;
  630. if (ERROR_SUCCESS != regkey.QueryValue(szValue, _T("path"), &dwSize))
  631. {
  632. regkey.Detach();
  633. return FALSE;
  634. }
  635. m_strFilePath = szValue;
  636. dwSize = MAX_PATH;
  637. if (ERROR_SUCCESS != regkey.QueryValue(szValue, _T("backup"), &dwSize))
  638. {
  639. regkey.Detach();
  640. return FALSE;
  641. }
  642. m_strBackupPath = szValue;
  643. dwSize = MAX_PATH;
  644. if (ERROR_SUCCESS != regkey.QueryValue(szValue, _T("location"), &dwSize))
  645. {
  646. regkey.Detach();
  647. return FALSE;
  648. }
  649. m_strLocation = szValue;
  650. dwSize = MAX_PATH;
  651. if (ERROR_SUCCESS != regkey.QueryValue(szValue, _T("command"), &dwSize))
  652. {
  653. regkey.Detach();
  654. return FALSE;
  655. }
  656. m_strCommand = szValue;
  657. dwSize = MAX_PATH;
  658. if (ERROR_SUCCESS != regkey.QueryValue(szValue, _T("item"), &dwSize))
  659. {
  660. regkey.Detach();
  661. return FALSE;
  662. }
  663. m_strItem = szValue;
  664. regkey.Detach();
  665. m_fLive = FALSE;
  666. return TRUE;
  667. }
  668. //----------------------------------------------------------------------------
  669. // Create the startup item from the file found in the folder. If the file
  670. // is a shortcut, get the information about the target.
  671. //----------------------------------------------------------------------------
  672. BOOL CStartupItemFolder::Create(const WIN32_FIND_DATA & fd, HKEY hkey, LPCTSTR szRegPathToFolder, LPCTSTR szFolder, LPCTSTR szDir)
  673. {
  674. // We want to save the path to the file in the startup folder (even if
  675. // it is a shortcut).
  676. m_strFilePath = szDir;
  677. if (m_strFilePath.Right(1) != CString(_T("\\")))
  678. m_strFilePath += CString(_T("\\"));
  679. m_strFilePath += fd.cFileName;
  680. // Look at the file to determine how to handle it.
  681. CString strFile(fd.cFileName);
  682. strFile.MakeLower();
  683. if (strFile.Right(4) == CString(_T(".lnk")))
  684. {
  685. // The file is a shortcut to a different command. Show that command.
  686. CIconInfo info;
  687. _tcscpy(info.szPath, m_strFilePath);
  688. if (SUCCEEDED(GetIconInfo(info)))
  689. {
  690. m_fLive = TRUE;
  691. m_strItem = fd.cFileName;
  692. m_strLocation = szFolder;
  693. m_strCommand.Format(_T("%s %s"), info.szTarget, info.szArgs);
  694. int iDot = m_strItem.ReverseFind(_T('.'));
  695. if (iDot > 0)
  696. m_strItem = m_strItem.Left(iDot);
  697. return TRUE;
  698. }
  699. }
  700. else
  701. {
  702. // A file besides a shortcut. It may be an EXE, or some other file type
  703. // (we'll handle them the same).
  704. m_fLive = TRUE;
  705. m_strItem = fd.cFileName;
  706. m_strLocation = szFolder;
  707. m_strCommand = m_strFilePath;
  708. int iDot = m_strItem.ReverseFind(_T('.'));
  709. if (iDot > 0)
  710. m_strItem = m_strItem.Left(iDot);
  711. return TRUE;
  712. }
  713. return FALSE;
  714. }
  715. //----------------------------------------------------------------------------
  716. // Get the information about a shortcut. Creates a thread to do so, since it
  717. // needs to be done in an apartment model thread.
  718. //
  719. // JJ's code, cleaned up a bit.
  720. //----------------------------------------------------------------------------
  721. DWORD GetIconInfoProc(CStartupItemFolder::CIconInfo * pInfo);
  722. HRESULT CStartupItemFolder::GetIconInfo(CIconInfo & info)
  723. {
  724. DWORD dwID;
  725. HANDLE hThread;
  726. if (hThread = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)GetIconInfoProc, &info, 0, &dwID))
  727. {
  728. info.hResult = S_OK;
  729. ::WaitForSingleObject(hThread, INFINITE);
  730. }
  731. else
  732. info.hResult = E_FAIL;
  733. return info.hResult;
  734. }
  735. //----------------------------------------------------------------------------
  736. // Remove all the entries persisted in the registry.
  737. //----------------------------------------------------------------------------
  738. void CStartupItemFolder::RemovePersistedEntries()
  739. {
  740. CRegKey regkey;
  741. regkey.Attach(GetRegKey());
  742. if ((HKEY)regkey != NULL)
  743. regkey.RecurseDeleteKey(_T("startupfolder"));
  744. }
  745. //----------------------------------------------------------------------------
  746. // Procedure (run in its own thread) to get information about a shortcut.
  747. //
  748. // JJ's code, cleaned up a bit.
  749. //----------------------------------------------------------------------------
  750. DWORD GetIconInfoProc(CStartupItemFolder::CIconInfo * pInfo)
  751. {
  752. HRESULT hResult;
  753. IShellLink * psl = NULL;
  754. IPersistFile * ppf = NULL;
  755. try
  756. {
  757. // We have to use COINIT_APARTMENTTHREADED.
  758. if (SUCCEEDED(hResult = CoInitialize(NULL)))
  759. {
  760. // Get a pointer to the IShellLink interface.
  761. if (SUCCEEDED(hResult = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (VOID **) &psl)))
  762. {
  763. // Get a pointer to the IPersistFile interface.
  764. if (SUCCEEDED(hResult = psl->QueryInterface(IID_IPersistFile, (VOID **) &ppf)))
  765. {
  766. BSTR bstrPath;
  767. #ifdef UNICODE
  768. bstrPath = pInfo->szPath;
  769. #else
  770. WCHAR wszTemp[MAX_PATH];
  771. wsprintfW(wszTemp, L"%hs", pInfo->szPath);
  772. bstrPath = wszTemp;
  773. #endif
  774. if (SUCCEEDED(hResult = ppf->Load(bstrPath, STGM_READ)))
  775. {
  776. WIN32_FIND_DATA fd;
  777. hResult = psl->GetPath(pInfo->szTarget, sizeof(pInfo->szTarget), &fd, SLGP_SHORTPATH);
  778. hResult = psl->GetArguments(pInfo->szArgs, sizeof(pInfo->szArgs));
  779. }
  780. }
  781. }
  782. }
  783. pInfo->hResult = hResult;
  784. }
  785. catch(...)
  786. {
  787. if (psl)
  788. psl->Release();
  789. if (ppf)
  790. ppf->Release();
  791. CoUninitialize();
  792. throw;
  793. }
  794. if (psl)
  795. {
  796. psl->Release();
  797. psl = NULL;
  798. }
  799. if (ppf)
  800. {
  801. ppf->Release();
  802. ppf = NULL;
  803. }
  804. CoUninitialize();
  805. return 0;
  806. }
  807. BOOL CPageStartup::OnInitDialog()
  808. {
  809. CPropertyPage::OnInitDialog();
  810. ::EnableWindow(GetDlgItemHWND(IDC_LISTSTARTUP), TRUE);
  811. // Attach to the list view and set the styles we need.
  812. m_fIgnoreListChanges = TRUE;
  813. m_list.Attach(GetDlgItemHWND(IDC_LISTSTARTUP));
  814. ListView_SetExtendedListViewStyle(m_list.m_hWnd, LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT);
  815. // Add all of the necessary columns to the list view's header control.
  816. struct { UINT m_uiStringResource; int m_iPercentOfWidth; } aColumns[] =
  817. {
  818. { IDS_STARTUP_LOCATION, 50 },
  819. { IDS_STARTUP_COMMAND, 25 },
  820. { IDS_STARTUP_ITEM, 25 },
  821. { 0, 0 }
  822. };
  823. CRect rect;
  824. m_list.GetClientRect(&rect);
  825. int cxWidth = rect.Width();
  826. LVCOLUMN lvc;
  827. lvc.mask = LVCF_TEXT | LVCF_WIDTH;
  828. CString strCaption;
  829. ::AfxSetResourceHandle(_Module.GetResourceInstance());
  830. for (int i = 0; aColumns[i].m_uiStringResource; i++)
  831. {
  832. strCaption.LoadString(aColumns[i].m_uiStringResource);
  833. lvc.pszText = (LPTSTR)(LPCTSTR)strCaption;
  834. lvc.cx = aColumns[i].m_iPercentOfWidth * cxWidth / 100;
  835. ListView_InsertColumn(m_list.m_hWnd, 0, &lvc);
  836. }
  837. LoadStartupList();
  838. CPageBase::TabState state = GetCurrentTabState();
  839. ::EnableWindow(GetDlgItemHWND(IDC_BUTTONSUDISABLEALL), (state != DIAGNOSTIC));
  840. ::EnableWindow(GetDlgItemHWND(IDC_BUTTONSUENABLEALL), (state != NORMAL));
  841. m_stateRequested = GetAppliedTabState();
  842. m_fInitialized = TRUE;
  843. // Show the restore disabled startup item button based on whether or not
  844. // there are items to restore.
  845. ::ShowWindow(GetDlgItemHWND(IDC_BUTTONSURESTORE), CRestoreStartup::AreItemsToRestore() ? SW_SHOW : SW_HIDE);
  846. return TRUE; // return TRUE unless you set the focus to a control
  847. }
  848. void CPageStartup::OnDestroy()
  849. {
  850. CPropertyPage::OnDestroy();
  851. EmptyList(TRUE);
  852. }
  853. //-----------------------------------------------------------------------------
  854. // If there's a change to an item in the list, it's probably because the user
  855. // has checked or unchecked a checkbox.
  856. //-----------------------------------------------------------------------------
  857. void CPageStartup::OnItemChangedList(NMHDR * pNMHDR, LRESULT * pResult)
  858. {
  859. NM_LISTVIEW * pNMListView = (NM_LISTVIEW *)pNMHDR;
  860. if (!m_fIgnoreListChanges)
  861. {
  862. LVITEM lvi;
  863. lvi.mask = LVIF_PARAM;
  864. lvi.iSubItem = 0;
  865. lvi.iItem = pNMListView->iItem;
  866. if (ListView_GetItem(m_list.m_hWnd, &lvi))
  867. {
  868. CStartupItem * pItem = (CStartupItem *)lvi.lParam;
  869. if (pItem)
  870. {
  871. BOOL fCurrentCheck = ListView_GetCheckState(m_list.m_hWnd, pNMListView->iItem);
  872. if (fCurrentCheck != pItem->IsLive())
  873. SetModified(TRUE);
  874. CPageBase::TabState state = GetCurrentTabState();
  875. ::EnableWindow(GetDlgItemHWND(IDC_BUTTONSUDISABLEALL), (state != DIAGNOSTIC));
  876. ::EnableWindow(GetDlgItemHWND(IDC_BUTTONSUENABLEALL), (state != NORMAL));
  877. }
  878. }
  879. }
  880. *pResult = 0;
  881. }
  882. //-----------------------------------------------------------------------------
  883. // Handle the buttons to enable or disable all the items.
  884. //-----------------------------------------------------------------------------
  885. void CPageStartup::OnButtonDisableAll()
  886. {
  887. SetEnableForList(FALSE);
  888. }
  889. void CPageStartup::OnButtonEnableAll()
  890. {
  891. SetEnableForList(TRUE);
  892. }
  893. //-------------------------------------------------------------------------
  894. // Return the current state of the tab (need to look through the list).
  895. //-------------------------------------------------------------------------
  896. CPageBase::TabState CPageStartup::GetCurrentTabState()
  897. {
  898. if (!m_fInitialized)
  899. return GetAppliedTabState();
  900. // If there are no startup items, we can only return the
  901. // state that was last requested.
  902. if (ListView_GetItemCount(m_list.m_hWnd) == 0)
  903. return m_stateRequested;
  904. TabState stateReturn = USER;
  905. BOOL fAllEnabled = TRUE, fAllDisabled = TRUE;
  906. LVITEM lvi;
  907. lvi.mask = LVIF_PARAM;
  908. lvi.iSubItem = 0;
  909. for (int i = ListView_GetItemCount(m_list.m_hWnd) - 1; i >= 0; i--)
  910. {
  911. if (ListView_GetCheckState(m_list.m_hWnd, i))
  912. fAllDisabled = FALSE;
  913. else
  914. fAllEnabled = FALSE;
  915. }
  916. if (fAllEnabled)
  917. stateReturn = NORMAL;
  918. else if (fAllDisabled)
  919. stateReturn = DIAGNOSTIC;
  920. return stateReturn;
  921. }
  922. //-------------------------------------------------------------------------
  923. // Traverse the list looking for items which have check boxes that don't
  924. // match the state of the items. For these items, set the state.
  925. //
  926. // Finally, the base class implementation is called to maintain the
  927. // applied tab state.
  928. //-------------------------------------------------------------------------
  929. BOOL CPageStartup::OnApply()
  930. {
  931. LVITEM lvi;
  932. lvi.mask = LVIF_PARAM;
  933. lvi.iSubItem = 0;
  934. for (int i = ListView_GetItemCount(m_list.m_hWnd) - 1; i >= 0; i--)
  935. {
  936. lvi.iItem = i;
  937. if (ListView_GetItem(m_list.m_hWnd, &lvi))
  938. {
  939. CStartupItem * pItem = (CStartupItem *)lvi.lParam;
  940. if (pItem)
  941. {
  942. BOOL fCurrentCheck = ListView_GetCheckState(m_list.m_hWnd, i);
  943. if (fCurrentCheck != pItem->IsLive())
  944. pItem->SetEnable(fCurrentCheck);
  945. }
  946. }
  947. }
  948. CPageBase::SetAppliedState(GetCurrentTabState());
  949. CancelToClose();
  950. m_fMadeChange = TRUE;
  951. return TRUE;
  952. }
  953. //-------------------------------------------------------------------------
  954. // Apply the changes, remove the persisted registry entries, refill the
  955. // list. Then call the base class implementation.
  956. //-------------------------------------------------------------------------
  957. void CPageStartup::CommitChanges()
  958. {
  959. OnApply();
  960. CStartupItemRegistry::RemovePersistedEntries();
  961. CStartupItemFolder::RemovePersistedEntries();
  962. LoadStartupList();
  963. CPageBase::CommitChanges();
  964. }
  965. //-------------------------------------------------------------------------
  966. // Set the overall state of the tab to normal or diagnostic.
  967. //-------------------------------------------------------------------------
  968. void CPageStartup::SetNormal()
  969. {
  970. SetEnableForList(TRUE);
  971. m_stateRequested = NORMAL;
  972. }
  973. void CPageStartup::SetDiagnostic()
  974. {
  975. SetEnableForList(FALSE);
  976. m_stateRequested = DIAGNOSTIC;
  977. }
  978. //-------------------------------------------------------------------------
  979. // If nothing is selected when the list gets focus, select the first item
  980. // (so the user sees where the focus is).
  981. //-------------------------------------------------------------------------
  982. void CPageStartup::OnSetFocusList(NMHDR * pNMHDR, LRESULT * pResult)
  983. {
  984. if (0 == ListView_GetSelectedCount(m_list.m_hWnd) && 0 < ListView_GetItemCount(m_list.m_hWnd))
  985. ListView_SetItemState(m_list.m_hWnd, 0, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
  986. *pResult = 0;
  987. }
  988. //-------------------------------------------------------------------------
  989. // Show the dialog which allows the user to restore startup items which
  990. // were disabled during upgrade.
  991. //-------------------------------------------------------------------------
  992. void CPageStartup::OnButtonRestore()
  993. {
  994. CRestoreStartup dlg;
  995. dlg.DoModal();
  996. ::EnableWindow(GetDlgItemHWND(IDC_BUTTONSURESTORE), CRestoreStartup::AreItemsToRestore());
  997. }
  998. //=========================================================================
  999. // This code implements the CRestoreStartup dialog, which allows the
  1000. // user to restore items disabled by an upgrade.
  1001. //=========================================================================
  1002. CRestoreStartup::CRestoreStartup(CWnd* pParent /*=NULL*/) : CDialog(CRestoreStartup::IDD, pParent)
  1003. {
  1004. //{{AFX_DATA_INIT(CRestoreStartup)
  1005. // NOTE: the ClassWizard will add member initialization here
  1006. //}}AFX_DATA_INIT
  1007. }
  1008. void CRestoreStartup::DoDataExchange(CDataExchange* pDX)
  1009. {
  1010. CDialog::DoDataExchange(pDX);
  1011. //{{AFX_DATA_MAP(CRestoreStartup)
  1012. // NOTE: the ClassWizard will add DDX and DDV calls here
  1013. //}}AFX_DATA_MAP
  1014. }
  1015. BEGIN_MESSAGE_MAP(CRestoreStartup, CDialog)
  1016. //{{AFX_MSG_MAP(CRestoreStartup)
  1017. ON_WM_DESTROY()
  1018. ON_NOTIFY(LVN_ITEMCHANGED, IDC_RESTORELIST, OnItemChangedRestoreList)
  1019. //}}AFX_MSG_MAP
  1020. END_MESSAGE_MAP()
  1021. //-----------------------------------------------------------------------------
  1022. // As the dialog initializes, set the format of the list view, add the
  1023. // appropriate columns, and populate the list with the disabled startup items.
  1024. //-----------------------------------------------------------------------------
  1025. BOOL CRestoreStartup::OnInitDialog()
  1026. {
  1027. CDialog::OnInitDialog();
  1028. // Set the list view to have check boxes.
  1029. CWnd * pWnd = GetDlgItem(IDC_RESTORELIST);
  1030. if (pWnd == NULL)
  1031. return FALSE;
  1032. m_list.Attach(pWnd->m_hWnd);
  1033. ListView_SetExtendedListViewStyle(m_list.m_hWnd, LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT);
  1034. // Add all of the necessary columns to the list view's header control.
  1035. struct { UINT m_uiStringResource; int m_iPercentOfWidth; } aColumns[] =
  1036. {
  1037. { IDS_STARTUP_ITEM, 65 },
  1038. { IDS_STARTUP_LOCATION, 35 },
  1039. { 0, 0 }
  1040. };
  1041. CRect rect;
  1042. m_list.GetClientRect(&rect);
  1043. int cxWidth = rect.Width();
  1044. LVCOLUMN lvc;
  1045. lvc.mask = LVCF_TEXT | LVCF_WIDTH;
  1046. CString strCaption;
  1047. ::AfxSetResourceHandle(_Module.GetResourceInstance());
  1048. for (int i = 0; aColumns[i].m_uiStringResource; i++)
  1049. {
  1050. strCaption.LoadString(aColumns[i].m_uiStringResource);
  1051. lvc.pszText = (LPTSTR)(LPCTSTR)strCaption;
  1052. lvc.cx = aColumns[i].m_iPercentOfWidth * cxWidth / 100;
  1053. ListView_InsertColumn(m_list.m_hWnd, 0, &lvc);
  1054. }
  1055. // Load up the list with the disabled items.
  1056. LoadDisabledItemList();
  1057. SetOKState();
  1058. return TRUE;
  1059. }
  1060. //-----------------------------------------------------------------------------
  1061. // Load the items in the list (from the registry and startup directory).
  1062. //-----------------------------------------------------------------------------
  1063. BOOL CRestoreStartup::LoadDisabledItemList()
  1064. {
  1065. m_iNextPosition = 0;
  1066. BOOL fRegistry = LoadDisabledRegistry();
  1067. BOOL fStartup = LoadDisabledStartupGroup();
  1068. return (fRegistry && fStartup);
  1069. }
  1070. //-----------------------------------------------------------------------------
  1071. // Read the list of disabled startup items which would be restored to the
  1072. // registry. This list is just stored in a different registry location.
  1073. //-----------------------------------------------------------------------------
  1074. BOOL CRestoreStartup::LoadDisabledRegistry()
  1075. {
  1076. HKEY ahkeyBases[] = { HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER, NULL };
  1077. for (int i = 0; ahkeyBases[i] != NULL; i++)
  1078. {
  1079. // Open the key containing the disabled items. We open it KEY_WRITE | KEY_READ,
  1080. // even though we are just going to read in this function. This is because
  1081. // if opening for this access fails, we don't want to list the items because
  1082. // the user won't be able to restore the items.
  1083. CRegKey regkey;
  1084. if (ERROR_SUCCESS != regkey.Open(ahkeyBases[i], DISABLED_KEY, KEY_WRITE | KEY_READ))
  1085. return FALSE;
  1086. // Get the number of keys under the key and look at each one.
  1087. DWORD dwValueCount, dwSize;
  1088. if (ERROR_SUCCESS == ::RegQueryInfoKey((HKEY)regkey, NULL, NULL, NULL, NULL, NULL, NULL, &dwValueCount, NULL, NULL, NULL, NULL))
  1089. {
  1090. TCHAR szValueName[MAX_PATH], szValue[MAX_PATH];
  1091. for (DWORD dwKey = 0; dwKey < dwValueCount; dwKey++)
  1092. {
  1093. dwSize = MAX_PATH;
  1094. if (ERROR_SUCCESS != ::RegEnumValue((HKEY)regkey, dwKey, szValueName, &dwSize, NULL, NULL, NULL, NULL))
  1095. continue;
  1096. dwSize = MAX_PATH;
  1097. if (ERROR_SUCCESS != regkey.QueryValue(szValue, szValueName, &dwSize))
  1098. continue;
  1099. // Create the startup item and insert it in the list.
  1100. CStartupDisabledRegistry * pItem = new CStartupDisabledRegistry(szValueName, szValue, ENABLED_KEY, ahkeyBases[i]);
  1101. InsertDisabledStartupItem(pItem);
  1102. }
  1103. }
  1104. regkey.Close();
  1105. }
  1106. return TRUE;
  1107. }
  1108. //-----------------------------------------------------------------------------
  1109. // Add the items from the disabled startup group to the list:
  1110. //
  1111. // GIVEN the path to CSIDL_STARTUP, setup moves disabled items to
  1112. // ..\Disabled Startup and makes it hidden; it potentially contains
  1113. // the complete content of the original startup folder, which
  1114. // can be anything.
  1115. //
  1116. // Note - we'll also need to look under CSIDL_COMMON_STARTUP.
  1117. //-----------------------------------------------------------------------------
  1118. BOOL CRestoreStartup::LoadDisabledStartupGroup()
  1119. {
  1120. int anFolders[] = { CSIDL_STARTUP, CSIDL_COMMON_STARTUP, 0 };
  1121. TCHAR szPath[MAX_PATH * 2];
  1122. for (int i = 0; anFolders[i] != 0; i++)
  1123. {
  1124. if (FAILED(::SHGetSpecialFolderPath(NULL, szPath, anFolders[i], FALSE)))
  1125. continue;
  1126. // We need to trim off the last part of the path and replace it with
  1127. // "Disabled Startup".
  1128. CString strPath(szPath);
  1129. int iLastSlash = strPath.ReverseFind(_T('\\'));
  1130. if (iLastSlash == -1)
  1131. continue;
  1132. strPath = strPath.Left(iLastSlash) + CString(DISABLED_STARTUP);
  1133. // Now look for files in the folder.
  1134. CString strSearch(strPath);
  1135. strSearch += CString(_T("\\*.*"));
  1136. WIN32_FIND_DATA fd;
  1137. HANDLE hFind = FindFirstFile(strSearch, &fd);
  1138. if (hFind != INVALID_HANDLE_VALUE)
  1139. {
  1140. do
  1141. {
  1142. // We want to ignore the desktop.ini file which might appear in startup.
  1143. if ((fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) == 0 || _tcsicmp(fd.cFileName, _T("desktop.ini")) != 0)
  1144. {
  1145. // We only want to examine files which aren't directories.
  1146. if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
  1147. {
  1148. CStartupDisabledStartup * pItem = new CStartupDisabledStartup(fd.cFileName, szPath, strPath);
  1149. InsertDisabledStartupItem(pItem);
  1150. }
  1151. }
  1152. } while (FindNextFile(hFind, &fd));
  1153. FindClose(hFind);
  1154. }
  1155. }
  1156. return TRUE;
  1157. }
  1158. //-----------------------------------------------------------------------------
  1159. // Insert the disabled item into the list view.
  1160. //-----------------------------------------------------------------------------
  1161. void CRestoreStartup::InsertDisabledStartupItem(CStartupDisabled * pItem)
  1162. {
  1163. if (pItem == NULL)
  1164. return;
  1165. CString strItem, strLocation;
  1166. pItem->GetColumnCaptions(strItem, strLocation);
  1167. // Insert the item in the list view.
  1168. LV_ITEM lvi;
  1169. memset(&lvi, 0, sizeof(lvi));
  1170. lvi.mask = LVIF_TEXT | LVIF_PARAM;
  1171. lvi.iItem = m_iNextPosition;
  1172. lvi.pszText = (LPTSTR)(LPCTSTR)strLocation;
  1173. lvi.iSubItem = 0;
  1174. lvi.lParam = (LPARAM)pItem;
  1175. m_iNextPosition = ListView_InsertItem(m_list.m_hWnd, &lvi);
  1176. ListView_SetItemText(m_list.m_hWnd, m_iNextPosition, 1, (LPTSTR)(LPCTSTR)strItem);
  1177. ListView_SetCheckState(m_list.m_hWnd, m_iNextPosition, TRUE);
  1178. m_iNextPosition++;
  1179. }
  1180. //-----------------------------------------------------------------------------
  1181. // Remove all the items from the list view (freeing the objects pointed to
  1182. // by the LPARAM).
  1183. //-----------------------------------------------------------------------------
  1184. void CRestoreStartup::EmptyList()
  1185. {
  1186. LVITEM lvi;
  1187. lvi.mask = LVIF_PARAM;
  1188. lvi.iSubItem = 0;
  1189. for (int i = ListView_GetItemCount(m_list.m_hWnd) - 1; i >= 0; i--)
  1190. {
  1191. lvi.iItem = i;
  1192. if (ListView_GetItem(m_list.m_hWnd, &lvi))
  1193. {
  1194. CStartupDisabled * pItem = (CStartupDisabled *)lvi.lParam;
  1195. if (pItem)
  1196. delete pItem;
  1197. }
  1198. }
  1199. ListView_DeleteAllItems(m_list.m_hWnd);
  1200. }
  1201. //-----------------------------------------------------------------------------
  1202. // When the dialog is being destroyed, be sure to free the memory of the
  1203. // object pointers maintained in the list view.
  1204. //-----------------------------------------------------------------------------
  1205. void CRestoreStartup::OnDestroy()
  1206. {
  1207. EmptyList();
  1208. CDialog::OnDestroy();
  1209. }
  1210. //-----------------------------------------------------------------------------
  1211. // If the user clicks on OK, then we should make sure he or she really wants
  1212. // to perform this operation. If so, then look though the list, calling the
  1213. // Restore function for each object with the checkbox checked.
  1214. //-----------------------------------------------------------------------------
  1215. void CRestoreStartup::OnOK()
  1216. {
  1217. CString strText, strCaption;
  1218. strCaption.LoadString(IDS_DIALOGCAPTION);
  1219. strText.LoadString(IDS_VERIFYRESTORE);
  1220. if (IDYES == ::MessageBox(m_hWnd, strText, strCaption, MB_YESNO))
  1221. {
  1222. LVITEM lvi;
  1223. lvi.mask = LVIF_PARAM;
  1224. lvi.iSubItem = 0;
  1225. for (int i = ListView_GetItemCount(m_list.m_hWnd) - 1; i >= 0; i--)
  1226. if (ListView_GetCheckState(m_list.m_hWnd, i))
  1227. {
  1228. lvi.iItem = i;
  1229. if (ListView_GetItem(m_list.m_hWnd, &lvi))
  1230. {
  1231. CStartupDisabled * pItem = (CStartupDisabled *)lvi.lParam;
  1232. if (pItem != NULL)
  1233. pItem->Restore();
  1234. }
  1235. }
  1236. }
  1237. CDialog::OnOK();
  1238. }
  1239. //-----------------------------------------------------------------------------
  1240. // Enable or disable the OK button based on the state of the check boxes.
  1241. //-----------------------------------------------------------------------------
  1242. void CRestoreStartup::SetOKState()
  1243. {
  1244. CWnd * pWnd = GetDlgItem(IDOK);
  1245. if (pWnd == NULL)
  1246. return;
  1247. BOOL fEnable = FALSE;
  1248. for (int i = ListView_GetItemCount(m_list.m_hWnd) - 1; i >= 0; i--)
  1249. if (ListView_GetCheckState(m_list.m_hWnd, i))
  1250. {
  1251. fEnable = TRUE;
  1252. break;
  1253. }
  1254. if (::IsWindowEnabled(pWnd->m_hWnd) != fEnable)
  1255. ::EnableWindow(pWnd->m_hWnd, fEnable);
  1256. }
  1257. //-----------------------------------------------------------------------------
  1258. // If the user changed something in the list, update the OK button state.
  1259. //-----------------------------------------------------------------------------
  1260. void CRestoreStartup::OnItemChangedRestoreList(NMHDR* pNMHDR, LRESULT* pResult)
  1261. {
  1262. NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
  1263. SetOKState();
  1264. *pResult = 0;
  1265. }
  1266. //-----------------------------------------------------------------------------
  1267. // This static function will be called by the startup tab to determine if the
  1268. // button to launch this dialog box should be enabled.
  1269. //-----------------------------------------------------------------------------
  1270. BOOL CRestoreStartup::AreItemsToRestore()
  1271. {
  1272. // Look in the registry for disabled items.
  1273. HKEY ahkeyBases[] = { HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER, NULL };
  1274. for (int j = 0; ahkeyBases[j] != NULL; j++)
  1275. {
  1276. CRegKey regkey;
  1277. if (ERROR_SUCCESS == regkey.Open(ahkeyBases[j], DISABLED_KEY, KEY_READ))
  1278. {
  1279. DWORD dwValueCount;
  1280. if (ERROR_SUCCESS == ::RegQueryInfoKey((HKEY)regkey, NULL, NULL, NULL, NULL, NULL, NULL, &dwValueCount, NULL, NULL, NULL, NULL))
  1281. if (dwValueCount > 0)
  1282. {
  1283. regkey.Close();
  1284. return TRUE;
  1285. }
  1286. regkey.Close();
  1287. }
  1288. }
  1289. // Look in the disabled startup items folders.
  1290. int anFolders[] = { CSIDL_STARTUP, CSIDL_COMMON_STARTUP, 0 };
  1291. TCHAR szPath[MAX_PATH * 2];
  1292. BOOL fDisabledItem = FALSE;
  1293. for (int i = 0; !fDisabledItem && anFolders[i] != 0; i++)
  1294. {
  1295. if (FAILED(::SHGetSpecialFolderPath(NULL, szPath, anFolders[i], FALSE)))
  1296. continue;
  1297. // We need to trim off the last part of the path and replace it with
  1298. // "Disabled Startup".
  1299. CString strPath(szPath);
  1300. int iLastSlash = strPath.ReverseFind(_T('\\'));
  1301. if (iLastSlash == -1)
  1302. continue;
  1303. strPath = strPath.Left(iLastSlash) + CString(DISABLED_STARTUP);
  1304. // Now look for files in the folder.
  1305. CString strSearch(strPath);
  1306. strSearch += CString(_T("\\*.*"));
  1307. WIN32_FIND_DATA fd;
  1308. HANDLE hFind = FindFirstFile(strSearch, &fd);
  1309. if (hFind != INVALID_HANDLE_VALUE)
  1310. {
  1311. do
  1312. {
  1313. // We want to ignore the desktop.ini file which might appear in startup.
  1314. if ((fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) == 0 || _tcsicmp(fd.cFileName, _T("desktop.ini")) != 0)
  1315. {
  1316. // We only want to examine files which aren't directories.
  1317. if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
  1318. {
  1319. fDisabledItem = TRUE;
  1320. break;
  1321. }
  1322. }
  1323. } while (FindNextFile(hFind, &fd));
  1324. FindClose(hFind);
  1325. }
  1326. }
  1327. return fDisabledItem;
  1328. }