WindowsXP-SP1/shell/explorer/trayprop.cpp

2713 lines
86 KiB
C++

//---------------------------------------------------------------------------
// This file contains Taskbar and Start Menu property sheet code
//---------------------------------------------------------------------------
#include "cabinet.h"
#include "rcids.h"
#include "util.h"
#include <help.h> // help ids
#include <regstr.h>
#include <atlstuff.h>
#include "dlg.h"
#include "tray.h"
#include "traycmn.h"
#include "startmnu.h"
#include "desktop2.h"
#include "uemapp.h"
#define GROUPID_CURRENTITEMS 5
#define GROUPID_PASTITEMS 6
#define MAX_PROGS_ALLOWED 30
const static DWORD aInitStartMenuHelpIDs[] = {
IDC_NO_HELP_1, NO_HELP,
IDC_NO_HELP_2, NO_HELP,
IDC_NO_HELP_3, NO_HELP,
IDC_NO_HELP_4, NO_HELP,
IDC_GROUPBOX, IDH_COMM_GROUPBOX,
IDC_GROUPBOX_2, IDH_MENUCONFIG_CLEAR,
IDC_GROUPBOX_3, IDH_COMM_GROUPBOX,
IDC_ADDSHORTCUT, IDH_TRAY_ADD_PROGRAM,
IDC_DELSHORTCUT, IDH_TRAY_REMOVE_PROGRAM,
IDC_EXPLOREMENUS, IDH_TRAY_ADVANCED,
IDC_KILLDOCUMENTS, IDH_MENUCONFIG_CLEAR,
IDC_RESORT, IDH_TRAY_RESORT_BUTTON,
IDC_STARTMENUSETTINGSTEXT, IDH_TRAY_START_MENU_SETTINGS,
0, 0
};
const static DWORD aTaskOptionsHelpIDs[] = { // Context Help IDs
IDC_TASKBARAPPEARANCE,IDH_TASKBAR_OPTIONS_BITMAP,
IDC_NOTIFYAPPEARANCE, IDH_TASKBAR_OPTIONS_BITMAP,
IDC_TRAYOPTAUTOHIDE, IDH_TRAY_TASKBAR_AUTOHIDE,
IDC_TRAYOPTSHOWCLOCK, IDH_TRAY_SHOW_CLOCK,
IDC_TRAYOPTONTOP, IDH_TRAY_TASKBAR_ONTOP,
IDC_LOCKTASKBAR, IDH_TRAY_ENABLEMOVERESIZE,
IDC_GROUPITEMS, IDH_TRAY_GROUPING,
IDC_NOTIFYMAN, IDH_TRAY_HIDE_ICONS,
IDC_CUSTOMIZE, IDH_TRAY_CUSTOMIZE_ICONS,
IDC_QUICKLAUNCH, IDH_TRAY_QUICKLAUNCH,
0, 0
};
const static DWORD aNotifyOptionsHelpIDs[] = { // Context Help IDs
IDC_NOTIFY_TEXT, NO_HELP,
IDC_NOTIFY_TEXT2, NO_HELP,
IDC_COMBO_ACTION, NO_HELP,
IDC_NOTIFY_ITEMS, NO_HELP,
IDB_NOTIFY_RESTOREDEFAULTS, IDH_TRAY_RESTOREDEFBUTTON,
0, 0
};
const static DWORD aStartTabHelpIDs[] = {
IDC_STARTMENUPREVIEW, IDH_START_PREVIEW,
IDC_NEWSCHOOL, IDH_START_SELECTPERSONAL,
IDC_OLDSCHOOL, IDH_START_SELECTCLASSIC,
IDC_NEWSTARTCUSTOMIZE, IDH_START_CUSTOMIZEPERSONAL,
IDC_OLDSTARTCUSTOMIZE, IDH_START_CUSTOMIZECLASSIC,
0, 0
};
const static DWORD aStartCustGeneralTabHelpIDs[] = {
IDC_SPCUST_ICONLARGE, IDH_START_SPCUST_LARGE,
IDC_SPCUST_ICONSMALL, IDH_START_SPCUST_SMALL,
IDC_SPCUST_LARGE, IDH_START_SPCUST_LARGE,
IDC_SPCUST_SMALL, IDH_START_SPCUST_SMALL,
IDC_SPCUST_MINPROGS, IDH_START_SPCUST_MINPROGS,
IDC_SPCUST_MINPROGS_ARROW, IDH_START_SPCUST_MINPROGS,
IDB_SPCUST_CLEARPROG, IDH_START_SPCUST_CLEARPROG,
IDC_SPCUST_INTERNET, IDH_START_SPCUST_INTERNET,
IDC_SPCUST_INTERNETCB, IDH_START_SPCUST_INTERNETCB,
IDC_SPCUST_EMAIL, IDH_START_SPCUST_EMAIL,
IDC_SPCUST_EMAILCB, IDH_START_SPCUST_EMAILCB,
0, 0
};
const static DWORD aStartCustAdvancedTabHelpIDs[] = {
IDC_SPCUST_HOVEROPEN, IDH_START_SPCUST_HOVEROPEN,
IDC_SPCUST_NOTIFYNEW, IDH_START_SPCUST_NOTIFYNEW,
IDC_STARTMENUSETTINGS, IDH_START_STARTMENUSETTINGS,
IDC_SPCUST_RECENT_GROUPBOX, NO_HELP,
IDC_SPCUST_RECENT_TEXT, NO_HELP,
IDC_SPCUST_RECENT, IDH_START_SPCUST_RECENT,
IDB_SPCUST_CLEARDOCS, IDH_START_SPCUST_CLEARDOCS,
0, 0
};
#define REGSTR_VAL_LARGEICONSTEMP TEXT("Start_LargeIcons")
#define REGSTR_VAL_ADMINTOOLSTEMP TEXT("Start_AdminToolsTemp")
void SetDlgItemBitmap(HWND hDlg, int idStatic, int iResource);
void SetDlgItemIcon(HWND hDlg, int idStatic, HICON hi);
void SetProgramIcon(HWND hDlg, int idLarge, int idSmall);
void _TaskbarOptionsUpdateDisplay(HWND hDlg);
void _TaskbarOptionsSizeControls(HWND hDlg);
void _TaskbarOptionsDestroyBitmaps(HWND hDlg);
BOOL_PTR WINAPI AdvancedOptDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
typedef struct
{
HWND hwndTree;
IRegTreeOptions *pTO;
} SMADVANCED;
void SendPSMChanged(HWND hDlg)
{
SendMessage(GetParent(hDlg), PSM_CHANGED, (WPARAM)hDlg, 0L);
}
class CPinHelper
{
public:
CPinHelper();
~CPinHelper();
void Save(BOOL bShowEmail, BOOL bShowBrowser);
void GetPinInfo(BOOL *pbPinBrowser, BOOL *pbPinEmail);
private:
void SavePinInfo(LPCITEMIDLIST pidlVictim, BOOL bOld, BOOL bNew);
LPITEMIDLIST _pidlBrowser;
LPITEMIDLIST _pidlEmail;
IStartMenuPin *_psmp;
};
CPinHelper::CPinHelper()
{
_pidlBrowser = ILCreateFromPath(TEXT("shell:::{2559a1f4-21d7-11d4-bdaf-00c04f60b9f0}"));
_pidlEmail = ILCreateFromPath(TEXT("shell:::{2559a1f5-21d7-11d4-bdaf-00c04f60b9f0}"));
CoCreateInstance(CLSID_StartMenuPin, NULL, CLSCTX_INPROC_SERVER,
IID_PPV_ARG(IStartMenuPin, &_psmp));
}
CPinHelper::~CPinHelper()
{
ILFree(_pidlBrowser);
ILFree(_pidlEmail);
ATOMICRELEASE(_psmp);
}
void CPinHelper::GetPinInfo(BOOL *pbPinBrowser, BOOL *pbPinEmail)
{
*pbPinBrowser = FALSE;
*pbPinEmail = FALSE;
if (_psmp)
{
IEnumIDList *peidl;
if (SUCCEEDED(_psmp->EnumObjects(&peidl)))
{
LPITEMIDLIST pidl;
while (peidl->Next(1, &pidl, NULL) == S_OK)
{
if (ILIsEqual(pidl, _pidlBrowser)) *pbPinBrowser = TRUE;
if (ILIsEqual(pidl, _pidlEmail)) *pbPinEmail = TRUE;
ILFree(pidl);
}
peidl->Release();
}
}
}
void CPinHelper::SavePinInfo(LPCITEMIDLIST pidlVictim, BOOL bOld, BOOL bNew)
{
ASSERT(bOld == TRUE || bOld == FALSE);
ASSERT(bNew == TRUE || bNew == FALSE);
if (pidlVictim && _psmp && bOld != bNew)
{
if (bNew)
{
_psmp->Modify(NULL, pidlVictim);
_psmp->Modify(pidlVictim, SMPIN_POS(0));
}
else
{
_psmp->Modify(pidlVictim, NULL);
}
}
}
void CPinHelper::Save(BOOL bShowEmail, BOOL bShowBrowser)
{
// Get old settings
BOOL bShowBrowserOld, bShowEmailOld;
GetPinInfo(&bShowBrowserOld, &bShowEmailOld);
//
// Do in reverse order because we insert at the top of the list.
//
SavePinInfo(_pidlEmail, bShowEmailOld, bShowEmail);
SavePinInfo(_pidlBrowser, bShowBrowserOld, bShowBrowser);
}
class ATL_NO_VTABLE CNotificationsDlg :
public CComObjectRootEx<CComSingleThreadModel>,
public CDialogImpl<CNotificationsDlg>,
public INotificationCB
{
public:
CNotificationsDlg()
{
_pTrayNotify = NULL;
_fItemChanged = FALSE;
_hPlaceholderIcon = NULL;
_nIndex = -1;
_fComboBoxActive = FALSE;
};
virtual ~CNotificationsDlg()
{
if (_pTrayNotify)
{
_pTrayNotify->Release();
_pTrayNotify = NULL;
}
};
DECLARE_NOT_AGGREGATABLE(CNotificationsDlg)
BEGIN_COM_MAP(CNotificationsDlg)
COM_INTERFACE_ENTRY(INotificationCB)
END_COM_MAP()
enum {IDD = DLG_NOTIFY};
BEGIN_MSG_MAP_EX(CNotificationsDlg)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu)
MESSAGE_HANDLER(WM_HELP, OnHelp)
NOTIFY_HANDLER_EX(IDC_NOTIFY_ITEMS, LVN_ITEMCHANGED, OnItemChanged)
NOTIFY_HANDLER_EX(IDC_NOTIFY_ITEMS, LVN_ENDSCROLL, OnEndScroll)
NOTIFY_CODE_HANDLER(HDN_ITEMCHANGED, OnHeaderItemChanged)
COMMAND_HANDLER_EX(IDC_COMBO_ACTION, CBN_SELENDOK, OnComboSelEnd)
COMMAND_ID_HANDLER_EX(IDB_NOTIFY_RESTOREDEFAULTS, OnRestoreDefaults)
COMMAND_RANGE_HANDLER(IDOK, IDNO, OnCloseCmd)
END_MSG_MAP()
//*** INotificationCB ***
STDMETHODIMP Notify(DWORD dwMessage, LPNOTIFYITEM pNotifyItem);
//*** Message Callbacks ***
LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnHelp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnItemChanged(LPNMHDR pnmh);
LRESULT OnEndScroll(LPNMHDR pnmh);
LRESULT OnHeaderItemChanged(WPARAM wParam, LPNMHDR pnmh, LPARAM lParam);
LRESULT OnComboSelEnd(UINT uMsg, UINT uID , HWND hwnd);
LRESULT OnRestoreDefaults(UINT uMsg, UINT uID , HWND hwnd);
LRESULT OnCloseCmd(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
static LRESULT CALLBACK s_ListViewSubClassWndProc(HWND hwnd, UINT uMsg, WPARAM wParam,
LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
static LRESULT CALLBACK s_ComboBoxSubClassWndProc(HWND hwnd, UINT uMsg, WPARAM wParam,
LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
//*** Other ***
void ApplyChanges(void);
private:
HRESULT _AddItem(CNotificationItem& ni, int iIndex);
void _ShowComboBox();
int _GetCurSel();
void _LoadAndSetLVItemText(UINT uResourceID, DWORD nRow, DWORD nCol);
CSimpleArray<CNotificationItem> _saItems; //copy of the data, initialized by user
BOOL _fItemChanged;
ITrayNotify* _pTrayNotify;
int _nPrevIndex;
HWND _hwndCombo;
HWND _hwndListView;
RECT _rcOldPos;
HICON _hPlaceholderIcon;
BOOL _fComboBoxActive;
int _nIndex;
};
HRESULT CNotificationsDlg::_AddItem(CNotificationItem& ni, int iIndex)
{
HIMAGELIST himl = ListView_GetImageList(_hwndListView, LVSIL_SMALL);
BOOL fInsert = FALSE;
LV_ITEM lvitem = {0};
int iImage = -1;
if (!ni.hIcon)
{
if (!_hPlaceholderIcon)
{
_hPlaceholderIcon = (HICON)LoadImage(hinstCabinet,
MAKEINTRESOURCE(ICO_TRAYPROP_PLACEHOLDER), IMAGE_ICON,
GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
LR_LOADMAP3DCOLORS);
}
if (_hPlaceholderIcon)
ni.hIcon = CopyIcon(_hPlaceholderIcon);
}
if (iIndex == -1)
{
iIndex = _saItems.GetSize();
iImage = ImageList_AddIcon(himl, ni.hIcon);
fInsert = TRUE;
}
else
{
lvitem.mask = LVIF_IMAGE;
lvitem.iItem = iIndex;
lvitem.iSubItem = 0;
ListView_GetItem(_hwndListView, &lvitem);
ImageList_ReplaceIcon(himl, lvitem.iImage, ni.hIcon);
iImage = lvitem.iImage;
fInsert = FALSE;
}
if (!ni.pszIconText || ni.pszIconText[0] == 0)
{
TCHAR szTemp[MAX_PATH];
if (LoadString(hinstCabinet, IDS_NOTITLE, szTemp, ARRAYSIZE(szTemp)))
ni.SetIconText(szTemp);
// ni.m_strText.LoadString(IDS_NOTITLE);
}
else
// Replace '\n' with ' '
{
LPTSTR szTemp = NULL;
while (NULL != (szTemp = StrChr(ni.pszIconText, TEXT('\n'))))
{
ni.pszIconText[szTemp-ni.pszIconText] = TEXT(' ');
}
}
lvitem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_GROUPID;
lvitem.iItem = iIndex;
lvitem.iSubItem = 0;
lvitem.pszText = ni.pszIconText;
lvitem.iImage = iImage;
lvitem.iGroupId = (ni.hWnd == NULL) ? GROUPID_PASTITEMS : GROUPID_CURRENTITEMS;
if (fInsert)
ListView_InsertItem(_hwndListView, &lvitem);
else
ListView_SetItem(_hwndListView, &lvitem);
lvitem.mask = LVIF_TEXT;
lvitem.iItem = iIndex;
lvitem.iSubItem = 1;
CString str;
str.LoadString(IDS_NOTIFY_FIRST + ni.dwUserPref);
lvitem.pszText = (LPTSTR)(LPCTSTR)str;
ListView_SetItem(_hwndListView, &lvitem);
if (fInsert)
{
_saItems.Add(ni);
}
else
{
_saItems[iIndex] = ni;
}
return S_OK;
}
HRESULT CNotificationsDlg::Notify(DWORD dwMessage, NOTIFYITEM * pNotifyItem)
{
if (!pNotifyItem || (!pNotifyItem->hWnd && !pNotifyItem->pszExeName))
return E_INVALIDARG;
ASSERT(pNotifyItem);
CNotificationItem ni = *pNotifyItem;
switch (dwMessage)
{
case NIM_ADD:
case NIM_MODIFY:
{
// We never need to modify a Past Item
for (int i = 0; (i < _saItems.GetSize() && ni.hWnd); i++)
{
// If the Item is already in the list just update it
if (_saItems[i] == ni)
{
return _AddItem(ni, i);
}
}
// If it is not in the list add it
return _AddItem(ni, -1);
}
break;
case NIM_DELETE:
{
for (int i = 0; (i < _saItems.GetSize()); i++)
{
if (_saItems[i] == ni)
{
_saItems.RemoveAt(i);
ListView_DeleteItem(_hwndListView, i);
_ShowComboBox();
return S_OK;
}
}
break;
}
}
return E_INVALIDARG;
}
LRESULT CNotificationsDlg::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
_hwndListView = GetDlgItem(IDC_NOTIFY_ITEMS);
_nPrevIndex = -2;
_rcOldPos.top = -500;
CImageList il;
int iSize = GetSystemMetrics(SM_CXSMICON);
il.Create(iSize, iSize, SHGetImageListFlags(_hwndListView), _saItems.GetSize(), 4);
if (il)
{
CString str;
//list view control holding all the items
ListView_SetExtendedListViewStyle(_hwndListView, LVS_EX_FULLROWSELECT);
ListView_EnableGroupView(_hwndListView, TRUE);
static const struct {
int ids;
int idGroup;
} groupData[] = {{ IDS_NOTIFY_CURRENTITEMS, GROUPID_CURRENTITEMS },
{ IDS_NOTIFY_PASTITEMS, GROUPID_PASTITEMS }};
for (int i = 0; i < ARRAYSIZE(groupData); i++)
{
str.LoadString(groupData[i].ids);
LVGROUP lvgrp = { sizeof(LVGROUP) };
lvgrp.mask = LVGF_HEADER | LVGF_GROUPID;
lvgrp.pszHeader = (LPTSTR)(LPCTSTR)str;
lvgrp.cchHeader = lstrlen(lvgrp.pszHeader);
lvgrp.iGroupId = groupData[i].idGroup;
SendMessage(_hwndListView, LVM_INSERTGROUP, -1, (LPARAM)&lvgrp);
}
//Split width of columns 3/5, 2/5
RECT rc;
::GetClientRect(_hwndListView, &rc);
int width = rc.right - rc.left - GetSystemMetrics(SM_CXHSCROLL);
int width0 = 3*width/5;
int width1 = width-width0;
LV_COLUMN lvcol = {0};
lvcol.mask = LVCF_TEXT | LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM;
str.LoadString(IDS_NOTIFYNAME);
lvcol.pszText = (LPTSTR)(LPCTSTR)str;
lvcol.cx = width0;
lvcol.iSubItem = 0;
ListView_InsertColumn(_hwndListView, 0, &lvcol);
str.LoadString(IDS_BEHAVIOR);
lvcol.pszText = (LPTSTR)(LPCTSTR)str;
lvcol.cx = width1;
lvcol.iSubItem = 1;
ListView_InsertColumn(_hwndListView, 1, &lvcol);
il.SetBkColor(GetSysColor(COLOR_WINDOW));
ListView_SetImageList(_hwndListView, il, LVSIL_SMALL);
il.Detach();
_hwndCombo = GetDlgItem(IDC_COMBO_ACTION);
// make sure combo box uses same font as list view
::SendMessage(_hwndCombo, WM_SETFONT, (WPARAM)::SendMessage(_hwndListView, WM_GETFONT, 0, 0), MAKELPARAM(TRUE, 0));
for (int i = IDS_NOTIFY_FIRST; i < IDS_NOTIFY_LAST; i++)
{
CString strTemp;
strTemp.LoadString(i);
ComboBox_AddString(_hwndCombo, strTemp);
}
::SetParent(_hwndCombo, _hwndListView);
HWND hwndHeader = ListView_GetHeader(_hwndListView);
::SetWindowPos(_hwndCombo, hwndHeader, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW);
::SetWindowSubclass(_hwndListView, s_ListViewSubClassWndProc, 0,
reinterpret_cast<DWORD_PTR>(this));
::SetWindowSubclass(_hwndCombo, s_ComboBoxSubClassWndProc, 0,
reinterpret_cast<DWORD_PTR>(this));
}
_saItems.RemoveAll();
if (_pTrayNotify)
{
_pTrayNotify->Release();
_pTrayNotify = NULL;
}
if (SUCCEEDED(CoCreateInstance(CLSID_TrayNotify, NULL, CLSCTX_LOCAL_SERVER, IID_PPV_ARG(ITrayNotify, &_pTrayNotify))))
{
INotificationCB* pCB;
if (SUCCEEDED(QueryInterface(IID_PPV_ARG(INotificationCB, &pCB))))
{
_pTrayNotify->RegisterCallback(pCB);
pCB->Release();
}
}
// Set the selected and focused state to the first item
// ListView_SetItemState(hwndLV, 0, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
bHandled = TRUE;
return 0;
}
LRESULT CNotificationsDlg::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
::WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU, (ULONG_PTR)(void *)aNotifyOptionsHelpIDs);
bHandled = TRUE;
return 0;
}
LRESULT CNotificationsDlg::OnHelp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
::WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, NULL, HELP_WM_HELP, (ULONG_PTR)(LPTSTR) aNotifyOptionsHelpIDs);
bHandled = TRUE;
return 0;
}
LRESULT CNotificationsDlg::OnItemChanged(LPNMHDR pnmh)
{
_ShowComboBox();
return 0;
}
LRESULT CNotificationsDlg::OnEndScroll(LPNMHDR pnmh)
{
_ShowComboBox();
return 0;
}
LRESULT CNotificationsDlg::OnHeaderItemChanged(WPARAM wParam, LPNMHDR pnmh, LPARAM lParam)
{
HWND hwndHeader = ListView_GetHeader(_hwndListView);
if (pnmh->hwndFrom == hwndHeader)
{
_ShowComboBox();
}
return 0;
}
int CNotificationsDlg::_GetCurSel()
{
return (int)::SendMessage(_hwndListView, LVM_GETNEXTITEM, -1, MAKELPARAM(LVNI_ALL | LVNI_SELECTED, 0));
}
void CNotificationsDlg::_LoadAndSetLVItemText(UINT uResourceID, DWORD nRow, DWORD nCol)
{
CString str;
str.LoadString(uResourceID);
ListView_SetItemText(_hwndListView, nRow, nCol, (LPTSTR)(LPCTSTR)str);
}
LRESULT CNotificationsDlg::OnComboSelEnd(UINT uMsg, UINT uID ,HWND hwnd)
{
int nCurIndex = _fComboBoxActive ? _nIndex : _GetCurSel();
if (nCurIndex != -1)
{
DWORD dwUserPref = ComboBox_GetCurSel(_hwndCombo);
if (dwUserPref != _saItems[nCurIndex].dwUserPref)
{
_fItemChanged = TRUE;
_saItems[nCurIndex].dwUserPref = dwUserPref;
_LoadAndSetLVItemText(IDS_NOTIFY_FIRST + dwUserPref, nCurIndex, 1);
}
}
return 0;
}
LRESULT CNotificationsDlg::OnRestoreDefaults(UINT uMsg, UINT uID , HWND hwnd)
{
for (int i=0;i<_saItems.GetSize();i++)
{
if (_saItems[i].dwUserPref != TNUP_AUTOMATIC)
{
_fItemChanged = TRUE;
_saItems[i].dwUserPref = TNUP_AUTOMATIC;
_LoadAndSetLVItemText(IDS_AUTOMATIC, i, 1);
}
}
return 0;
}
LRESULT CNotificationsDlg::OnCloseCmd(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
if (wID == IDOK)
{
ApplyChanges();
}
if (_hPlaceholderIcon)
{
DestroyIcon(_hPlaceholderIcon);
_hPlaceholderIcon = NULL;
}
_saItems.RemoveAll();
if (_hwndListView)
{
RemoveWindowSubclass(_hwndListView, s_ListViewSubClassWndProc, 0);
}
if (_hwndCombo)
{
RemoveWindowSubclass(_hwndCombo, s_ComboBoxSubClassWndProc, 0);
}
if (_pTrayNotify)
{
_pTrayNotify->RegisterCallback(NULL);
}
bHandled = TRUE;
::EndDialog(m_hWnd, wID);
return 0;
}
LRESULT CALLBACK CNotificationsDlg::s_ListViewSubClassWndProc( HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData )
{
CNotificationsDlg * pNotificationsDlg = reinterpret_cast<CNotificationsDlg*>(dwRefData);
AssertMsg((pNotificationsDlg != NULL), TEXT("pNotificationsDlg SHOULD NOT be NULL."));
switch (uMsg)
{
case WM_KEYDOWN:
{
if (wParam == VK_RIGHT && !pNotificationsDlg->_fComboBoxActive)
{
int nIndex = pNotificationsDlg->_GetCurSel();
if (nIndex != -1)
{
pNotificationsDlg->_nIndex = nIndex;
pNotificationsDlg->_fComboBoxActive = TRUE;
::SetFocus(pNotificationsDlg->_hwndCombo);
}
return 0;
}
}
break;
}
return DefSubclassProc(hwnd, uMsg, wParam, lParam);
}
LRESULT CALLBACK CNotificationsDlg::s_ComboBoxSubClassWndProc( HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData )
{
CNotificationsDlg * pNotificationsDlg = reinterpret_cast<CNotificationsDlg*>(dwRefData);
AssertMsg((pNotificationsDlg != NULL), TEXT("pNotificationsDlg SHOULD NOT be NULL."));
switch (uMsg)
{
case WM_KEYDOWN:
{
if (pNotificationsDlg->_fComboBoxActive)
{
if (wParam == VK_LEFT)
{
pNotificationsDlg->_fComboBoxActive = FALSE;
pNotificationsDlg->_nIndex = 0;
::SetFocus(pNotificationsDlg->_hwndListView);
return 0;
}
else if (wParam == VK_RIGHT)
{
// Disable selection in combo on right button
return 0;
}
}
}
break;
case WM_KILLFOCUS:
{
if (pNotificationsDlg->_fComboBoxActive)
{
pNotificationsDlg->_fComboBoxActive = FALSE;
pNotificationsDlg->_nIndex = 0;
}
}
break;
}
return DefSubclassProc(hwnd, uMsg, wParam, lParam);
}
void CNotificationsDlg::ApplyChanges(void)
{
if (!_fItemChanged)
return;
if (_pTrayNotify)
{
for (int i = 0; i < _saItems.GetSize(); i++)
{
_pTrayNotify->SetPreference(&_saItems[i]);
}
}
}
void CNotificationsDlg::_ShowComboBox(void)
{
int nCurIndex = _GetCurSel();
if (!_fComboBoxActive && nCurIndex == -1)
{
::ShowWindow(_hwndCombo, SW_HIDE);
}
else if (nCurIndex != -1)
{
RECT rcListView;
::GetClientRect(_hwndListView, &rcListView);
RECT rc;
ListView_GetItemRect(_hwndListView, nCurIndex, &rc, LVIR_BOUNDS);
RECT rcHeader;
HWND hwndHeader = ListView_GetHeader(_hwndListView);
Header_GetItemRect(hwndHeader, 1, &rcHeader);
rc.left = rcHeader.left;
rc.right = rcHeader.right;
if (!EqualRect(&_rcOldPos, &rc))
{
_rcOldPos = rc;
::MoveWindow(_hwndCombo, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE);
}
if (!::IsWindowVisible(_hwndCombo))
{
::ShowWindow(_hwndCombo, SW_SHOW);
ComboBox_SetCurSel(_hwndCombo, _saItems[nCurIndex].dwUserPref);
}
}
}
//This is the property sheet for all of the task bar stuff
class CTaskBarPropertySheet : public CPropertySheetImpl<CTaskBarPropertySheet>
{
public:
CTaskBarPropertySheet(UINT nStartPage, HWND hwndParent, DWORD dwFlags) :
CPropertySheetImpl<CTaskBarPropertySheet>((LPCTSTR)NULL, nStartPage, hwndParent),
_dwFlags(dwFlags)
{
LoadString(hinstCabinet, IDS_STARTMENUANDTASKBAR, szPath, ARRAYSIZE(szPath));
SetTitle(szPath);
HPROPSHEETPAGE hpage;
PROPSHEETPAGE psp;
psp.dwSize = sizeof(psp);
psp.dwFlags = PSP_DEFAULT;
psp.hInstance = hinstCabinet;
//taskbar page
psp.pszTemplate = MAKEINTRESOURCE(DLG_TRAY_OPTIONS);
psp.pfnDlgProc = s_TaskbarOptionsDlgProc;
psp.lParam = (LPARAM) this;
hpage = CreatePropertySheetPage(&psp);
if (hpage)
AddPage(hpage);
//start page
psp.pszTemplate = MAKEINTRESOURCE(DLG_START);
psp.pfnDlgProc = s_StartMenuDlgProc;
psp.lParam = (LPARAM) this;
hpage = CreatePropertySheetPage(&psp);
if (hpage)
AddPage(hpage);
//
// We really want to have the tree-options work like the StartPageOptionHelper class above, but
// it stores state in the treeview, which goes away when the child dialog is closed. So for now,
// have it save when the customize dialog is closed, not when the parent is closed.
// Still, have the lifetime of the object be controlled by the parent.
//
if (FAILED(CoCreateInstance(CLSID_CRegTreeOptions, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IRegTreeOptions, &_Adv.pTO))))
{
TraceMsg(TF_WARNING, "ctbps failed to create CRegTreeOptions");
}
_pDlgNotify = new CComObject<CNotificationsDlg>;
if (_pDlgNotify)
{
_pDlgNotify->AddRef();
}
}
~CTaskBarPropertySheet()
{
ATOMICRELEASE(_Adv.pTO);
ATOMICRELEASE(_pDlgNotify);
}
// We aren't handling any messages special, so we just make an empty map
DECLARE_EMPTY_MSG_MAP()
private:
// dlgproc's for the various pages
static BOOL_PTR s_TaskbarOptionsDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
static BOOL_PTR s_StartMenuDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL_PTR TaskbarOptionsDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL_PTR StartMenuDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
void _ApplyTaskbarOptionsFromDialog(HWND hDlg);
void _ApplyStartOptionsFromDialog(HWND hDlg);
// for the old style customize dialog
SMADVANCED _Adv;
//need to keep storage for the title until the property sheet is created
TCHAR szPath[MAX_PATH];
CComObject<CNotificationsDlg>* _pDlgNotify;
DWORD _dwFlags;
};
//
// RegSaveDefaultClient
//
void RegSaveDefaultClient(HWND hwndCB, LPCTSTR pszPath)
{
int iSelected = ComboBox_GetCurSel(hwndCB);
if (iSelected >= 0)
{
LPTSTR pszKey = (LPTSTR)ComboBox_GetItemData(hwndCB, iSelected);
if (pszKey)
{
if (SHSetValue(HKEY_CURRENT_USER, pszPath, NULL, REG_SZ, pszKey, sizeof(TCHAR) * (1 + lstrlen(pszKey))) == ERROR_SUCCESS)
{
SHSendMessageBroadcast(WM_SETTINGCHANGE, 0, (LPARAM)pszPath);
}
}
}
}
BOOL RegGetDefaultClient(HWND hwndCB, HKEY hkRoot, LPCTSTR pszPath)
{
TCHAR szCurrent[MAX_PATH];
LONG cb = sizeof(szCurrent);
cb = sizeof(szCurrent);
if (RegQueryValue(hkRoot, pszPath, szCurrent, &cb) != ERROR_SUCCESS ||
szCurrent[0] == TEXT('\0'))
{
return FALSE;
}
// Now make sure the selected client exists
int i = ComboBox_GetCount(hwndCB);
while (--i >= 0)
{
LPTSTR pszKey = (LPTSTR)ComboBox_GetItemData(hwndCB, i);
// Use StrCmpIC so we don't get faked out by Hungarian locale...
if (pszKey && StrCmpIC(pszKey, szCurrent) == 0)
{
ComboBox_SetCurSel(hwndCB, i);
return TRUE;
}
}
return FALSE;
}
void RegPopulateComboBox(HWND hwndCB, LPCTSTR pszPath)
{
TCHAR szFriendlyName [MAX_PATH];
TCHAR szKeyName [MAX_PATH];
DWORD i; // Index counter
HKEY hkeyProtocol;
// See if the clients key even exists...
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, pszPath, 0, KEY_READ, &hkeyProtocol) != ERROR_SUCCESS)
return;
// populate the dropdown
for(i=0; // always start with 0
ERROR_SUCCESS==RegEnumKey(hkeyProtocol, i, szKeyName, ARRAYSIZE(szKeyName));
i++) // get next entry
{
// get the friendly name of the client
if (SUCCEEDED(SHLoadLegacyRegUIString(hkeyProtocol, szKeyName, szFriendlyName, ARRAYSIZE(szFriendlyName))))
{
// save its key name so we can find it later
LPTSTR pszKeyName = StrDup(szKeyName);
if (pszKeyName)
{
// add name to dropdown
int iAdded = ComboBox_AddString(hwndCB, szFriendlyName);
if (iAdded >= 0)
{
ComboBox_SetItemData(hwndCB, iAdded, pszKeyName);
}
else
{
LocalFree(pszKeyName);
}
}
}
}
RegCloseKey(hkeyProtocol);
// Do this after populating the dropdown because we need to look into
// the dropdown to see if the current value is valid or not
//
// First try HKCU; then try HKLM...
//
if (!RegGetDefaultClient(hwndCB, HKEY_CURRENT_USER, pszPath))
{
RegGetDefaultClient(hwndCB, HKEY_LOCAL_MACHINE, pszPath);
}
}
void RegClearClientComboBox(HWND hDlg, UINT idc)
{
HWND hwndCB = GetDlgItem(hDlg, idc);
int i = ComboBox_GetCount(hwndCB);
while (--i >= 0)
{
LPTSTR pszKey = (LPTSTR)ComboBox_GetItemData(hwndCB, i);
LocalFree(pszKey);
}
}
void HandleClearButtonClick(HWND hwndClear);
void SetDocButton(HWND hDlg, int id);
//This is the property sheet for the "Customize Simple Start Menu" dlg
class CCustomizeSPPropSheet : public CPropertySheetImpl<CCustomizeSPPropSheet>
{
public:
CCustomizeSPPropSheet(HWND hwndParent) :
CPropertySheetImpl<CCustomizeSPPropSheet>((LPCTSTR)NULL, 0, hwndParent)
, _fInsideInit(FALSE)
{
HPROPSHEETPAGE hpage;
PROPSHEETPAGE psp;
// We are heap-allocated so these should be pre-initialized properly
ASSERT(_bDirtyTree == FALSE);
ASSERT(_prto == NULL);
ASSERT(_pph == NULL);
LoadString(hinstCabinet, IDS_SPCUST_TITLE, _szTitle, ARRAYSIZE(_szTitle));
SetTitle(_szTitle);
m_psh.dwFlags |= PSH_NOAPPLYNOW;
psp.dwSize = sizeof(psp);
psp.dwFlags = PSP_DEFAULT;
psp.hInstance = hinstCabinet;
//General page
psp.pszTemplate = MAKEINTRESOURCE(DLG_PAGE_SMGENERAL);
psp.pfnDlgProc = s_GeneralTabDlgProc;
psp.lParam = (LPARAM) this;
hpage = CreatePropertySheetPage(&psp);
if (hpage)
AddPage(hpage);
//Advanced page
psp.pszTemplate = MAKEINTRESOURCE(DLG_PAGE_SMADVANCED);
psp.pfnDlgProc = s_AdvancedTabDlgProc;
psp.lParam = (LPARAM) this;
hpage = CreatePropertySheetPage(&psp);
if (hpage)
AddPage(hpage);
};
~CCustomizeSPPropSheet()
{
if (_pph)
delete _pph;
ATOMICRELEASE(_prto);
}
private:
// dlgproc's for the various pages
static BOOL_PTR s_GeneralTabDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
static BOOL_PTR s_AdvancedTabDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL_PTR GeneralTabDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL_PTR AdvancedTabDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL GeneralTabInit(HWND hDlg);
BOOL AdvancedTabInit(HWND hDlg);
BOOL OnCommand(UINT id, UINT code, HWND hwndCtl, HWND hwndDlg); // shared command handler
BOOL OnGeneralApply(HWND hwndDlg);
BOOL_PTR OnAdvancedNotify(HWND hwndDlg, NMHDR * pnm);
BOOL_PTR OnAdvancedHelp(HWND hDlg, HELPINFO *phi);
void _InitMagicEntries();
void _SaveMagicEntries();
//helpers
DWORD _ReadStartPageSetting(LPCTSTR pszVal, DWORD dwDefault)
{
DWORD dw, cb=sizeof(dw), dwType;
SHRegGetUSValue(REGSTR_PATH_STARTPANE_SETTINGS, pszVal, &dwType, &dw, &cb, FALSE, &dwDefault, sizeof(dwDefault));
return dw; // since we passed a default value, above fn will return our default on failure
}
BOOL _ReadStartPageCUSetting(LPCTSTR pszVal, DWORD *pdw) // returns TRUE/FALSE for present under CU or not, actual value in pdw
{
DWORD cb=sizeof(*pdw), dwType;
return NO_ERROR == SHGetValue(HKEY_CURRENT_USER, REGSTR_PATH_STARTPANE_SETTINGS, pszVal, &dwType, pdw, &cb);
}
BOOL _WriteStartPageSetting(LPCTSTR pszVal, DWORD dwVal)
{
return SHSetValue(HKEY_CURRENT_USER, REGSTR_PATH_STARTPANE_SETTINGS, pszVal, REG_DWORD, &dwVal, sizeof(DWORD)) == NO_ERROR;
}
BOOL _ClearStartPageSetting(LPCTSTR pszVal)
{
return SHDeleteValue(HKEY_CURRENT_USER, REGSTR_PATH_STARTPANE_SETTINGS, pszVal) == NO_ERROR;
}
// State
BOOL _bLargeIcons;
IRegTreeOptions *_prto;
// Dirty Flags
BOOL _bDirtyTree; // to avoid saving the tree if we don't need to
BOOL _bDirtyClients; // to avoid saving the clients if we don't need to
BOOL _bDirtyPinList; // to avoid re-persisting the pin list (and possibly changing the order)
BOOL _bCustNetPlaces; // Did the user previously have net places customized?
BOOL _bCustNetConn; // Did the user previously have net connections customized?
// random bits
CPinHelper *_pph;
TCHAR _szTitle[80]; // needed for the propsheet title...
// We need this to take care of initialization!
BOOL _fInsideInit;
};
BOOL_PTR CCustomizeSPPropSheet::s_GeneralTabDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CCustomizeSPPropSheet* self = NULL;
if (uMsg == WM_INITDIALOG)
{
::SetWindowLongPtr(hDlg, DWLP_USER, lParam);
self = (CCustomizeSPPropSheet*) ((PROPSHEETPAGE*)lParam)->lParam;
}
else
{
PROPSHEETPAGE* psp = (PROPSHEETPAGE*)::GetWindowLongPtr(hDlg, DWLP_USER);
if (psp)
self = (CCustomizeSPPropSheet*)psp->lParam;
}
if (self)
{
return self->GeneralTabDlgProc(hDlg, uMsg, wParam, lParam);
}
else
{
return FALSE;
}
}
BOOL_PTR CCustomizeSPPropSheet::s_AdvancedTabDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CCustomizeSPPropSheet* self = NULL;
if (uMsg == WM_INITDIALOG)
{
::SetWindowLongPtr(hDlg, DWLP_USER, lParam);
self = (CCustomizeSPPropSheet*) ((PROPSHEETPAGE*)lParam)->lParam;
}
else
{
PROPSHEETPAGE* psp = (PROPSHEETPAGE*)::GetWindowLongPtr(hDlg, DWLP_USER);
if (psp)
self = (CCustomizeSPPropSheet*)psp->lParam;
}
if (self)
{
return self->AdvancedTabDlgProc(hDlg, uMsg, wParam, lParam);
}
else
{
return FALSE;
}
}
BOOL_PTR CCustomizeSPPropSheet::GeneralTabDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
return GeneralTabInit(hDlg);
case WM_COMMAND:
return OnCommand(LOWORD(wParam), HIWORD(wParam), (HWND) lParam, hDlg);
case WM_DESTROY:
{
SetDlgItemIcon(hDlg, IDC_SPCUST_ICONSMALL, NULL);
SetDlgItemIcon(hDlg, IDC_SPCUST_ICONLARGE, NULL);
RegClearClientComboBox(hDlg, IDC_SPCUST_EMAILCB);
RegClearClientComboBox(hDlg, IDC_SPCUST_INTERNETCB);
break;
}
case WM_NOTIFY:
switch (((NMHDR*)lParam)->code)
{
case PSN_APPLY:
return OnGeneralApply(hDlg);
}
break;
case WM_HELP:
::WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, NULL, HELP_WM_HELP, (ULONG_PTR)(LPTSTR) aStartCustGeneralTabHelpIDs);
break;
case WM_CONTEXTMENU:
::WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU, (ULONG_PTR)(void *)aStartCustGeneralTabHelpIDs);
break;
}
return FALSE;
}
BOOL CCustomizeSPPropSheet::GeneralTabInit(HWND hDlg)
{
_fInsideInit = TRUE; //We are getting inside initilization!
::SendMessage(::GetDlgItem(hDlg, IDC_SPCUST_MINPROGS_ARROW), UDM_SETRANGE, 0, (LPARAM)MAKELONG(MAX_PROGS_ALLOWED, 0));
// set up icon size
_bLargeIcons = _ReadStartPageSetting(REGSTR_VAL_DV2_LARGEICONS, /*bDefault*/ TRUE);
::CheckDlgButton(hDlg, IDC_SPCUST_LARGE, _bLargeIcons);
::CheckDlgButton(hDlg, IDC_SPCUST_SMALL, !_bLargeIcons);
SetProgramIcon(hDlg, IDC_SPCUST_ICONLARGE, IDC_SPCUST_ICONSMALL);
// Set up the Number of programs dropdown
DWORD dwMinMFU = _ReadStartPageSetting(REGSTR_VAL_DV2_MINMFU, REGSTR_VAL_DV2_MINMFU_DEFAULT);
::SetDlgItemInt(hDlg, IDC_SPCUST_MINPROGS, dwMinMFU, FALSE);
// Set up internet, email checkboxes and comboboxes
BOOL bInternet=FALSE, bMail=FALSE;
RegPopulateComboBox(::GetDlgItem(hDlg, IDC_SPCUST_EMAILCB), TEXT("SOFTWARE\\Clients\\mail"));
RegPopulateComboBox(::GetDlgItem(hDlg, IDC_SPCUST_INTERNETCB), TEXT("SOFTWARE\\Clients\\StartMenuInternet"));
// if this fails, its not fatal, we just won't be able to persist the pin info
_pph = new CPinHelper();
if (_pph)
{
_pph->GetPinInfo(&bInternet, &bMail);
}
::CheckDlgButton(hDlg, IDC_SPCUST_INTERNET, bInternet);
::CheckDlgButton(hDlg, IDC_SPCUST_EMAIL, bMail);
::EnableWindow(::GetDlgItem(hDlg, IDC_SPCUST_INTERNETCB), bInternet);
::EnableWindow(::GetDlgItem(hDlg, IDC_SPCUST_EMAILCB), bMail);
_fInsideInit = FALSE; //We are done initializing.
return TRUE;
}
// Temp until the new UEM code gets in...
void ClearUEMData()
{
HKEY hk;
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_EXPLORER TEXT("\\UserAssist\\{75048700-EF1F-11D0-9888-006097DEACF9}\\Count"),
0, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_SET_VALUE,
&hk))
{
int cValues;
if (ERROR_SUCCESS == RegQueryInfoKey(hk, NULL, NULL, NULL, NULL, NULL, NULL, (DWORD*) &cValues, NULL, NULL, NULL, NULL))
{
while (cValues >= 0)
{
TCHAR szValue[MAX_PATH];
DWORD cch = ARRAYSIZE(szValue);
DWORD cbData;
if (ERROR_SUCCESS != RegEnumValue(hk, --cValues, szValue, &cch, NULL, NULL, NULL, &cbData))
break;
// don't nuke the session value
if (cbData > 8)
RegDeleteValue(hk, szValue);
}
#ifdef DEBUG
RegQueryInfoKey(hk, NULL, NULL, NULL, NULL, NULL, NULL, (DWORD*) &cValues, NULL, NULL, NULL, NULL);
ASSERT(cValues == 1); // the session info value should still exist
#endif
}
RegCloseKey(hk);
// Set the "Apps installed prior to this point are not interesting"
// to the current time. Since we deleted all the usages, we have to
// do something to prevent all the user's apps from being redetected
// as "newly installed and not yet run".
FILETIME ftNow;
GetSystemTimeAsFileTime(&ftNow);
SHRegSetUSValue(DV2_REGPATH, DV2_SYSTEM_START_TIME, REG_BINARY,
&ftNow, sizeof(ftNow), SHREGSET_FORCE_HKCU);
// Start a new session - this kick-starts anybody who is listening
// to UEM events to tell them their cache is invalid
UEMFireEvent(&UEMIID_SHELL, UEME_CTLSESSION, UEMF_XEVENT, TRUE, -1);
}
}
void AdjustNumOfProgsOnStartMenu(HWND hwndDlg, UINT Id)
{
BOOL fTranslated;
int iNumOfProgs = (int)GetDlgItemInt(hwndDlg, Id, &fTranslated, FALSE);
int iNewNumOfProgs = min(max(iNumOfProgs, 0), MAX_PROGS_ALLOWED);
if((iNumOfProgs != iNewNumOfProgs) || (!fTranslated))
{
SetDlgItemInt(hwndDlg, Id, (UINT)iNewNumOfProgs, FALSE);
SendPSMChanged(hwndDlg);
}
}
// NOTE - shared WM_COMMAND handler
//
BOOL CCustomizeSPPropSheet::OnCommand(UINT id, UINT code, HWND hwndCtl, HWND hwndDlg)
{
switch (id)
{
////// General Tab Controls
case IDC_SPCUST_LARGE:
case IDC_SPCUST_SMALL:
_bLargeIcons = (id == IDC_SPCUST_LARGE);
SendPSMChanged(hwndDlg);
return FALSE;
case IDC_SPCUST_MINPROGS:
if(code == EN_KILLFOCUS)
AdjustNumOfProgsOnStartMenu(hwndDlg, id);
else
{
if ((_fInsideInit == FALSE) && (code == EN_CHANGE))
SendPSMChanged(hwndDlg);
}
return FALSE;
case IDB_SPCUST_CLEARPROG:
ClearUEMData();
return FALSE;
case IDC_SPCUST_INTERNET:
case IDC_SPCUST_EMAIL:
COMPILETIME_ASSERT(IDC_SPCUST_INTERNETCB == IDC_SPCUST_INTERNET+1);
COMPILETIME_ASSERT(IDC_SPCUST_EMAILCB == IDC_SPCUST_EMAIL+1);
::EnableWindow(::GetDlgItem(hwndDlg, id+1), ::IsDlgButtonChecked(hwndDlg, id));
_bDirtyPinList = TRUE;
SendPSMChanged(hwndDlg);
return FALSE;
case IDC_SPCUST_INTERNETCB:
case IDC_SPCUST_EMAILCB:
if (code == CBN_SELCHANGE)
{
_bDirtyClients = TRUE;
SendPSMChanged(hwndDlg);
}
return FALSE;
////// Advanced Tab Controls
case IDC_SPCUST_RECENT:
SendPSMChanged(hwndDlg);
return FALSE;
case IDB_SPCUST_CLEARDOCS:
HandleClearButtonClick(hwndCtl);
return FALSE;
case IDC_SPCUST_HOVEROPEN:
case IDC_SPCUST_NOTIFYNEW:
SendPSMChanged(hwndDlg);
return FALSE;
break;
}
return TRUE;
}
BOOL CCustomizeSPPropSheet::OnGeneralApply(HWND hDlg)
{
TraceMsg(TF_ALWAYS, "cspps.General apply", _bDirtyTree);
_WriteStartPageSetting(REGSTR_VAL_DV2_LARGEICONS, _bLargeIcons);
if (_pph && _bDirtyPinList)
{
BOOL bInternet = ::IsDlgButtonChecked(hDlg, IDC_SPCUST_INTERNET);
BOOL bMail = ::IsDlgButtonChecked(hDlg, IDC_SPCUST_EMAIL);
_pph->Save(bMail, bInternet);
}
if (_bDirtyClients)
{
// persist Internet, Mail comboboxes
RegSaveDefaultClient(::GetDlgItem(hDlg, IDC_SPCUST_EMAILCB), TEXT("Software\\Clients\\mail"));
RegSaveDefaultClient(::GetDlgItem(hDlg, IDC_SPCUST_INTERNETCB), TEXT("SOFTWARE\\Clients\\StartMenuInternet"));
}
BOOL bTranslated;
DWORD dwMinMFU = ::GetDlgItemInt(hDlg, IDC_SPCUST_MINPROGS, &bTranslated, FALSE);
if (EVAL(bTranslated))
{
dwMinMFU = min(max(dwMinMFU, 0), MAX_PROGS_ALLOWED);
_WriteStartPageSetting(REGSTR_VAL_DV2_MINMFU, dwMinMFU);
}
return TRUE;
}
BOOL_PTR CCustomizeSPPropSheet::OnAdvancedNotify(HWND hwndDlg, NMHDR * pnm)
{
::SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, 0); // handled
switch (pnm->code)
{
case PSN_APPLY:
TraceMsg(TF_ALWAYS, "cspps.Advanced apply - _bDirtyTree=%d", _bDirtyTree);
if (_bDirtyTree)
{
_prto->WalkTree(WALK_TREE_SAVE);
}
_WriteStartPageSetting(REGSTR_VAL_DV2_SHOWRECDOCS, ::IsDlgButtonChecked(hwndDlg, IDC_SPCUST_RECENT) ? 2 : 0); // 2 so that it cascades
_WriteStartPageSetting(REGSTR_VAL_DV2_AUTOCASCADE, ::IsDlgButtonChecked(hwndDlg, IDC_SPCUST_HOVEROPEN));
_WriteStartPageSetting(REGSTR_VAL_DV2_NOTIFYNEW, ::IsDlgButtonChecked(hwndDlg, IDC_SPCUST_NOTIFYNEW));
// fall through to PSN_RESET case...
case PSN_RESET:
_SaveMagicEntries(); // this must be called on both cancel and apply, so that it cleans up properly...
break;
case TVN_KEYDOWN:
{
TV_KEYDOWN *pnmtv = (TV_KEYDOWN*)pnm;
if (pnmtv->wVKey == VK_SPACE)
{
HWND hwndTree = ::GetDlgItem(hwndDlg, IDC_STARTMENUSETTINGS);
_prto->ToggleItem((HTREEITEM)SendMessage(hwndTree, TVM_GETNEXTITEM, (WPARAM)TVGN_CARET, 0L));
_bDirtyTree = TRUE;
SendPSMChanged(hwndDlg);
::SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE); // eat the key
}
break;
}
case NM_CLICK:
case NM_DBLCLK:
// is this click in our tree?
if ( pnm->idFrom == IDC_STARTMENUSETTINGS )
{
HWND hwndTree = ::GetDlgItem(hwndDlg, IDC_STARTMENUSETTINGS);
TV_HITTESTINFO ht;
DWORD dwPos = GetMessagePos(); // get where we were hit
ht.pt.x = GET_X_LPARAM(dwPos);
ht.pt.y = GET_Y_LPARAM(dwPos);
::ScreenToClient(hwndTree, &ht.pt); // translate it to our window
// retrieve the item hit
HTREEITEM hti = TreeView_HitTest(hwndTree, &ht);
if (hti)
{
_prto->ToggleItem(hti);
_bDirtyTree = TRUE;
SendPSMChanged(hwndDlg);
}
}
break;
// no help yet- needs ids/text from UA
#if 0
case NM_RCLICK: // right mouse click
if (pnm->hwndFrom == hwndTree)
{
_DoTreeHelp(pAdv, (WPARAM)pnm->hwndFrom);
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE); // eat the click
return TRUE;
}
break;
#endif
}
return TRUE;
}
BOOL_PTR CCustomizeSPPropSheet::OnAdvancedHelp(HWND hDlg, HELPINFO *phi)
{
if (phi->iCtrlId != IDC_STARTMENUSETTINGS)
{
::WinHelp((HWND)(phi->hItemHandle), NULL, HELP_WM_HELP, (ULONG_PTR)(LPTSTR)aStartCustAdvancedTabHelpIDs);
}
else
{
HTREEITEM hItem;
HWND hwndTree = ::GetDlgItem(hDlg, IDC_STARTMENUSETTINGS);
//Is this help invoked throught F1 key
if (GetAsyncKeyState(VK_F1) < 0)
{
// Yes. WE need to give help for the currently selected item
hItem = TreeView_GetSelection(hwndTree);
}
else
{
//No, We need to give help for the item at the cursor position
TV_HITTESTINFO ht;
ht.pt = phi->MousePos;
::ScreenToClient(hwndTree, &ht.pt); // Translate it to our window
hItem = TreeView_HitTest(hwndTree, &ht);
}
if (hItem)
_prto->ShowHelp(hItem, HELP_WM_HELP);
}
return TRUE;
}
BOOL_PTR CCustomizeSPPropSheet::AdvancedTabDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
return AdvancedTabInit(hDlg);
case WM_COMMAND:
return OnCommand(LOWORD(wParam), HIWORD(wParam), (HWND) lParam, hDlg);
case WM_NOTIFY:
return OnAdvancedNotify(hDlg, (NMHDR*)lParam);
case WM_HELP:
return OnAdvancedHelp(hDlg, (HELPINFO*) lParam);
break;
case WM_CONTEXTMENU:
::WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU, (ULONG_PTR)(void *)aStartCustAdvancedTabHelpIDs);
break;
}
return FALSE;
}
int DefaultNetConValue()
{
return ShouldShowConnectTo() ? 2 : 0; // default to menu-style (2)
}
int DefaultNetPlacesValue()
{
return ShouldShowNetPlaces() ? 1 : 0; // default to link -style (1)
}
// These two "magic" functions maintain the proper behavior of the network places and network connections settings
// which, by default, turn on when there are n or more items in the folder. But they can also be customized by the
// user to force them on or off.
void CCustomizeSPPropSheet::_InitMagicEntries()
{
BOOL bNewNetPlaces;
BOOL bNewNetConn;
_bCustNetPlaces = _ReadStartPageCUSetting(REGSTR_VAL_DV2_SHOWNETPL, (DWORD*) &bNewNetPlaces);
_bCustNetConn = _ReadStartPageCUSetting(REGSTR_VAL_DV2_SHOWNETCONN, (DWORD*) &bNewNetConn);
// if the user didn't previously customize these settings, then use the auto-magic setting
if (!_bCustNetPlaces)
bNewNetPlaces = DefaultNetPlacesValue();
if (!_bCustNetConn)
bNewNetConn = DefaultNetConValue();
// Write it out, so the rgtreeoption control will reflect either the user's customization, or the magic value
_WriteStartPageSetting(REGSTR_VAL_DV2_SHOWNETPL, bNewNetPlaces);
_WriteStartPageSetting(REGSTR_VAL_DV2_SHOWNETCONN, bNewNetConn);
// for the admin tools radio buttons:
// 0 = don't show anywhere
// 1 = display in all programs (StartMenuAdminTools = 1, Start_AdminToolsRoot = 0)
// 2 = display in all programs and root (StartMenuAdminTools = 1, Start_AdminToolsRoot = 2)
int iAdminToolsTemp = _ReadStartPageSetting(REGSTR_VAL_DV2_ADMINTOOLSROOT, FALSE) ? 2 :
(_ReadStartPageSetting(TEXT("StartMenuAdminTools"), FALSE) ? 1 : 0);
_WriteStartPageSetting(REGSTR_VAL_ADMINTOOLSTEMP, iAdminToolsTemp);
}
void CCustomizeSPPropSheet::_SaveMagicEntries()
{
BOOL bNewNetPlaces = _ReadStartPageSetting(REGSTR_VAL_DV2_SHOWNETPL, FALSE);
BOOL bNewNetConn = _ReadStartPageSetting(REGSTR_VAL_DV2_SHOWNETCONN, FALSE);
// if the user previously had it customized, then we don't need to clear it since it will either
// contain the original value we loaded in _InitMagicEntries, or the updated value if the user changed it.
// if it wasn't originally customized, then we need to clear it if the tree isn't even dirty, or the current value is the magic value we loaded
if (!_bCustNetPlaces && (!_bDirtyTree || bNewNetPlaces == DefaultNetPlacesValue()))
_ClearStartPageSetting(REGSTR_VAL_DV2_SHOWNETPL);
if (!_bCustNetConn && (!_bDirtyTree || bNewNetConn == DefaultNetConValue()))
_ClearStartPageSetting(REGSTR_VAL_DV2_SHOWNETCONN);
if (_bDirtyTree)
{
// see comment above for how this should work
int iAdminToolsTemp = _ReadStartPageSetting(REGSTR_VAL_ADMINTOOLSTEMP, FALSE);
int iATRoot = 0;
int iATPrograms = 0;
if (iAdminToolsTemp >= 1)
{
iATPrograms = 1;
if (iAdminToolsTemp == 2)
{
iATRoot = 2;
}
}
_WriteStartPageSetting(REGSTR_VAL_DV2_ADMINTOOLSROOT, iATRoot);
_WriteStartPageSetting(TEXT("StartMenuAdminTools"), iATPrograms);
}
_ClearStartPageSetting(REGSTR_VAL_ADMINTOOLSTEMP);
}
BOOL CCustomizeSPPropSheet::AdvancedTabInit(HWND hDlg)
{
if (SUCCEEDED(CoCreateInstance(CLSID_CRegTreeOptions, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IRegTreeOptions, &_prto))))
{
HRESULT hr;
HWND hwndTV = ::GetDlgItem(hDlg, IDC_STARTMENUSETTINGS);
// Compute the magic entries before we init the RegTreeOptions
// (so we will have correct information for him!)
_InitMagicEntries();
// HACKHACK - IRegTreeOptions is ANSI, so we temporarily turn off UNICODE
#undef TEXT
#define TEXT(s) s
hr = _prto->InitTree(hwndTV, HKEY_LOCAL_MACHINE, REGSTR_PATH_SMADVANCED "\\StartPanel", NULL);
#undef TEXT
#define TEXT(s) __TEXT(s)
TreeView_SelectSetFirstVisible(hwndTV, TreeView_GetRoot(hwndTV));
::CheckDlgButton(hDlg, IDC_SPCUST_RECENT, _ReadStartPageSetting(REGSTR_VAL_DV2_SHOWRECDOCS, IsOS(OS_PERSONAL) ? FALSE : TRUE));
::CheckDlgButton(hDlg, IDC_SPCUST_HOVEROPEN,_ReadStartPageSetting(REGSTR_VAL_DV2_AUTOCASCADE, TRUE));
::CheckDlgButton(hDlg, IDC_SPCUST_NOTIFYNEW,_ReadStartPageSetting(REGSTR_VAL_DV2_NOTIFYNEW, TRUE));
if(SHRestricted(REST_NORECENTDOCSMENU))
{
//Since this policy is present, hide all the relevant controls
::ShowWindow(::GetDlgItem(hDlg, IDC_SPCUST_RECENT_GROUPBOX), FALSE);// Group box
::ShowWindow(::GetDlgItem(hDlg, IDC_SPCUST_RECENT_TEXT), FALSE); // Description Text.
::ShowWindow(::GetDlgItem(hDlg, IDC_SPCUST_RECENT), FALSE); // Check box
::ShowWindow(::GetDlgItem(hDlg, IDB_SPCUST_CLEARDOCS), FALSE); // Clear button.
}
SetDocButton(hDlg, IDB_SPCUST_CLEARDOCS);
return TRUE;
}
return FALSE;
}
BOOL_PTR CTaskBarPropertySheet::s_TaskbarOptionsDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CTaskBarPropertySheet* self = NULL;
if (uMsg == WM_INITDIALOG)
{
::SetWindowLongPtr(hDlg, DWLP_USER, lParam);
self = (CTaskBarPropertySheet*) ((PROPSHEETPAGE*)lParam)->lParam;
}
else
{
PROPSHEETPAGE* psp = (PROPSHEETPAGE*)::GetWindowLongPtr(hDlg, DWLP_USER);
if (psp)
self = (CTaskBarPropertySheet*)psp->lParam;
}
BOOL_PTR fValue = FALSE;
if (self)
{
self->TaskbarOptionsDlgProc(hDlg, uMsg, wParam, lParam);
}
return fValue;
}
void _TaskbarOptions_OnInitDialog(HWND hDlg)
{
TRAYVIEWOPTS tvo;
c_tray.GetTrayViewOpts(&tvo);
CheckDlgButton(hDlg, IDC_QUICKLAUNCH, tvo.fShowQuickLaunch);
CheckDlgButton(hDlg, IDC_TRAYOPTONTOP, tvo.fAlwaysOnTop);
CheckDlgButton(hDlg, IDC_TRAYOPTAUTOHIDE, (tvo.uAutoHide & AH_ON));
CheckDlgButton(hDlg, IDC_TRAYOPTSHOWCLOCK, !tvo.fHideClock);
if (SHRestricted(REST_HIDECLOCK))
{
EnableWindow(GetDlgItem(hDlg, IDC_TRAYOPTSHOWCLOCK), FALSE);
}
if (SHRestricted(REST_NOTOOLBARSONTASKBAR))
{
EnableWindow(GetDlgItem(hDlg, IDC_QUICKLAUNCH), FALSE);
}
// Restriction- either the tray is disabled by policy, or the "smart" auto tray
// is disabled by policy
if (tvo.fNoTrayItemsDisplayPolicyEnabled || tvo.fNoAutoTrayPolicyEnabled)
{
EnableWindow(GetDlgItem(hDlg, IDC_NOTIFYMAN), FALSE);
EnableWindow(GetDlgItem(hDlg, IDC_CUSTOMIZE), FALSE);
EnableWindow(GetDlgItem(hDlg, IDC_STATIC_NOTIFY), FALSE);
}
else
{
EnableWindow(GetDlgItem(hDlg, IDC_CUSTOMIZE), tvo.fAutoTrayEnabledByUser);
CheckDlgButton(hDlg, IDC_NOTIFYMAN, tvo.fAutoTrayEnabledByUser);
}
CheckDlgButton(hDlg, IDC_LOCKTASKBAR, !_IsSizeMoveEnabled());
BOOL fEnable = !_IsSizeMoveRestricted();
EnableWindow(GetDlgItem(hDlg, IDC_LOCKTASKBAR), fEnable);
if (SHRestricted(REST_NOTASKGROUPING))
{
// If there is a restriction of any kine, hide the window
ShowWindow(GetDlgItem(hDlg, IDC_GROUPITEMS), FALSE);
}
else if (SHRegGetBoolUSValue(REGSTR_EXPLORER_ADVANCED, TEXT("TaskbarGlomming"),
FALSE, TRUE))
{
CheckDlgButton(hDlg, IDC_GROUPITEMS, TRUE);
}
_TaskbarOptionsSizeControls(hDlg);
_TaskbarOptionsUpdateDisplay(hDlg);
}
BOOL_PTR CTaskBarPropertySheet::TaskbarOptionsDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
INSTRUMENT_WNDPROC(SHCNFI_TRAYVIEWOPTIONS_DLGPROC, hDlg, uMsg, wParam, lParam);
switch (uMsg)
{
case WM_COMMAND:
if (GET_WM_COMMAND_ID(wParam, lParam) == IDC_CUSTOMIZE)
{
if (_pDlgNotify)
{
_pDlgNotify->DoModal();
}
}
_TaskbarOptionsUpdateDisplay(hDlg);
SendPSMChanged(hDlg);
break;
case WM_INITDIALOG:
_TaskbarOptions_OnInitDialog(hDlg);
if (_dwFlags & TPF_INVOKECUSTOMIZE)
{
::PostMessage(hDlg, WM_COMMAND, IDC_CUSTOMIZE, 0);
}
break;
case WM_SYSCOLORCHANGE:
_TaskbarOptionsUpdateDisplay(hDlg);
return TRUE;
case WM_DESTROY:
_TaskbarOptionsDestroyBitmaps(hDlg);
break;
case WM_NOTIFY:
switch (((NMHDR *)lParam)->code)
{
case PSN_APPLY:
// save settings here
_ApplyTaskbarOptionsFromDialog(hDlg);
return TRUE;
case PSN_KILLACTIVE:
case PSN_SETACTIVE:
return TRUE;
}
break;
case WM_HELP:
::WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, NULL, HELP_WM_HELP, (ULONG_PTR)(LPTSTR) aTaskOptionsHelpIDs);
break;
case WM_CONTEXTMENU:
::WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU, (ULONG_PTR)(void *)aTaskOptionsHelpIDs);
break;
}
return FALSE;
}
void _StartOptions_OnInitDialog(HWND hDlg)
{
// If StartPanel UI is turned off, then this check box should not show up!
if (SHRestricted(REST_NOSTARTPANEL))
{
//If the restriction exists, then hide this check box.
ShowWindow(::GetDlgItem(hDlg, IDC_NEWSCHOOL), FALSE);
ShowWindow(::GetDlgItem(hDlg, IDC_NEWSCHOOLDESCRIPTION), FALSE);
ShowWindow(::GetDlgItem(hDlg, IDC_NEWSTARTCUSTOMIZE), FALSE);
// And the only thing you can do is check the OldSchool button
CheckDlgButton(hDlg, IDC_OLDSCHOOL, TRUE);
// TODO - PM's need to figure out what to do in the case where new start menu is restricted
// or not available. This propsheet page is rather pointless in that case...
SetDlgItemBitmap(hDlg, IDC_STARTMENUPREVIEW, IDB_STARTPREVIEWCLASSIC);
}
else
{
SHELLSTATE ss = {0};
SHGetSetSettings(&ss, SSF_STARTPANELON, FALSE);
CheckDlgButton(hDlg, IDC_NEWSCHOOL, BOOLIFY(ss.fStartPanelOn));
CheckDlgButton(hDlg, IDC_OLDSCHOOL, !BOOLIFY(ss.fStartPanelOn));
SetDlgItemBitmap(hDlg, IDC_STARTMENUPREVIEW,
ss.fStartPanelOn ? IDB_STARTPREVIEWNEW : IDB_STARTPREVIEWCLASSIC);
// disable "customize" for the style thats off.
EnableWindow(GetDlgItem(hDlg, ss.fStartPanelOn ? IDC_OLDSTARTCUSTOMIZE : IDC_NEWSTARTCUSTOMIZE), FALSE);
}
}
// On destroy, clean up the bitmaps we loaded so we don't leak them
void _StartOptions_OnDestroy(HWND hDlg)
{
SetDlgItemBitmap(hDlg, IDC_STARTMENUPREVIEW, 0);
}
BOOL_PTR CTaskBarPropertySheet::s_StartMenuDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CTaskBarPropertySheet* self = NULL;
if (uMsg == WM_INITDIALOG)
{
::SetWindowLongPtr(hDlg, DWLP_USER, lParam);
self = (CTaskBarPropertySheet*) ((PROPSHEETPAGE*)lParam)->lParam;
}
else
{
PROPSHEETPAGE* psp = (PROPSHEETPAGE*)::GetWindowLongPtr(hDlg, DWLP_USER);
if (psp)
self = (CTaskBarPropertySheet*)psp->lParam;
}
BOOL_PTR fValue = FALSE;
if (self)
{
self->StartMenuDlgProc(hDlg, uMsg, wParam, lParam);
}
return fValue;
}
BOOL_PTR CTaskBarPropertySheet::StartMenuDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_COMMAND:
switch (GET_WM_COMMAND_ID(wParam, lParam))
{
case IDC_NEWSCHOOL:
case IDC_OLDSCHOOL:
if (HIWORD(wParam) == BN_CLICKED)
{
::EnableWindow(::GetDlgItem(hDlg, IDC_NEWSTARTCUSTOMIZE), GET_WM_COMMAND_ID(wParam, lParam) == IDC_NEWSCHOOL);
::EnableWindow(::GetDlgItem(hDlg, IDC_OLDSTARTCUSTOMIZE), GET_WM_COMMAND_ID(wParam, lParam) == IDC_OLDSCHOOL);
SetDlgItemBitmap(hDlg, IDC_STARTMENUPREVIEW,
GET_WM_COMMAND_ID(wParam, lParam) == IDC_NEWSCHOOL ? IDB_STARTPREVIEWNEW : IDB_STARTPREVIEWCLASSIC);
SendPSMChanged(hDlg);
}
break;
case IDC_NEWSTARTCUSTOMIZE:
{
CCustomizeSPPropSheet *pps = new CCustomizeSPPropSheet(hDlg);
if (pps)
{
if (pps->DoModal() == IDOK)
{
// if anything changed, let the propsheet know
SendPSMChanged(hDlg);
}
delete pps;
}
break;
}
case IDC_OLDSTARTCUSTOMIZE:
{
if (DialogBoxParam(hinstCabinet, MAKEINTRESOURCE(DLG_STARTMENU_CONFIG), hDlg, AdvancedOptDlgProc, (LPARAM)&_Adv))
{
// if anything changed, let the propsheet know
SendPSMChanged(hDlg);
}
break;
}
}
break;
case WM_INITDIALOG:
{
_StartOptions_OnInitDialog(hDlg);
}
break;
case WM_DESTROY:
_StartOptions_OnDestroy(hDlg);
break;
case WM_NOTIFY:
switch (((NMHDR *)lParam)->code)
{
case PSN_APPLY:
// save settings here
_ApplyStartOptionsFromDialog(hDlg);
return TRUE;
case PSN_KILLACTIVE:
case PSN_SETACTIVE:
return TRUE;
}
break;
case WM_HELP:
::WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, NULL, HELP_WM_HELP, (ULONG_PTR)(LPTSTR) aStartTabHelpIDs);
break;
case WM_CONTEXTMENU:
::WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU, (ULONG_PTR)(void *)aStartTabHelpIDs);
break;
}
return FALSE;
}
void _UpdateNotifySetting(BOOL fNotifySetting)
{
ITrayNotify * pTrayNotify = NULL;
if (SUCCEEDED(CoCreateInstance(CLSID_TrayNotify, NULL, CLSCTX_LOCAL_SERVER, IID_PPV_ARG(ITrayNotify, &pTrayNotify))))
{
pTrayNotify->EnableAutoTray(fNotifySetting);
pTrayNotify->Release();
}
}
void CTaskBarPropertySheet ::_ApplyTaskbarOptionsFromDialog(HWND hDlg)
{
// We need to get the Cabinet structure from the property sheet info.
BOOL fAlwaysOnTop;
BOOL fAutoHide;
BOOL fChanged;
LONG lRet;
TRAYVIEWOPTS tvo;
// First check for Always on Top
fAlwaysOnTop = ::IsDlgButtonChecked(hDlg, IDC_TRAYOPTONTOP);
c_tray._UpdateAlwaysOnTop(fAlwaysOnTop);
// And change the Autohide state
fAutoHide = ::IsDlgButtonChecked(hDlg, IDC_TRAYOPTAUTOHIDE);
lRet = c_tray._SetAutoHideState(fAutoHide);
c_tray.GetTrayViewOpts(&tvo);
if (!HIWORD(lRet) && fAutoHide)
{
// we tried and failed.
if (!(tvo.uAutoHide & AH_ON))
{
::CheckDlgButton(hDlg, IDC_TRAYOPTAUTOHIDE, FALSE);
_TaskbarOptionsUpdateDisplay(hDlg);
}
}
fChanged = LOWORD(lRet);
if (fChanged)
c_tray._AppBarNotifyAll(NULL, ABN_STATECHANGE, NULL, 0);
// show/hide the clock
tvo.fHideClock = !::IsDlgButtonChecked(hDlg, IDC_TRAYOPTSHOWCLOCK);
if (!tvo.fNoTrayItemsDisplayPolicyEnabled && !tvo.fNoAutoTrayPolicyEnabled)
{
BOOL fNotifySetting = ::IsDlgButtonChecked(hDlg, IDC_NOTIFYMAN);
if (tvo.fAutoTrayEnabledByUser != fNotifySetting)
{
tvo.fAutoTrayEnabledByUser = fNotifySetting;
_UpdateNotifySetting(fNotifySetting);
}
}
tvo.fShowQuickLaunch = ::IsDlgButtonChecked(hDlg, IDC_QUICKLAUNCH);
c_tray.SetTrayViewOpts(&tvo);
SendMessage(c_tray.GetTrayNotifyHWND(), TNM_HIDECLOCK, 0, tvo.fHideClock);
c_tray.SizeWindows();
// Update registry for locked taskbar
DWORD dwEnableSizeMove = !::IsDlgButtonChecked(hDlg, IDC_LOCKTASKBAR);
SHRegSetUSValue(REGSTR_EXPLORER_ADVANCED, TEXT("TaskbarSizeMove"),
REG_DWORD, &dwEnableSizeMove, sizeof(DWORD), SHREGSET_FORCE_HKCU);
//Update registry for grouping behavior
DWORD dwGlom = ::IsDlgButtonChecked(hDlg, IDC_GROUPITEMS);
SHRegSetUSValue(REGSTR_EXPLORER_ADVANCED, TEXT("TaskbarGlomming"),
REG_DWORD, &dwGlom, sizeof(DWORD), SHREGSET_FORCE_HKCU);
::SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, NULL, (LPARAM)TEXT("TraySettings"), SMTO_NOTIMEOUTIFNOTHUNG, 1000, NULL);
}
void CTaskBarPropertySheet::_ApplyStartOptionsFromDialog(HWND hDlg)
{
if(!SHRestricted(REST_NOSTARTPANEL))
{
//Get the current state of the check box
BOOL fStartPanelOn = BOOLIFY(::IsDlgButtonChecked(hDlg, IDC_NEWSCHOOL) );
SHELLSTATE ss = {0};
//See if Startpage is currently on or off.
SHGetSetSettings(&ss, SSF_STARTPANELON, FALSE);
//Check if the check box has been toggled
if(fStartPanelOn != BOOLIFY(ss.fStartPanelOn))
{
// Toggle the setting
ss.fStartPanelOn = fStartPanelOn;
SHGetSetSettings(&ss, SSF_STARTPANELON, TRUE);
//Tell the desktop window so it can add/remove the desktop icons
::PostMessage(v_hwndDesktop, DTM_STARTPAGEONOFF, 0, 0);
}
// Tell the Start Menu to rebuild itself now that we changed it
// (This part is unconditional since the user may have merely
// changed a setting with the Start Menu)
::PostMessage(v_hwndTray, SBM_REBUILDMENU, 0, 0);
}
}
//---------------------------------------------------------------------------
void _TaskbarOptionsDestroyBitmaps(HWND hDlg)
{
SetDlgItemBitmap(hDlg, IDC_TASKBARAPPEARANCE, 0);
SetDlgItemBitmap(hDlg, IDC_NOTIFYAPPEARANCE, 0);
}
typedef struct
{
int idc;
int iAdd;
}
CONTROLBITMAP;
int _TaskbarPickBitmap(HWND hDlg, int iBmpBase, const CONTROLBITMAP* pca, int cca)
{
for (int i = 0; i < cca; i++)
{
if (!IsDlgButtonChecked(hDlg, pca[i].idc))
{
iBmpBase += pca[i].iAdd;
}
}
return iBmpBase;
}
void _TaskbarOptionsUpdateDisplay(HWND hDlg)
{
static const CONTROLBITMAP c_caTaskbar[] =
{
{ IDC_LOCKTASKBAR, 1 },
{ IDC_GROUPITEMS, 2 },
{ IDC_QUICKLAUNCH, 4 },
};
static const CONTROLBITMAP c_caNotify[] =
{
{ IDC_TRAYOPTSHOWCLOCK, 1 },
{ IDC_NOTIFYMAN, 2 },
};
//
// top preview
//
int iBmp;
if (IsDlgButtonChecked(hDlg, IDC_TRAYOPTAUTOHIDE))
{
iBmp = IDB_TAAUTOHIDE;
}
else
{
iBmp = _TaskbarPickBitmap(hDlg, IDB_TAQLLOCKGROUP, c_caTaskbar, ARRAYSIZE(c_caTaskbar));
}
SetDlgItemBitmap(hDlg, IDC_TASKBARAPPEARANCE, iBmp);
//
// bottom preview
//
iBmp = _TaskbarPickBitmap(hDlg, IDB_NACLOCKCLEAN, c_caNotify, ARRAYSIZE(c_caNotify));
SetDlgItemBitmap(hDlg, IDC_NOTIFYAPPEARANCE, iBmp);
//
// customize button
//
EnableWindow(GetDlgItem(hDlg, IDC_CUSTOMIZE), IsDlgButtonChecked(hDlg, IDC_NOTIFYMAN));
}
#define CX_PREVIEW 336
#define CY_PREVIEW 35
// need to do this by hand because dialog units to pixels will change,
// but the bitmaps won't
void _TaskbarOptionsSizeControls(HWND hDlg)
{
static const int c_IDC[] =
{
IDC_TASKBARAPPEARANCE,
IDC_NOTIFYAPPEARANCE
};
for (int i = 0; i < ARRAYSIZE(c_IDC); i++)
{
SetWindowPos(GetDlgItem(hDlg, c_IDC[i]), NULL, 0, 0, CX_PREVIEW, CY_PREVIEW,
SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
}
}
typedef BOOL (* PFCFGSTART) (HWND, BOOL);
void CallAppWiz(HWND hDlg, BOOL bDelItems)
{
HINSTANCE hmodWiz = LoadLibrary(TEXT("AppWiz.Cpl"));
if (hmodWiz)
{
PFCFGSTART pfnCfgStart = (PFCFGSTART)GetProcAddress(hmodWiz, "ConfigStartMenu");
if (pfnCfgStart)
{
pfnCfgStart(hDlg, bDelItems);
}
FreeLibrary(hmodWiz);
}
}
BOOL ExecExplorerAtStartMenu(HWND hDlg)
{
SHELLEXECUTEINFO ei;
BOOL fWorked= FALSE;
TCHAR szParams[MAX_PATH];
ei.cbSize = sizeof(ei);
ei.hwnd = hDlg;
ei.lpVerb = NULL;
ei.fMask = 0;
ei.lpFile = TEXT("Explorer.exe");
if (IsUserAnAdmin())
{
lstrcpy(szParams, TEXT("/E,"));
SHGetSpecialFolderPath(hDlg, &(szParams[ARRAYSIZE(TEXT("/E,"))-1]),
CSIDL_STARTMENU, FALSE);
}
else
{
lstrcpy(szParams, TEXT("/E,/Root,"));
SHGetSpecialFolderPath(hDlg, &(szParams[ARRAYSIZE(TEXT("/E,/Root,"))-1]),
CSIDL_STARTMENU, FALSE);
}
ei.lpParameters = szParams;
ei.lpDirectory = NULL;
ei.lpClass = NULL;
ei.nShow = SW_SHOWDEFAULT;
ei.hInstApp = hinstCabinet;
return(ShellExecuteEx(&ei));
}
const TCHAR *c_szRegMruKeysToDelete[] =
{
TEXT("Software\\Microsoft\\Internet Explorer\\TypedURLs"),
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RunMRU"),
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Doc Find Spec MRU"),
// New for Whistler (should've been in Windows 2000 and Millennium but we forgot)
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Comdlg32\\OpenSaveMRU"),
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Comdlg32\\LastVisitedMRU"),
};
void SetDocButton(HWND hDlg, int id)
{
LPITEMIDLIST pidl;
BOOL bAreDocs = FALSE;
HRESULT hr = SHGetSpecialFolderLocation(hDlg, CSIDL_RECENT, &pidl);
if (SUCCEEDED(hr))
{
IShellFolder *psf = BindToFolder(pidl);
if (psf)
{
HRESULT hres;
LPENUMIDLIST penum;
hres = psf->EnumObjects(hDlg, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &penum);
if (SUCCEEDED(hres))
{
unsigned long celt;
LPITEMIDLIST pidlenum;
if ((S_OK == penum->Next(1, &pidlenum, &celt)) && (celt == 1))
{
SHFree(pidlenum);
bAreDocs = TRUE;
}
penum->Release();
}
psf->Release();
}
SHFree(pidl);
}
// Check other MRU registry keys
if (!bAreDocs)
{
int i;
for (i = 0; i < ARRAYSIZE(c_szRegMruKeysToDelete); i++)
{
HKEY hkey;
if (RegOpenKeyEx(HKEY_CURRENT_USER, c_szRegMruKeysToDelete[i], 0L, KEY_ALL_ACCESS, &hkey) == ERROR_SUCCESS)
{
bAreDocs = TRUE;
RegCloseKey(hkey);
}
}
}
Button_Enable(GetDlgItem(hDlg, id), bAreDocs);
}
void ClearRecentDocumentsAndMRUStuff(BOOL fBroadcastChange)
{
int i;
SHAddToRecentDocs(0, NULL);
// Flush other MRUs in the registry for privacy
for (i = 0; i < ARRAYSIZE(c_szRegMruKeysToDelete); i++)
{
SHDeleteKey(HKEY_CURRENT_USER, c_szRegMruKeysToDelete[i]);
if (fBroadcastChange)
SHSendMessageBroadcast(WM_SETTINGCHANGE, 0,
(LPARAM)c_szRegMruKeysToDelete[i]);
}
}
void HandleClearButtonClick(HWND hwndClear)
{
HCURSOR hc = SetCursor(LoadCursor(NULL, IDC_WAIT));
ClearRecentDocumentsAndMRUStuff(TRUE);
SetCursor(hc);
//
// Before disabling the button, shove focus off it.
//
if (GetFocus() == hwndClear)
{
SendMessage(GetParent(hwndClear), WM_NEXTDLGCTL, 0, MAKELONG(FALSE, 0));
}
Button_Enable(hwndClear, FALSE);
}
void Reorder(HDPA hdpa)
{
for (int i = DPA_GetPtrCount(hdpa) - 1; i >= 0; i--)
{
PORDERITEM poi = (PORDERITEM)DPA_FastGetPtr(hdpa, i);
poi->nOrder = i;
}
}
void MenuOrderSort(HKEY hkeyRoot, IShellFolder* psf);
void MenuOrderSortKeyWithFolder(HKEY hkeyRoot, LPTSTR pszKey, IShellFolder* psf)
{
HKEY hkey;
if (ERROR_SUCCESS == RegOpenKeyEx(hkeyRoot, pszKey, 0, KEY_READ | KEY_WRITE, &hkey))
{
MenuOrderSort(hkey, psf);
RegCloseKey(hkey);
}
}
// Binds to the Key pszKey, under hkey root, using psf, and sorts the resultant order.
void MenuOrderSortSubKey(HKEY hkeyRoot, LPTSTR szFolder, LPTSTR pszKey, IShellFolder* psf)
{
LPITEMIDLIST pidl;
DWORD cbEaten;
DWORD dwAttrib;
WCHAR wszKey[MAX_PATH];
SHTCharToUnicode(szFolder, wszKey, ARRAYSIZE(wszKey));
if (SUCCEEDED(psf->ParseDisplayName(NULL, NULL, wszKey, &cbEaten, &pidl, &dwAttrib)))
{
IShellFolder* psfSub;
if (SUCCEEDED(psf->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &psfSub))))
{
MenuOrderSortKeyWithFolder(hkeyRoot, pszKey, psfSub);
psfSub->Release();
}
ILFree(pidl);
}
}
void MenuOrderSort(HKEY hkeyRoot, IShellFolder* psf)
{
// Try to open Value Order
IStream* pstm = SHOpenRegStream(hkeyRoot, TEXT(""), TEXT("Order"), STGM_READWRITE);
if (pstm)
{
IOrderList2* pol2;
if (SUCCEEDED(CoCreateInstance(CLSID_OrderListExport, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IOrderList2, &pol2))))
{
HDPA hdpa;
if (SUCCEEDED(pol2->LoadFromStream(pstm, &hdpa, psf)))
{
// Since it's stored ordered by name, this should be no problem.
Reorder(hdpa);
// Set the seek pointer at the beginning.
LARGE_INTEGER liZero = {0};
pstm->Seek(liZero, STREAM_SEEK_SET, NULL);
pol2->SaveToStream(pstm, hdpa);
DPA_Destroy(hdpa);
}
pol2->Release();
}
pstm->Release();
}
// Now enumerate sub keys.
TCHAR szKey[MAX_PATH];
DWORD cbKey = ARRAYSIZE(szKey);
int iIndex = 0;
while (ERROR_SUCCESS == RegEnumKeyEx(hkeyRoot, iIndex, szKey, &cbKey, NULL, NULL, NULL, NULL))
{
MenuOrderSortSubKey(hkeyRoot, szKey, szKey, psf);
iIndex++;
cbKey = ARRAYSIZE(szKey);
}
}
// Defined in Tray.c
IShellFolder* BindToFolder(LPCITEMIDLIST pidl);
void StartMenuSort()
{
IShellFolder* psf = NULL;
LPITEMIDLIST pidl;
HRESULT hr = SHGetSpecialFolderLocation(NULL, CSIDL_STARTMENU, &pidl);
if (SUCCEEDED(hr))
{
LPITEMIDLIST pidl2;
if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_COMMON_STARTMENU, &pidl2)))
{
IAugmentedShellFolder2* pasf;
IShellFolder* psfCommon;
IShellFolder* psfUser;
HRESULT hres = CoCreateInstance(CLSID_MergedFolder, NULL, CLSCTX_INPROC,
IID_PPV_ARG(IAugmentedShellFolder2, &pasf));
if (SUCCEEDED(hres))
{
psfUser = BindToFolder(pidl);
if (psfUser)
{
pasf->AddNameSpace(NULL, psfUser, pidl, ASFF_DEFAULT | ASFF_DEFNAMESPACE_ALL);
psfUser->Release();
}
psfCommon = BindToFolder(pidl2);
if (psfCommon)
{
pasf->AddNameSpace(NULL, psfCommon, pidl2, ASFF_DEFAULT);
psfCommon->Release();
}
hres = pasf->QueryInterface(IID_PPV_ARG(IShellFolder, &psf));
pasf->Release();
}
ILFree(pidl2);
}
else
{
psf = BindToFolder(pidl);
}
ILFree(pidl);
}
if (psf)
{
HKEY hkeyRoot;
// Recursivly sort the orders. Should this be on another thread?
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, STRREG_STARTMENU,
0, KEY_READ | KEY_WRITE, &hkeyRoot))
{
MenuOrderSort(hkeyRoot, psf);
// Sort the My Documents menu item:
LPITEMIDLIST pidlMyDocs;
SHGetFolderLocation(NULL, CSIDL_PERSONAL, NULL, 0, &pidlMyDocs);
if (pidlMyDocs)
{
IShellFolder* psfMyDocs;
if (SUCCEEDED(SHBindToObjectEx(NULL, pidlMyDocs, NULL, IID_PPV_ARG(IShellFolder, &psfMyDocs))))
{
MenuOrderSortKeyWithFolder(hkeyRoot, TEXT("MyDocuments"), psfMyDocs);
psfMyDocs->Release();
}
ILFree(pidlMyDocs);
}
// What happens if the Filesystem programs is not equal to the hard coded string "Programs"? This
// happens on German: Programme != Programs and we fail to sort. So let's verify:
TCHAR szPath[MAX_PATH];
SHGetFolderPath(NULL, CSIDL_PROGRAMS, NULL, 0, szPath);
LPTSTR pszName = PathFindFileName(szPath);
if (StrCmpI(pszName, TEXT("Programs")) != 0)
{
// Ok, It's not the same, so go bind to that sub tree and sort it.
MenuOrderSortSubKey(hkeyRoot, pszName, TEXT("Programs"), psf);
}
RegCloseKey(hkeyRoot);
}
psf->Release();
}
}
BOOL Advanced_OnInitDialog(HWND hwndDlg, SMADVANCED* pAdv)
{
if (!pAdv || !pAdv->pTO)
{
EndDialog(hwndDlg, 0);
return FALSE; // no memory?
}
SetWindowPtr(hwndDlg, DWLP_USER, pAdv);
// since the large icon setting is stored in the tray state, not as a standalone reg key, we need to have a temp reg key for the regtreeop to use...
TRAYVIEWOPTS tvo;
c_tray.GetTrayViewOpts(&tvo);
BOOL fLargePrev = !tvo.fSMSmallIcons;
SHSetValue(HKEY_CURRENT_USER, REGSTR_EXPLORER_ADVANCED, REGSTR_VAL_LARGEICONSTEMP, REG_DWORD, (void*) &fLargePrev, sizeof(fLargePrev));
pAdv->hwndTree = GetDlgItem( hwndDlg, IDC_STARTMENUSETTINGS );
// HACKHACK - IRegTreeOptions is ANSI, so we temporarily turn off UNICODE
#undef TEXT
#define TEXT(s) s
HRESULT hr = pAdv->pTO->InitTree(pAdv->hwndTree, HKEY_LOCAL_MACHINE, REGSTR_PATH_SMADVANCED "\\StartMenu", NULL);
#undef TEXT
#define TEXT(s) __TEXT(s)
// find the first root and make sure that it is visible
TreeView_EnsureVisible(pAdv->hwndTree, TreeView_GetRoot( pAdv->hwndTree ));
SetDocButton(hwndDlg, IDC_KILLDOCUMENTS);
return SUCCEEDED(hr);
}
void InitStartMenu_DoTreeHelp(SMADVANCED* pAdv, WPARAM wParam)
{
TV_HITTESTINFO ht;
GetCursorPos( &ht.pt ); // get where we were hit
if (pAdv->hwndTree == WindowFromPoint(ht.pt))
{
ScreenToClient( pAdv->hwndTree, &ht.pt ); // translate it to our window
// retrieve the item hit
pAdv->pTO->ShowHelp(TreeView_HitTest( pAdv->hwndTree, &ht),HELP_CONTEXTMENU);
}
else
{
WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU,
(ULONG_PTR)(LPVOID)aInitStartMenuHelpIDs);
}
}
BOOL_PTR CALLBACK AdvancedOptDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
SMADVANCED* pAdv = (SMADVANCED*)GetWindowPtr(hwndDlg, DWLP_USER);
INSTRUMENT_WNDPROC(SHCNFI_INITSTARTMENU_DLGPROC, hwndDlg, msg, wParam, lParam);
if (msg != WM_INITDIALOG && !pAdv)
{
// We've been re-entered after being destroyed. Bail.
return FALSE;
}
switch (msg)
{
case WM_COMMAND:
switch(GET_WM_COMMAND_ID(wParam, lParam))
{
case IDC_ADDSHORTCUT:
CallAppWiz(hwndDlg, FALSE);
break;
case IDC_DELSHORTCUT:
CallAppWiz(hwndDlg, TRUE);
break;
case IDC_RESORT:
{
SHChangeDWORDAsIDList dwidl;
StartMenuSort();
// Notify everyone that the order changed
dwidl.cb = sizeof(dwidl) - sizeof(dwidl.cbZero);
dwidl.dwItem1 = SHCNEE_ORDERCHANGED;
dwidl.dwItem2 = 0;
dwidl.cbZero = 0;
SHChangeNotify(SHCNE_EXTENDED_EVENT, SHCNF_FLUSH, (LPCITEMIDLIST)&dwidl, NULL);
break;
}
case IDC_EXPLOREMENUS:
ExecExplorerAtStartMenu(hwndDlg);
break;
case IDC_KILLDOCUMENTS:
{
HandleClearButtonClick(GET_WM_COMMAND_HWND(wParam, lParam));
}
break;
case IDOK:
{
pAdv->pTO->WalkTree(WALK_TREE_SAVE);
TRAYVIEWOPTS tvo;
c_tray.GetTrayViewOpts(&tvo);
BOOL fSmallPrev = tvo.fSMSmallIcons;
// note that we are loading the classic setting for large icons here....
BOOL fSmallNew = !SHRegGetBoolUSValue(REGSTR_EXPLORER_ADVANCED, REGSTR_VAL_LARGEICONSTEMP, FALSE, TRUE /* default to large*/);
if (fSmallPrev != fSmallNew)
{
tvo.fSMSmallIcons = fSmallNew;
c_tray.SetTrayViewOpts(&tvo);
IMenuPopup_SetIconSize(c_tray.GetStartMenu(), fSmallNew ? BMICON_SMALL : BMICON_LARGE);
}
::SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, NULL, (LPARAM)TEXT("TraySettings"), SMTO_NOTIMEOUTIFNOTHUNG, 1000, NULL);
}
// fall through
case IDCANCEL:
SHDeleteValue(HKEY_CURRENT_USER, REGSTR_EXPLORER_ADVANCED, REGSTR_VAL_LARGEICONSTEMP);
EndDialog(hwndDlg, FALSE); // false to not enable parent's apply
break;
}
break;
case WM_INITDIALOG:
return Advanced_OnInitDialog(hwndDlg, (SMADVANCED *)lParam);
case WM_NOTIFY:
{
LPNMHDR pnm = (NMHDR *)lParam;
SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, 0); // handled
switch (pnm->code)
{
case TVN_KEYDOWN:
{
TV_KEYDOWN *pnmKeyDown = (TV_KEYDOWN*)((NMHDR *)lParam);
if (pnmKeyDown->wVKey == VK_SPACE)
{
pAdv->pTO->ToggleItem((HTREEITEM)SendMessage(pAdv->hwndTree, TVM_GETNEXTITEM, (WPARAM)TVGN_CARET, 0L));
SendMessage(GetParent(hwndDlg), PSM_CHANGED, (WPARAM)hwndDlg, 0L);
SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, TRUE); // eat the key
}
break;
}
case NM_CLICK:
case NM_DBLCLK:
// is this click in our tree?
if ( pnm->idFrom == IDC_STARTMENUSETTINGS )
{
TV_HITTESTINFO ht;
DWORD dwPos = GetMessagePos(); // get where we were hit
ht.pt.x = GET_X_LPARAM(dwPos);
ht.pt.y = GET_Y_LPARAM(dwPos);
ScreenToClient( pAdv->hwndTree, &ht.pt ); // translate it to our window
// retrieve the item hit
pAdv->pTO->ToggleItem(TreeView_HitTest( pAdv->hwndTree, &ht));
SendMessage(GetParent(hwndDlg), PSM_CHANGED, (WPARAM)hwndDlg, 0L);
}
break;
case NM_RCLICK: // right mouse click
if (pnm->hwndFrom == pAdv->hwndTree)
{
InitStartMenu_DoTreeHelp(pAdv, (WPARAM)pnm->hwndFrom);
SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, TRUE); // eat the click
return TRUE;
}
break;
}
break;
}
case WM_HELP: // F1
{
LPHELPINFO phi = (LPHELPINFO)lParam;
if (phi->iCtrlId != IDC_STARTMENUSETTINGS)
{
WinHelp( (HWND)(phi->hItemHandle), NULL,
HELP_WM_HELP, (ULONG_PTR)(LPTSTR)aInitStartMenuHelpIDs);
}
else
{
HTREEITEM hItem;
//Is this help invoked throught F1 key
if (GetAsyncKeyState(VK_F1) < 0)
{
// Yes. WE need to give help for the currently selected item
hItem = TreeView_GetSelection(pAdv->hwndTree);
}
else
{
//No, We need to give help for the item at the cursor position
TV_HITTESTINFO ht;
ht.pt = phi->MousePos;
ScreenToClient(pAdv->hwndTree, &ht.pt); // Translate it to our window
hItem = TreeView_HitTest(pAdv->hwndTree, &ht);
}
pAdv->pTO->ShowHelp(hItem, HELP_WM_HELP);
}
break;
}
case WM_CONTEXTMENU: // right mouse click
{
InitStartMenu_DoTreeHelp(pAdv, wParam);
break;
}
case WM_DESTROY:
{
// will be free'd when our parent is destroyed
pAdv->pTO->WalkTree(WALK_TREE_DELETE);
// make sure we don't re-enter
SetWindowPtr( hwndDlg, DWLP_USER, NULL );
}
break; // WM_DESTORY
default:
return FALSE;
}
return TRUE;
}
#define TPF_PAGEFLAGS (TPF_STARTMENUPAGE | TPF_TASKBARPAGE)
void DoTaskBarProperties(HWND hwnd, DWORD dwFlags)
{
ASSERT(((dwFlags & TPF_PAGEFLAGS) == TPF_STARTMENUPAGE) ||
((dwFlags & TPF_PAGEFLAGS) == TPF_TASKBARPAGE));
UINT nStartPage = (dwFlags & TPF_TASKBARPAGE) ? 0 : 1;
CTaskBarPropertySheet sheet(nStartPage, hwnd, dwFlags);
sheet.DoModal(hwnd);
}
// Passing iResource=0 deletes the bitmap in the control
void SetDlgItemBitmap(HWND hDlg, int idStatic, int iResource)
{
HBITMAP hbm;
if (iResource)
{
hbm = (HBITMAP)LoadImage(hinstCabinet, MAKEINTRESOURCE(iResource), IMAGE_BITMAP, 0,0, LR_LOADMAP3DCOLORS);
}
else
{
hbm = NULL;
}
hbm = (HBITMAP)SendDlgItemMessage(hDlg, idStatic, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbm);
if (hbm)
DeleteObject(hbm);
}
void SetDlgItemIcon(HWND hDlg, int idStatic, HICON hIcon)
{
HICON hiOld = (HICON)SendDlgItemMessage(hDlg, idStatic, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon);
if (hiOld)
DestroyIcon(hiOld);
}
// REVIEW - use SHGetFileInfo?
void SetProgramIcon(HWND hDlg, int idLarge, int idSmall)
{
HICON hIconLarge = NULL;
HICON hIconSmall = NULL;
LPITEMIDLIST pidlMyComp = ILCreateFromPath(TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}")); // CLSID_MyComputer;
if (pidlMyComp)
{
IShellFolder *psfDesktop;
if (SUCCEEDED(SHGetDesktopFolder(&psfDesktop)))
{
IExtractIcon *pxi;
if (SUCCEEDED(psfDesktop->GetUIObjectOf(NULL, 1, (LPCITEMIDLIST*)&pidlMyComp, IID_PPV_ARG_NULL(IExtractIcon, &pxi))))
{
TCHAR szIconFile[MAX_PATH];
int iIndex;
UINT wFlags;
if (S_OK == pxi->GetIconLocation(GIL_FORSHELL, szIconFile, ARRAYSIZE(szIconFile), &iIndex, &wFlags))
{
pxi->Extract(szIconFile, iIndex, &hIconLarge, &hIconSmall, (GetSystemMetrics(SM_CXSMICON)<<16) | GetSystemMetrics(SM_CXICON));
}
pxi->Release();
}
psfDesktop->Release();
}
ILFree(pidlMyComp);
}
if (hIconLarge)
SetDlgItemIcon(hDlg, idLarge, hIconLarge);
if (hIconSmall)
SetDlgItemIcon(hDlg, idSmall, hIconSmall);
}