|
|
#include "stdafx.h"
#include "PageStartup.h"
#include "MSConfigState.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__; #endif
/////////////////////////////////////////////////////////////////////////////
// CPageStartup property page
IMPLEMENT_DYNCREATE(CPageStartup, CPropertyPage)
CPageStartup::CPageStartup() : CPropertyPage(CPageStartup::IDD) { //{{AFX_DATA_INIT(CPageStartup)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
m_fModified = FALSE; }
CPageStartup::~CPageStartup() { }
void CPageStartup::DoDataExchange(CDataExchange* pDX) { CPropertyPage::DoDataExchange(pDX); //{{AFX_DATA_MAP(CPageStartup)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CPageStartup, CPropertyPage) //{{AFX_MSG_MAP(CPageStartup)
ON_WM_DESTROY() ON_NOTIFY(LVN_ITEMCHANGED, IDC_LISTSTARTUP, OnItemChangedList) ON_BN_CLICKED(IDC_BUTTONSUDISABLEALL, OnButtonDisableAll) ON_BN_CLICKED(IDC_BUTTONSUENABLEALL, OnButtonEnableAll) ON_NOTIFY(NM_SETFOCUS, IDC_LISTSTARTUP, OnSetFocusList) ON_BN_CLICKED(IDC_BUTTONSURESTORE, OnButtonRestore) //}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CPageStartup message handlers
//-----------------------------------------------------------------------------
// Load the list of startup items.
//-----------------------------------------------------------------------------
void CPageStartup::LoadStartupList() { m_fIgnoreListChanges = TRUE; EmptyList(FALSE); m_iNextPosition = 0;
LoadStartupListLiveItems(); LoadStartupListDisabledItems(); m_fIgnoreListChanges = FALSE; }
//-----------------------------------------------------------------------------
// Load the list of items which are actually being started on this system.
//-----------------------------------------------------------------------------
void CPageStartup::LoadStartupListLiveItems() { LoadStartupListLiveItemsRunKey(); LoadStartupListLiveItemsStartup(); LoadStartupListLiveItemsWinIniKey(); }
//-----------------------------------------------------------------------------
// Look under the Run registry key for startup items.
//-----------------------------------------------------------------------------
void CPageStartup::LoadStartupListLiveItemsRunKey() { LPCTSTR szRunKey = _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"); HKEY ahkey[] = { HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER, NULL }; TCHAR szValueName[MAX_PATH], szValue[MAX_PATH]; DWORD dwSize; CRegKey regkey;
for (int i = 0; ahkey[i] != NULL; i++) { // Try to open the Run registry key.
if (ERROR_SUCCESS != regkey.Open(ahkey[i], szRunKey, KEY_READ)) continue;
// Get the number of keys under the Run key and look at each one.
DWORD dwValueCount; if (ERROR_SUCCESS != ::RegQueryInfoKey((HKEY)regkey, NULL, NULL, NULL, NULL, NULL, NULL, &dwValueCount, NULL, NULL, NULL, NULL)) { regkey.Close(); continue; }
for (DWORD dwKey = 0; dwKey < dwValueCount; dwKey++) { dwSize = MAX_PATH; if (ERROR_SUCCESS != ::RegEnumValue((HKEY)regkey, dwKey, szValueName, &dwSize, NULL, NULL, NULL, NULL)) continue;
dwSize = MAX_PATH; if (ERROR_SUCCESS != regkey.QueryValue(szValue, szValueName, &dwSize)) continue;
// We don't want to show MSConfig in the startup item list.
CString strTemp(szValue); strTemp.MakeLower(); if (strTemp.Find(_T("msconfig.exe")) != -1) continue;
// TBD - verify that the file exists?
// To get the name of this startup item, we'll take the command and
// strip off everything but the filename (without the extension).
CString strName(szValue); GetCommandName(strName);
// Create the startup item and insert it in the list.
CStartupItemRegistry * pItem = new CStartupItemRegistry(ahkey[i], szRunKey, strName, szValueName, szValue); InsertStartupItem(pItem); }
regkey.Close(); } }
//-----------------------------------------------------------------------------
// Look under the registry for the mapped win.ini file and check out its run
// and load items.
//-----------------------------------------------------------------------------
void CPageStartup::LoadStartupListLiveItemsWinIniKey() { LPCTSTR aszValueNames[] = { _T("Run"), _T("Load"), NULL }; CRegKey regkey; TCHAR szValue[MAX_PATH * 4]; DWORD dwSize; LPCTSTR szKeyName = _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows"); HKEY hkey = HKEY_CURRENT_USER;
if (ERROR_SUCCESS != regkey.Open(hkey, szKeyName, KEY_READ)) return;
for (int i = 0; aszValueNames[i] != NULL; i++) { dwSize = MAX_PATH * 4; if (ERROR_SUCCESS != regkey.QueryValue(szValue, aszValueNames[i], &dwSize)) continue;
// The string we get back is a comma delimited list of programs. We need
// to parse them into individual programs.
CString strLine(szValue); while (!strLine.IsEmpty()) { CString strItem = strLine.SpanExcluding(_T(",")); if (!strItem.IsEmpty()) { // Create the startup item and insert it in the list.
CString strCommandName(strItem); GetCommandName(strCommandName);
CStartupItemRegistry * pItem = new CStartupItemRegistry(szKeyName, strCommandName, aszValueNames[i], strItem); InsertStartupItem(pItem);
// Trim the item of the line.
strLine = strLine.Mid(strItem.GetLength()); } strLine.TrimLeft(_T(" ,")); } }
regkey.Close(); }
//-----------------------------------------------------------------------------
// Look in the startup folder for items.
//-----------------------------------------------------------------------------
void CPageStartup::LoadStartupListLiveItemsStartup() { LPCTSTR szRunKey = _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"); HKEY ahkey[] = { HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER, NULL }; LPCTSTR aszRunValue[] = { _T("Common Startup"), _T("Startup"), NULL }; CRegKey regkey; TCHAR szStartupFolderDir[MAX_PATH]; TCHAR szStartupFileSpec[_MAX_PATH]; DWORD dwSize;
for (int i = 0; ahkey[i] != NULL; i++) { // Try to open the registry key.
if (ERROR_SUCCESS != regkey.Open(ahkey[i], szRunKey, KEY_READ)) continue;
// Get the path for the startup item folder.
dwSize = MAX_PATH; if (aszRunValue[i] == NULL || ERROR_SUCCESS != regkey.QueryValue(szStartupFolderDir, aszRunValue[i], &dwSize)) { regkey.Close(); continue; } regkey.Close();
// Append the filespec on the end of the directory.
_tmakepath(szStartupFileSpec, NULL, szStartupFolderDir, _T("*.*"), NULL);
// Examine all of the files in the directory.
WIN32_FIND_DATA fd; HANDLE hFind = FindFirstFile(szStartupFileSpec, &fd); if (hFind != INVALID_HANDLE_VALUE) { do { // We want to ignore the desktop.ini file which might appear in startup.
if ((fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) == 0 || _tcsicmp(fd.cFileName, _T("desktop.ini")) != 0) { // We only want to examine files which aren't directories.
if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { CStartupItemFolder * pItem = new CStartupItemFolder; if (pItem) { if (pItem->Create(fd, ahkey[i], szRunKey, aszRunValue[i], szStartupFolderDir)) this->InsertStartupItem(pItem); else delete pItem; } } } } while (FindNextFile(hFind, &fd));
FindClose(hFind); } } }
//-----------------------------------------------------------------------------
// Load the list of items which were being started on this system, but which
// we've disabled. This list is maintained in the registry.
//-----------------------------------------------------------------------------
void CPageStartup::LoadStartupListDisabledItems() { CRegKey regkey; regkey.Attach(GetRegKey(_T("startupreg"))); if ((HKEY)regkey != NULL) { DWORD dwKeyCount, dwSize; TCHAR szKeyName[MAX_PATH];
if (ERROR_SUCCESS == ::RegQueryInfoKey((HKEY)regkey, NULL, NULL, NULL, &dwKeyCount, NULL, NULL, NULL, NULL, NULL, NULL, NULL)) { for (DWORD dwKey = 0; dwKey < dwKeyCount; dwKey++) { dwSize = MAX_PATH; if (ERROR_SUCCESS != ::RegEnumKeyEx((HKEY)regkey, dwKey, szKeyName, &dwSize, NULL, NULL, NULL, NULL)) continue;
CRegKey regkeyItem; if (ERROR_SUCCESS == regkeyItem.Open((HKEY)regkey, szKeyName, KEY_READ)) { CStartupItemRegistry * pItem = new CStartupItemRegistry; if (pItem->Create(szKeyName, (HKEY)regkeyItem)) InsertStartupItem(pItem); else delete pItem; regkeyItem.Close(); } } }
regkey.Close(); }
regkey.Attach(GetRegKey(_T("startupfolder"))); if ((HKEY)regkey != NULL) { DWORD dwKeyCount, dwSize; TCHAR szKeyName[MAX_PATH];
if (ERROR_SUCCESS == ::RegQueryInfoKey((HKEY)regkey, NULL, NULL, NULL, &dwKeyCount, NULL, NULL, NULL, NULL, NULL, NULL, NULL)) { for (DWORD dwKey = 0; dwKey < dwKeyCount; dwKey++) { dwSize = MAX_PATH; if (ERROR_SUCCESS != ::RegEnumKeyEx((HKEY)regkey, dwKey, szKeyName, &dwSize, NULL, NULL, NULL, NULL)) continue;
CRegKey regkeyItem; if (ERROR_SUCCESS == regkeyItem.Open((HKEY)regkey, szKeyName, KEY_READ)) { CStartupItemFolder * pItem = new CStartupItemFolder; if (pItem->Create(szKeyName, (HKEY)regkeyItem)) InsertStartupItem(pItem); else delete pItem; regkeyItem.Close(); } } }
regkey.Close(); } }
//-----------------------------------------------------------------------------
// Take a command line and strip off everything except the command name.
//-----------------------------------------------------------------------------
void CPageStartup::GetCommandName(CString & strCommand) { // Strip off the path information.
int iLastBackslash = strCommand.ReverseFind(_T('\\')); if (iLastBackslash != -1) strCommand = strCommand.Mid(iLastBackslash + 1);
// Strip off the extension and any flags.
int iDot = strCommand.Find(_T('.')); if (iDot != -1) { if (iDot != 0) strCommand = strCommand.Left(iDot); else strCommand.Empty(); } }
//-----------------------------------------------------------------------------
// Insert the specified item in the startup list. The caller is then not
// responsible for deleting the item.
//-----------------------------------------------------------------------------
void CPageStartup::InsertStartupItem(CStartupItem * pItem) { ASSERT(pItem); if (pItem == NULL) return;
// Get the strings to add to the list view.
CString strItem, strLocation, strCommand; pItem->GetDisplayInfo(strItem, strLocation, strCommand);
// Insert the item in the list view.
LV_ITEM lvi; memset(&lvi, 0, sizeof(lvi)); lvi.mask = LVIF_TEXT | LVIF_PARAM; lvi.iItem = m_iNextPosition;
lvi.pszText = (LPTSTR)(LPCTSTR)strItem; lvi.iSubItem = 0; lvi.lParam = (LPARAM)pItem;
m_iNextPosition = ListView_InsertItem(m_list.m_hWnd, &lvi); ListView_SetItemText(m_list.m_hWnd, m_iNextPosition, 1, (LPTSTR)(LPCTSTR)strCommand); ListView_SetItemText(m_list.m_hWnd, m_iNextPosition, 2, (LPTSTR)(LPCTSTR)strLocation); ListView_SetCheckState(m_list.m_hWnd, m_iNextPosition, pItem->IsLive());
m_iNextPosition++; }
//-----------------------------------------------------------------------------
// Remove all the items from the list view (freeing the objects pointed to
// by the LPARAM).
//-----------------------------------------------------------------------------
void CPageStartup::EmptyList(BOOL fFreeMemoryOnly) { LVITEM lvi; lvi.mask = LVIF_PARAM; lvi.iSubItem = 0;
for (int i = ListView_GetItemCount(m_list.m_hWnd) - 1; i >= 0; i--) { lvi.iItem = i;
if (ListView_GetItem(m_list.m_hWnd, &lvi)) { CStartupItem * pItem = (CStartupItem *)lvi.lParam; if (pItem) delete pItem;
// If we're leaving the list with these items, we better
// not do a double delete.
if (fFreeMemoryOnly) { lvi.lParam = 0; ListView_SetItem(m_list.m_hWnd, &lvi); } } }
if (!fFreeMemoryOnly) ListView_DeleteAllItems(m_list.m_hWnd); }
//-----------------------------------------------------------------------------
// Set the state of all of the items in the list.
//-----------------------------------------------------------------------------
void CPageStartup::SetEnableForList(BOOL fEnable) { HWND hwndFocus = ::GetFocus();
LVITEM lvi; lvi.mask = LVIF_PARAM; lvi.iSubItem = 0;
for (int i = ListView_GetItemCount(m_list.m_hWnd) - 1; i >= 0; i--) ListView_SetCheckState(m_list.m_hWnd, i, fEnable);
::EnableWindow(GetDlgItemHWND(IDC_BUTTONSUDISABLEALL), fEnable); if (!fEnable && hwndFocus == GetDlgItemHWND(IDC_BUTTONSUDISABLEALL)) PrevDlgCtrl();
::EnableWindow(GetDlgItemHWND(IDC_BUTTONSUENABLEALL), !fEnable); if (fEnable && hwndFocus == GetDlgItemHWND(IDC_BUTTONSUENABLEALL)) NextDlgCtrl(); }
//============================================================================
// The CStartupItemRegistry class is used to encapsulate an individual startup
// stored in the registry.
//============================================================================
//----------------------------------------------------------------------------
// Construct this flavor of startup item.
//----------------------------------------------------------------------------
CStartupItemRegistry::CStartupItemRegistry() { m_hkey = NULL; m_fIniMapping = FALSE; }
CStartupItemRegistry::CStartupItemRegistry(HKEY hkey, LPCTSTR szKey, LPCTSTR szName, LPCTSTR szValueName, LPCTSTR szValue) { m_fIniMapping = FALSE; m_fLive = TRUE;
m_strItem = szName; m_strLocation = szKey; m_strCommand = szValue;
// Add the HKEY to the location.
if (hkey == HKEY_LOCAL_MACHINE) m_strLocation = CString(_T("HKLM\\")) + m_strLocation; else if (hkey == HKEY_CURRENT_USER) m_strLocation = CString(_T("HKCU\\")) + m_strLocation; m_hkey = hkey; m_strKey = szKey; m_strValueName = szValueName; }
//----------------------------------------------------------------------------
// This constructor is specifically for items under the INI file registry
// mapping.
//----------------------------------------------------------------------------
CStartupItemRegistry::CStartupItemRegistry(LPCTSTR szKey, LPCTSTR szName, LPCTSTR szValueName, LPCTSTR szValue) { m_fIniMapping = TRUE; m_fLive = TRUE;
m_strItem = szName; m_strLocation = szKey; m_strCommand = szValue; m_strLocation = CString(_T("HKCU\\")) + m_strLocation + CString(_T(":")) + szValueName; m_hkey = HKEY_CURRENT_USER; m_strKey = szKey; m_strValueName = szValueName; }
//----------------------------------------------------------------------------
// Enable or disable the startup item in the registry.
//----------------------------------------------------------------------------
BOOL CStartupItemRegistry::SetEnable(BOOL fEnable) { if (fEnable == IsLive()) return FALSE;
CRegKey regkey; if (ERROR_SUCCESS != regkey.Open(m_hkey, m_strKey, KEY_ALL_ACCESS)) return FALSE;
LONG lReturnCode = ERROR_SUCCESS + 1; // need to initialize it to not ERROR_SUCCESS
if (m_fIniMapping == FALSE) { // Create or delete the registry key from the data stored in
// this object.
if (fEnable) lReturnCode = regkey.SetValue(m_strCommand, m_strValueName); else lReturnCode = regkey.DeleteValue(m_strValueName); } else { // This item is an INI file mapping item (which means there
// might be more than one item on this line).
TCHAR szValue[MAX_PATH * 4]; DWORD dwSize = MAX_PATH * 4; if (ERROR_SUCCESS == regkey.QueryValue(szValue, m_strValueName, &dwSize)) { CString strValue(szValue);
if (fEnable) { if (!strValue.IsEmpty()) strValue += CString(_T(", ")); strValue += m_strCommand; } else { // The harder case - we need to remove the item, and possibly commas.
int iCommand = strValue.Find(m_strCommand); if (iCommand != -1) { CString strNewValue;
if (iCommand > 0) { strNewValue = strValue.Left(iCommand); strNewValue.TrimRight(_T(", ")); }
if (strValue.GetLength() > (m_strCommand.GetLength() + iCommand)) { if (!strNewValue.IsEmpty()) strNewValue += CString(_T(", "));
CString strRemainder(strValue.Mid(iCommand + m_strCommand.GetLength())); strRemainder.TrimLeft(_T(", ")); strNewValue += strRemainder; }
strValue = strNewValue; } }
lReturnCode = regkey.SetValue(strValue, m_strValueName); } }
regkey.Close();
if (lReturnCode != ERROR_SUCCESS) return FALSE;
// Delete or create the registry representation of this item.
// This representation persists the startup item when it has
// been deleted.
regkey.Attach(GetRegKey(_T("startupreg"))); if ((HKEY)regkey != NULL) { if (fEnable) regkey.DeleteSubKey(m_strValueName); else { regkey.SetKeyValue(m_strValueName, m_strKey, _T("key")); regkey.SetKeyValue(m_strValueName, m_strItem, _T("item")); if (m_hkey == HKEY_LOCAL_MACHINE) regkey.SetKeyValue(m_strValueName, _T("HKLM"), _T("hkey")); else regkey.SetKeyValue(m_strValueName, _T("HKCU"), _T("hkey")); regkey.SetKeyValue(m_strValueName, m_strCommand, _T("command")); regkey.SetKeyValue(m_strValueName, m_fIniMapping ? _T("1") : _T("0"), _T("inimapping")); } regkey.Close(); }
m_fLive = fEnable; return TRUE; }
//----------------------------------------------------------------------------
// Create the startup item from the registry representation of the item.
//----------------------------------------------------------------------------
BOOL CStartupItemRegistry::Create(LPCTSTR szKeyName, HKEY hkey) { if (hkey == NULL) return FALSE;
CRegKey regkey; regkey.Attach(hkey); if ((HKEY)regkey == NULL) return FALSE;
// Restore all of the values from the registry.
TCHAR szValue[MAX_PATH]; DWORD dwSize;
dwSize = MAX_PATH; if (ERROR_SUCCESS != regkey.QueryValue(szValue, _T("key"), &dwSize)) { regkey.Detach(); return FALSE; } m_strKey = szValue;
dwSize = MAX_PATH; if (ERROR_SUCCESS != regkey.QueryValue(szValue, _T("command"), &dwSize)) { regkey.Detach(); return FALSE; } m_strCommand = szValue;
dwSize = MAX_PATH; if (ERROR_SUCCESS != regkey.QueryValue(szValue, _T("item"), &dwSize)) { regkey.Detach(); return FALSE; } m_strItem = szValue;
dwSize = MAX_PATH; if (ERROR_SUCCESS != regkey.QueryValue(szValue, _T("hkey"), &dwSize)) { regkey.Detach(); return FALSE; } if (_tcscmp(szValue, _T("HKLM")) == 0) m_hkey = HKEY_LOCAL_MACHINE; else m_hkey = HKEY_CURRENT_USER;
dwSize = MAX_PATH; if (ERROR_SUCCESS != regkey.QueryValue(szValue, _T("inimapping"), &dwSize)) { regkey.Detach(); return FALSE; } if (_tcscmp(szValue, _T("0")) == 0) m_fIniMapping = FALSE; else m_fIniMapping = TRUE;
regkey.Detach();
m_strLocation = m_strKey; m_strValueName = szKeyName; m_fLive = FALSE; return TRUE; }
//----------------------------------------------------------------------------
// Remove all the entries persisted in the registry.
//----------------------------------------------------------------------------
void CStartupItemRegistry::RemovePersistedEntries() { CRegKey regkey; regkey.Attach(GetRegKey()); if ((HKEY)regkey != NULL) regkey.RecurseDeleteKey(_T("startupreg")); }
//============================================================================
// The CStartupItemFolder class is used to encapsulate an individual startup
// stored in the startup folder.
//============================================================================
CStartupItemFolder::CStartupItemFolder() { }
//----------------------------------------------------------------------------
// Enable or disable this startup item. Since the item is an actual file in
// a folder, disabling it will mean copying that file to a backup folder and
// creating a registry entry for it. Enabling will mean copying the file
// back to the appropriate startup folder and deleting the registry entry.
//----------------------------------------------------------------------------
BOOL CStartupItemFolder::SetEnable(BOOL fEnable) { if (fEnable == IsLive()) return FALSE;
// Copy the file (from or to the backup directory).
if (fEnable) { m_strBackupPath = GetBackupName(m_strFilePath, m_strLocation); ::CopyFile(m_strBackupPath, m_strFilePath, FALSE); } else { BackupFile(m_strFilePath, m_strLocation, TRUE); m_strBackupPath = GetBackupName(m_strFilePath, m_strLocation); }
// Update the registry for the new state. If we are making the file
// disabled, then we need to save both the original path and the
// backed up path (and the standard startup item stuff). Otherwise
// just delete the key.
CRegKey regkey; regkey.Attach(GetRegKey(_T("startupfolder"))); if ((HKEY)regkey == NULL) return FALSE; // The name for the registry key just needs to be unique. And not
// have any backslashes in it.
CString strRegkey(m_strFilePath); strRegkey.Replace(_T("\\"), _T("^"));
if (fEnable) { regkey.DeleteSubKey(strRegkey); ::DeleteFile(m_strBackupPath); } else { regkey.SetKeyValue(strRegkey, m_strFilePath, _T("path")); regkey.SetKeyValue(strRegkey, m_strBackupPath, _T("backup")); regkey.SetKeyValue(strRegkey, m_strLocation, _T("location")); regkey.SetKeyValue(strRegkey, m_strCommand, _T("command")); regkey.SetKeyValue(strRegkey, m_strItem, _T("item")); ::DeleteFile(m_strFilePath); }
m_fLive = fEnable; return TRUE; }
//----------------------------------------------------------------------------
// Load the disabled startup item from the registry.
//----------------------------------------------------------------------------
BOOL CStartupItemFolder::Create(LPCTSTR szKeyName, HKEY hkey) { if (hkey == NULL) return FALSE;
CRegKey regkey; regkey.Attach(hkey); if ((HKEY)regkey == NULL) return FALSE;
// Restore all of the values from the registry.
TCHAR szValue[MAX_PATH]; DWORD dwSize;
dwSize = MAX_PATH; if (ERROR_SUCCESS != regkey.QueryValue(szValue, _T("path"), &dwSize)) { regkey.Detach(); return FALSE; } m_strFilePath = szValue;
dwSize = MAX_PATH; if (ERROR_SUCCESS != regkey.QueryValue(szValue, _T("backup"), &dwSize)) { regkey.Detach(); return FALSE; } m_strBackupPath = szValue;
dwSize = MAX_PATH; if (ERROR_SUCCESS != regkey.QueryValue(szValue, _T("location"), &dwSize)) { regkey.Detach(); return FALSE; } m_strLocation = szValue;
dwSize = MAX_PATH; if (ERROR_SUCCESS != regkey.QueryValue(szValue, _T("command"), &dwSize)) { regkey.Detach(); return FALSE; } m_strCommand = szValue;
dwSize = MAX_PATH; if (ERROR_SUCCESS != regkey.QueryValue(szValue, _T("item"), &dwSize)) { regkey.Detach(); return FALSE; } m_strItem = szValue;
regkey.Detach(); m_fLive = FALSE; return TRUE; }
//----------------------------------------------------------------------------
// Create the startup item from the file found in the folder. If the file
// is a shortcut, get the information about the target.
//----------------------------------------------------------------------------
BOOL CStartupItemFolder::Create(const WIN32_FIND_DATA & fd, HKEY hkey, LPCTSTR szRegPathToFolder, LPCTSTR szFolder, LPCTSTR szDir) { // We want to save the path to the file in the startup folder (even if
// it is a shortcut).
m_strFilePath = szDir; if (m_strFilePath.Right(1) != CString(_T("\\"))) m_strFilePath += CString(_T("\\")); m_strFilePath += fd.cFileName;
// Look at the file to determine how to handle it.
CString strFile(fd.cFileName); strFile.MakeLower();
if (strFile.Right(4) == CString(_T(".lnk"))) { // The file is a shortcut to a different command. Show that command.
CIconInfo info; _tcsncpy(info.szPath, m_strFilePath, sizeof(info.szPath) / sizeof(TCHAR));
if (SUCCEEDED(GetIconInfo(info))) { m_fLive = TRUE; m_strItem = fd.cFileName; m_strLocation = szFolder;
m_strCommand.Format(_T("%s %s"), info.szTarget, info.szArgs); int iDot = m_strItem.ReverseFind(_T('.')); if (iDot > 0) m_strItem = m_strItem.Left(iDot);
return TRUE; } } else { // A file besides a shortcut. It may be an EXE, or some other file type
// (we'll handle them the same).
m_fLive = TRUE; m_strItem = fd.cFileName; m_strLocation = szFolder; m_strCommand = m_strFilePath;
int iDot = m_strItem.ReverseFind(_T('.')); if (iDot > 0) m_strItem = m_strItem.Left(iDot);
return TRUE; }
return FALSE; }
//----------------------------------------------------------------------------
// Get the information about a shortcut. Creates a thread to do so, since it
// needs to be done in an apartment model thread.
//
// JJ's code, cleaned up a bit.
//----------------------------------------------------------------------------
DWORD GetIconInfoProc(CStartupItemFolder::CIconInfo * pInfo); HRESULT CStartupItemFolder::GetIconInfo(CIconInfo & info) { DWORD dwID; HANDLE hThread;
if (hThread = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)GetIconInfoProc, &info, 0, &dwID)) { info.hResult = S_OK; ::WaitForSingleObject(hThread, INFINITE); } else info.hResult = E_FAIL;
return info.hResult; }
//----------------------------------------------------------------------------
// Remove all the entries persisted in the registry.
//----------------------------------------------------------------------------
void CStartupItemFolder::RemovePersistedEntries() { CRegKey regkey; regkey.Attach(GetRegKey()); if ((HKEY)regkey != NULL) regkey.RecurseDeleteKey(_T("startupfolder")); }
//----------------------------------------------------------------------------
// Procedure (run in its own thread) to get information about a shortcut.
//
// JJ's code, cleaned up a bit.
//----------------------------------------------------------------------------
DWORD GetIconInfoProc(CStartupItemFolder::CIconInfo * pInfo) { HRESULT hResult; IShellLink * psl = NULL; IPersistFile * ppf = NULL;
try { // We have to use COINIT_APARTMENTTHREADED.
if (SUCCEEDED(hResult = CoInitialize(NULL))) { // Get a pointer to the IShellLink interface.
if (SUCCEEDED(hResult = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (VOID **) &psl))) { // Get a pointer to the IPersistFile interface.
if (SUCCEEDED(hResult = psl->QueryInterface(IID_IPersistFile, (VOID **) &ppf))) { BSTR bstrPath; #ifdef UNICODE
bstrPath = pInfo->szPath; #else
WCHAR wszTemp[MAX_PATH]; if (pInfo->szPath(pInfo->szPath) < MAX_PATH) wsprintfW(wszTemp, L"%hs", pInfo->szPath); else wszTemp[0] = 0; bstrPath = wszTemp; #endif
if (SUCCEEDED(hResult = ppf->Load(bstrPath, STGM_READ))) { WIN32_FIND_DATA fd;
hResult = psl->GetPath(pInfo->szTarget, sizeof(pInfo->szTarget), &fd, SLGP_SHORTPATH); hResult = psl->GetArguments(pInfo->szArgs, sizeof(pInfo->szArgs)); } } } }
pInfo->hResult = hResult;
} catch(...) { if (psl) psl->Release(); if (ppf) ppf->Release(); CoUninitialize();
throw; }
if (psl) { psl->Release(); psl = NULL; }
if (ppf) { ppf->Release(); ppf = NULL; }
CoUninitialize();
return 0; }
BOOL CPageStartup::OnInitDialog() { CPropertyPage::OnInitDialog(); ::EnableWindow(GetDlgItemHWND(IDC_LISTSTARTUP), TRUE);
// Attach to the list view and set the styles we need.
m_fIgnoreListChanges = TRUE; m_list.Attach(GetDlgItemHWND(IDC_LISTSTARTUP)); ListView_SetExtendedListViewStyle(m_list.m_hWnd, LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT);
// Add all of the necessary columns to the list view's header control.
struct { UINT m_uiStringResource; int m_iPercentOfWidth; } aColumns[] = { { IDS_STARTUP_LOCATION, 50 }, { IDS_STARTUP_COMMAND, 25 }, { IDS_STARTUP_ITEM, 25 }, { 0, 0 } };
CRect rect; m_list.GetClientRect(&rect); int cxWidth = rect.Width();
LVCOLUMN lvc; lvc.mask = LVCF_TEXT | LVCF_WIDTH;
CString strCaption;
::AfxSetResourceHandle(_Module.GetResourceInstance()); for (int i = 0; aColumns[i].m_uiStringResource; i++) { strCaption.LoadString(aColumns[i].m_uiStringResource); lvc.pszText = (LPTSTR)(LPCTSTR)strCaption; lvc.cx = aColumns[i].m_iPercentOfWidth * cxWidth / 100; ListView_InsertColumn(m_list.m_hWnd, 0, &lvc); }
LoadStartupList();
CPageBase::TabState state = GetCurrentTabState(); ::EnableWindow(GetDlgItemHWND(IDC_BUTTONSUDISABLEALL), (state != DIAGNOSTIC)); ::EnableWindow(GetDlgItemHWND(IDC_BUTTONSUENABLEALL), (state != NORMAL));
m_stateRequested = GetAppliedTabState(); m_fInitialized = TRUE;
// Show the restore disabled startup item button based on whether or not
// there are items to restore.
::ShowWindow(GetDlgItemHWND(IDC_BUTTONSURESTORE), CRestoreStartup::AreItemsToRestore() ? SW_SHOW : SW_HIDE); return TRUE; // return TRUE unless you set the focus to a control
}
void CPageStartup::OnDestroy() { CPropertyPage::OnDestroy(); EmptyList(TRUE); }
//-----------------------------------------------------------------------------
// If there's a change to an item in the list, it's probably because the user
// has checked or unchecked a checkbox.
//-----------------------------------------------------------------------------
void CPageStartup::OnItemChangedList(NMHDR * pNMHDR, LRESULT * pResult) { NM_LISTVIEW * pNMListView = (NM_LISTVIEW *)pNMHDR;
if (!m_fIgnoreListChanges) { LVITEM lvi; lvi.mask = LVIF_PARAM; lvi.iSubItem = 0; lvi.iItem = pNMListView->iItem;
if (ListView_GetItem(m_list.m_hWnd, &lvi)) { CStartupItem * pItem = (CStartupItem *)lvi.lParam; if (pItem) { BOOL fCurrentCheck = ListView_GetCheckState(m_list.m_hWnd, pNMListView->iItem); if (fCurrentCheck != pItem->IsLive()) SetModified(TRUE);
CPageBase::TabState state = GetCurrentTabState(); ::EnableWindow(GetDlgItemHWND(IDC_BUTTONSUDISABLEALL), (state != DIAGNOSTIC)); ::EnableWindow(GetDlgItemHWND(IDC_BUTTONSUENABLEALL), (state != NORMAL)); } } } *pResult = 0; }
//-----------------------------------------------------------------------------
// Handle the buttons to enable or disable all the items.
//-----------------------------------------------------------------------------
void CPageStartup::OnButtonDisableAll() { SetEnableForList(FALSE); }
void CPageStartup::OnButtonEnableAll() { SetEnableForList(TRUE); }
//-------------------------------------------------------------------------
// Return the current state of the tab (need to look through the list).
//-------------------------------------------------------------------------
CPageBase::TabState CPageStartup::GetCurrentTabState() { if (!m_fInitialized) return GetAppliedTabState();
// If there are no startup items, we can only return the
// state that was last requested.
if (ListView_GetItemCount(m_list.m_hWnd) == 0) return m_stateRequested;
TabState stateReturn = USER; BOOL fAllEnabled = TRUE, fAllDisabled = TRUE; LVITEM lvi;
lvi.mask = LVIF_PARAM; lvi.iSubItem = 0;
for (int i = ListView_GetItemCount(m_list.m_hWnd) - 1; i >= 0; i--) { if (ListView_GetCheckState(m_list.m_hWnd, i)) fAllDisabled = FALSE; else fAllEnabled = FALSE; }
if (fAllEnabled) stateReturn = NORMAL; else if (fAllDisabled) stateReturn = DIAGNOSTIC;
return stateReturn; }
//-------------------------------------------------------------------------
// Traverse the list looking for items which have check boxes that don't
// match the state of the items. For these items, set the state.
//
// Finally, the base class implementation is called to maintain the
// applied tab state.
//-------------------------------------------------------------------------
BOOL CPageStartup::OnApply() { if (!m_fModified) return TRUE;
LVITEM lvi; lvi.mask = LVIF_PARAM; lvi.iSubItem = 0;
for (int i = ListView_GetItemCount(m_list.m_hWnd) - 1; i >= 0; i--) { lvi.iItem = i;
if (ListView_GetItem(m_list.m_hWnd, &lvi)) { CStartupItem * pItem = (CStartupItem *)lvi.lParam; if (pItem) { BOOL fCurrentCheck = ListView_GetCheckState(m_list.m_hWnd, i); if (fCurrentCheck != pItem->IsLive()) pItem->SetEnable(fCurrentCheck); } } }
CPageBase::SetAppliedState(GetCurrentTabState()); CancelToClose(); m_fMadeChange = TRUE; return TRUE; }
//-------------------------------------------------------------------------
// Apply the changes, remove the persisted registry entries, refill the
// list. Then call the base class implementation.
//-------------------------------------------------------------------------
void CPageStartup::CommitChanges() { OnApply(); CStartupItemRegistry::RemovePersistedEntries(); CStartupItemFolder::RemovePersistedEntries(); LoadStartupList(); CPageBase::CommitChanges(); }
//-------------------------------------------------------------------------
// Set the overall state of the tab to normal or diagnostic.
//-------------------------------------------------------------------------
void CPageStartup::SetNormal() { SetEnableForList(TRUE); m_stateRequested = NORMAL; }
void CPageStartup::SetDiagnostic() { SetEnableForList(FALSE); m_stateRequested = DIAGNOSTIC; }
//-------------------------------------------------------------------------
// If nothing is selected when the list gets focus, select the first item
// (so the user sees where the focus is).
//-------------------------------------------------------------------------
void CPageStartup::OnSetFocusList(NMHDR * pNMHDR, LRESULT * pResult) { if (0 == ListView_GetSelectedCount(m_list.m_hWnd) && 0 < ListView_GetItemCount(m_list.m_hWnd)) ListView_SetItemState(m_list.m_hWnd, 0, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
*pResult = 0; }
//-------------------------------------------------------------------------
// Show the dialog which allows the user to restore startup items which
// were disabled during upgrade.
//-------------------------------------------------------------------------
void CPageStartup::OnButtonRestore() { CRestoreStartup dlg; dlg.DoModal(); ::EnableWindow(GetDlgItemHWND(IDC_BUTTONSURESTORE), CRestoreStartup::AreItemsToRestore()); }
//=========================================================================
// This code implements the CRestoreStartup dialog, which allows the
// user to restore items disabled by an upgrade.
//=========================================================================
CRestoreStartup::CRestoreStartup(CWnd* pParent /*=NULL*/) : CDialog(CRestoreStartup::IDD, pParent) { //{{AFX_DATA_INIT(CRestoreStartup)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
}
void CRestoreStartup::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CRestoreStartup)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CRestoreStartup, CDialog) //{{AFX_MSG_MAP(CRestoreStartup)
ON_WM_DESTROY() ON_NOTIFY(LVN_ITEMCHANGED, IDC_RESTORELIST, OnItemChangedRestoreList) //}}AFX_MSG_MAP
END_MESSAGE_MAP()
//-----------------------------------------------------------------------------
// As the dialog initializes, set the format of the list view, add the
// appropriate columns, and populate the list with the disabled startup items.
//-----------------------------------------------------------------------------
BOOL CRestoreStartup::OnInitDialog() { CDialog::OnInitDialog();
// Set the list view to have check boxes.
CWnd * pWnd = GetDlgItem(IDC_RESTORELIST); if (pWnd == NULL) return FALSE; m_list.Attach(pWnd->m_hWnd); ListView_SetExtendedListViewStyle(m_list.m_hWnd, LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT);
// Add all of the necessary columns to the list view's header control.
struct { UINT m_uiStringResource; int m_iPercentOfWidth; } aColumns[] = { { IDS_STARTUP_ITEM, 65 }, { IDS_STARTUP_LOCATION, 35 }, { 0, 0 } };
CRect rect; m_list.GetClientRect(&rect); int cxWidth = rect.Width();
LVCOLUMN lvc; lvc.mask = LVCF_TEXT | LVCF_WIDTH;
CString strCaption;
::AfxSetResourceHandle(_Module.GetResourceInstance()); for (int i = 0; aColumns[i].m_uiStringResource; i++) { strCaption.LoadString(aColumns[i].m_uiStringResource); lvc.pszText = (LPTSTR)(LPCTSTR)strCaption; lvc.cx = aColumns[i].m_iPercentOfWidth * cxWidth / 100; ListView_InsertColumn(m_list.m_hWnd, 0, &lvc); }
// Load up the list with the disabled items.
LoadDisabledItemList(); SetOKState(); return TRUE; }
//-----------------------------------------------------------------------------
// Load the items in the list (from the registry and startup directory).
//-----------------------------------------------------------------------------
BOOL CRestoreStartup::LoadDisabledItemList() { m_iNextPosition = 0; BOOL fRegistry = LoadDisabledRegistry(); BOOL fStartup = LoadDisabledStartupGroup(); return (fRegistry && fStartup); }
//-----------------------------------------------------------------------------
// Read the list of disabled startup items which would be restored to the
// registry. This list is just stored in a different registry location.
//-----------------------------------------------------------------------------
BOOL CRestoreStartup::LoadDisabledRegistry() { HKEY ahkeyBases[] = { HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER, NULL };
for (int i = 0; ahkeyBases[i] != NULL; i++) { // Open the key containing the disabled items. We open it KEY_WRITE | KEY_READ,
// even though we are just going to read in this function. This is because
// if opening for this access fails, we don't want to list the items because
// the user won't be able to restore the items.
CRegKey regkey; if (ERROR_SUCCESS != regkey.Open(ahkeyBases[i], DISABLED_KEY, KEY_WRITE | KEY_READ)) return FALSE;
// Get the number of keys under the key and look at each one.
DWORD dwValueCount, dwSize; if (ERROR_SUCCESS == ::RegQueryInfoKey((HKEY)regkey, NULL, NULL, NULL, NULL, NULL, NULL, &dwValueCount, NULL, NULL, NULL, NULL)) { TCHAR szValueName[MAX_PATH], szValue[MAX_PATH]; for (DWORD dwKey = 0; dwKey < dwValueCount; dwKey++) { dwSize = MAX_PATH; if (ERROR_SUCCESS != ::RegEnumValue((HKEY)regkey, dwKey, szValueName, &dwSize, NULL, NULL, NULL, NULL)) continue;
dwSize = MAX_PATH; if (ERROR_SUCCESS != regkey.QueryValue(szValue, szValueName, &dwSize)) continue;
// Create the startup item and insert it in the list.
CStartupDisabledRegistry * pItem = new CStartupDisabledRegistry(szValueName, szValue, ENABLED_KEY, ahkeyBases[i]); InsertDisabledStartupItem(pItem); } }
regkey.Close(); }
return TRUE; }
//-----------------------------------------------------------------------------
// Add the items from the disabled startup group to the list:
//
// GIVEN the path to CSIDL_STARTUP, setup moves disabled items to
// ..\Disabled Startup and makes it hidden; it potentially contains
// the complete content of the original startup folder, which
// can be anything.
//
// Note - we'll also need to look under CSIDL_COMMON_STARTUP.
//-----------------------------------------------------------------------------
BOOL CRestoreStartup::LoadDisabledStartupGroup() { int anFolders[] = { CSIDL_STARTUP, CSIDL_COMMON_STARTUP, 0 }; TCHAR szPath[MAX_PATH * 2];
for (int i = 0; anFolders[i] != 0; i++) { if (FAILED(::SHGetSpecialFolderPath(NULL, szPath, anFolders[i], FALSE))) continue;
// We need to trim off the last part of the path and replace it with
// "Disabled Startup".
CString strPath(szPath); int iLastSlash = strPath.ReverseFind(_T('\\')); if (iLastSlash == -1) continue; strPath = strPath.Left(iLastSlash) + CString(DISABLED_STARTUP);
// Now look for files in the folder.
CString strSearch(strPath); strSearch += CString(_T("\\*.*"));
WIN32_FIND_DATA fd; HANDLE hFind = FindFirstFile(strSearch, &fd); if (hFind != INVALID_HANDLE_VALUE) { do { // We want to ignore the desktop.ini file which might appear in startup.
if ((fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) == 0 || _tcsicmp(fd.cFileName, _T("desktop.ini")) != 0) { // We only want to examine files which aren't directories.
if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { CStartupDisabledStartup * pItem = new CStartupDisabledStartup(fd.cFileName, szPath, strPath); InsertDisabledStartupItem(pItem); } } } while (FindNextFile(hFind, &fd));
FindClose(hFind); } }
return TRUE; }
//-----------------------------------------------------------------------------
// Insert the disabled item into the list view.
//-----------------------------------------------------------------------------
void CRestoreStartup::InsertDisabledStartupItem(CStartupDisabled * pItem) { if (pItem == NULL) return;
CString strItem, strLocation; pItem->GetColumnCaptions(strItem, strLocation);
// Insert the item in the list view.
LV_ITEM lvi; memset(&lvi, 0, sizeof(lvi)); lvi.mask = LVIF_TEXT | LVIF_PARAM; lvi.iItem = m_iNextPosition;
lvi.pszText = (LPTSTR)(LPCTSTR)strLocation; lvi.iSubItem = 0; lvi.lParam = (LPARAM)pItem;
m_iNextPosition = ListView_InsertItem(m_list.m_hWnd, &lvi); ListView_SetItemText(m_list.m_hWnd, m_iNextPosition, 1, (LPTSTR)(LPCTSTR)strItem); ListView_SetCheckState(m_list.m_hWnd, m_iNextPosition, TRUE);
m_iNextPosition++; }
//-----------------------------------------------------------------------------
// Remove all the items from the list view (freeing the objects pointed to
// by the LPARAM).
//-----------------------------------------------------------------------------
void CRestoreStartup::EmptyList() { LVITEM lvi; lvi.mask = LVIF_PARAM; lvi.iSubItem = 0;
for (int i = ListView_GetItemCount(m_list.m_hWnd) - 1; i >= 0; i--) { lvi.iItem = i;
if (ListView_GetItem(m_list.m_hWnd, &lvi)) { CStartupDisabled * pItem = (CStartupDisabled *)lvi.lParam; if (pItem) delete pItem; } }
ListView_DeleteAllItems(m_list.m_hWnd); }
//-----------------------------------------------------------------------------
// When the dialog is being destroyed, be sure to free the memory of the
// object pointers maintained in the list view.
//-----------------------------------------------------------------------------
void CRestoreStartup::OnDestroy() { EmptyList(); CDialog::OnDestroy(); }
//-----------------------------------------------------------------------------
// If the user clicks on OK, then we should make sure he or she really wants
// to perform this operation. If so, then look though the list, calling the
// Restore function for each object with the checkbox checked.
//-----------------------------------------------------------------------------
void CRestoreStartup::OnOK() { CString strText, strCaption;
strCaption.LoadString(IDS_DIALOGCAPTION); strText.LoadString(IDS_VERIFYRESTORE);
if (IDYES == ::MessageBox(m_hWnd, strText, strCaption, MB_YESNO)) { LVITEM lvi; lvi.mask = LVIF_PARAM; lvi.iSubItem = 0; for (int i = ListView_GetItemCount(m_list.m_hWnd) - 1; i >= 0; i--) if (ListView_GetCheckState(m_list.m_hWnd, i)) { lvi.iItem = i; if (ListView_GetItem(m_list.m_hWnd, &lvi)) { CStartupDisabled * pItem = (CStartupDisabled *)lvi.lParam; if (pItem != NULL) pItem->Restore(); } } } CDialog::OnOK(); }
//-----------------------------------------------------------------------------
// Enable or disable the OK button based on the state of the check boxes.
//-----------------------------------------------------------------------------
void CRestoreStartup::SetOKState() { CWnd * pWnd = GetDlgItem(IDOK); if (pWnd == NULL) return;
BOOL fEnable = FALSE; for (int i = ListView_GetItemCount(m_list.m_hWnd) - 1; i >= 0; i--) if (ListView_GetCheckState(m_list.m_hWnd, i)) { fEnable = TRUE; break; }
if (::IsWindowEnabled(pWnd->m_hWnd) != fEnable) ::EnableWindow(pWnd->m_hWnd, fEnable); }
//-----------------------------------------------------------------------------
// If the user changed something in the list, update the OK button state.
//-----------------------------------------------------------------------------
void CRestoreStartup::OnItemChangedRestoreList(NMHDR* pNMHDR, LRESULT* pResult) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; SetOKState(); *pResult = 0; }
//-----------------------------------------------------------------------------
// This static function will be called by the startup tab to determine if the
// button to launch this dialog box should be enabled.
//-----------------------------------------------------------------------------
BOOL CRestoreStartup::AreItemsToRestore() { // Look in the registry for disabled items.
HKEY ahkeyBases[] = { HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER, NULL }; for (int j = 0; ahkeyBases[j] != NULL; j++) { CRegKey regkey; if (ERROR_SUCCESS == regkey.Open(ahkeyBases[j], DISABLED_KEY, KEY_READ)) { DWORD dwValueCount; if (ERROR_SUCCESS == ::RegQueryInfoKey((HKEY)regkey, NULL, NULL, NULL, NULL, NULL, NULL, &dwValueCount, NULL, NULL, NULL, NULL)) if (dwValueCount > 0) { regkey.Close(); return TRUE; } regkey.Close(); } }
// Look in the disabled startup items folders.
int anFolders[] = { CSIDL_STARTUP, CSIDL_COMMON_STARTUP, 0 }; TCHAR szPath[MAX_PATH * 2]; BOOL fDisabledItem = FALSE;
for (int i = 0; !fDisabledItem && anFolders[i] != 0; i++) { if (FAILED(::SHGetSpecialFolderPath(NULL, szPath, anFolders[i], FALSE))) continue;
// We need to trim off the last part of the path and replace it with
// "Disabled Startup".
CString strPath(szPath); int iLastSlash = strPath.ReverseFind(_T('\\')); if (iLastSlash == -1) continue; strPath = strPath.Left(iLastSlash) + CString(DISABLED_STARTUP);
// Now look for files in the folder.
CString strSearch(strPath); strSearch += CString(_T("\\*.*"));
WIN32_FIND_DATA fd; HANDLE hFind = FindFirstFile(strSearch, &fd); if (hFind != INVALID_HANDLE_VALUE) { do { // We want to ignore the desktop.ini file which might appear in startup.
if ((fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) == 0 || _tcsicmp(fd.cFileName, _T("desktop.ini")) != 0) { // We only want to examine files which aren't directories.
if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { fDisabledItem = TRUE; break; } } } while (FindNextFile(hFind, &fd));
FindClose(hFind); } }
return fDisabledItem; }
|