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.

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