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
1662 lines
47 KiB
#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;
|
|
}
|