//--------------------------------------------------------------------------- // This file contains Taskbar and Start Menu property sheet code //--------------------------------------------------------------------------- #include "cabinet.h" #include "rcids.h" #include "util.h" #include // help ids #include #include #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, public CDialogImpl, 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 _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 pszTemp = NULL; while (NULL != (pszTemp = StrChr(ni.pszIconText, TEXT('\n')))) { *pszTemp = 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); // found in security review -- not a security problem, but this doesnt do jack (?) // ::Create allocates a new CImageList, should this call initialize()? 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(this)); ::SetWindowSubclass(_hwndCombo, s_ComboBoxSubClassWndProc, 0, reinterpret_cast(this)); } _saItems.RemoveAll(); if (_pTrayNotify) { _pTrayNotify->Release(); _pTrayNotify = NULL; } // localserver for tray notify 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(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(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 { public: CTaskBarPropertySheet(UINT nStartPage, HWND hwndParent, DWORD dwFlags) : CPropertySheetImpl((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); _pDlgNotify = new CComObject; if (_pDlgNotify) { _pDlgNotify->AddRef(); } } ~CTaskBarPropertySheet() { 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* _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); 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 { public: CCustomizeSPPropSheet(HWND hwndParent) : CPropertySheetImpl((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() { ASSERT(!_prto); // should be gone by now if (_pph) delete _pph; } 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(dwVal)) == 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... // must release prto before the treeview goes away! _prto->WalkTree(WALK_TREE_DELETE); ATOMICRELEASE(_prto); 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 (FAILED(CoCreateInstance(CLSID_CRegTreeOptions, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IRegTreeOptions, &_Adv.pTO)))) { TraceMsg(TF_WARNING, "ctbps failed to create CRegTreeOptions"); break; } 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; // localserver for tray notify 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. // First check for Always on Top BOOL fAlwaysOnTop = ::IsDlgButtonChecked(hDlg, IDC_TRAYOPTONTOP); c_tray._UpdateAlwaysOnTop(fAlwaysOnTop); // And change the Autohide state BOOL fAutoHide = ::IsDlgButtonChecked(hDlg, IDC_TRAYOPTAUTOHIDE); LONG lRet = c_tray._SetAutoHideState(fAutoHide); TRAYVIEWOPTS tvo; c_tray.GetTrayViewOpts(&tvo); if (!HIWORD(lRet) && fAutoHide) { // we tried and failed. if (!(tvo.uAutoHide & AH_ON)) { ::CheckDlgButton(hDlg, IDC_TRAYOPTAUTOHIDE, FALSE); _TaskbarOptionsUpdateDisplay(hDlg); } } BOOL 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) { BOOL fRet = FALSE; TCHAR szFile[MAX_PATH]; if (GetSystemWindowsDirectory(szFile, ARRAYSIZE(szFile))) { SHELLEXECUTEINFO ei = { 0 }; StrCatBuff(szFile, TEXT("\\explorer.exe"), ARRAYSIZE(szFile)); ei.lpFile = szFile; ei.cbSize = sizeof(ei); ei.hwnd = hDlg; TCHAR szParams[MAX_PATH + ARRAYSIZE(TEXT("/E,/Root,"))]; if (IsUserAnAdmin()) { lstrcpyn(szParams, TEXT("/E,"), ARRAYSIZE(szParams)); SHGetSpecialFolderPath(hDlg, &(szParams[ARRAYSIZE(TEXT("/E,"))-1]), CSIDL_STARTMENU, FALSE); } else { lstrcpyn(szParams, TEXT("/E,/Root,"), ARRAYSIZE(szParams)); SHGetSpecialFolderPath(hDlg, &(szParams[ARRAYSIZE(TEXT("/E,/Root,"))-1]), CSIDL_STARTMENU, FALSE); } ei.lpParameters = szParams; ei.nShow = SW_SHOWDEFAULT; ei.hInstApp = hinstCabinet; fRet = ShellExecuteEx(&ei); } return fRet; } 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) { IEnumIDList *penum; if (S_OK == psf->EnumObjects(hDlg, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &penum)) { unsigned long celt; LPITEMIDLIST pidlenum; if ((S_OK == penum->Next(1, &pidlenum, &celt)) && (celt == 1)) { ILFree(pidlenum); bAreDocs = TRUE; } penum->Release(); } psf->Release(); } ILFree(pidl); } // Check other MRU registry keys if (!bAreDocs) { int i; for (i = 0; i < ARRAYSIZE(c_szRegMruKeysToDelete); i++) { HKEY hkey; // ALL_ACCESS to delete c_szRegMruKeysToDelete. 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 pszFolder, LPTSTR pszKey, IShellFolder* psf) { LPITEMIDLIST pidl; DWORD cbEaten; DWORD dwAttrib; if (SUCCEEDED(psf->ParseDisplayName(NULL, NULL, pszFolder, &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_SERVER, 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: { pAdv->pTO->WalkTree(WALK_TREE_DELETE); ATOMICRELEASE(pAdv->pTO); // 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); }