Windows2000/private/shell/applets/smtidy/smwiz.c
2020-09-30 17:12:32 +02:00

461 lines
12 KiB
C

#include "smtidy.h"
#include "smwiz.h"
#include "resource.h"
#include "util.h"
#include "killactv.h"
#include "finish.h"
#define POINTS_PER_INCH 72
DWORD GetOriginalTargetAttribs(IShellLink *psl)
{
DWORD dwRet = 0;
WIN32_FIND_DATA fd;
if (SUCCEEDED(psl->lpVtbl->GetPath(psl, NULL, 0, &fd, 0)))
dwRet = fd.dwFileAttributes;
return dwRet;
}
// Given a pidl for a link, extract the appropriate info and append it to
// the app list.
void SMIList_AppendItem(PSMTIDYINFO psmti, PIDL pidlFolder, PIDL pidlItem, DWORD dwFlags)
{
TCHAR szPath[MAX_PATH];
WCHAR wszPath[MAX_PATH];
SMITEM smi;
PIDL pidl;
Assert(psmti->hdsaSMI);
Assert(pidlFolder);
Assert(pidlItem);
Assert(psmti->psl);
Assert(psmti->ppf);
pidl = ILCombine(pidlFolder, pidlItem);
memset(&smi, 0, SIZEOF(smi));
smi.dwFlags = dwFlags;
smi.pidlItem = pidl;
SHGetPathFromIDList(pidl, szPath);
STRTOOLESTR(wszPath, szPath);
if (SUCCEEDED(psmti->ppf->lpVtbl->Load(psmti->ppf, wszPath, 0)))
{
PIDL pidlTarget;
if (SUCCEEDED(psmti->psl->lpVtbl->GetIDList(psmti->psl, &pidlTarget)))
{
SHGetPathFromIDList(pidlTarget, szPath);
if (*szPath)
{
Sz_AllocCopy(szPath, &smi.pszTarget);
smi.dwMatch = GetOriginalTargetAttribs(psmti->psl) & FILE_ATTRIBUTE_DIRECTORY; // Needed for link tracking.
}
else
{
smi.dwFlags |= SMIF_TARGET_NOT_FILE;
}
}
}
DSA_AppendItem(psmti->hdsaSMI, &smi);
}
typedef BOOL (*PFNENUMFOLDERCALLBACK)(LPSHELLFOLDER psf, HWND hwndOwner, PIDL pidlFolder, PIDL pidlItem, LPVOID pv);
BOOL EnumFolder(HWND hwndOwner, PIDL pidlFolder, DWORD grfFlags, PFNENUMFOLDERCALLBACK pfn, LPVOID pv)
{
LPSHELLFOLDER psf;
LPSHELLFOLDER psfDesktop;
BOOL fRet = FALSE;
if (SUCCEEDED(ICoCreateInstance(&CLSID_ShellDesktop, &IID_IShellFolder, &psfDesktop)))
{
if (SUCCEEDED(psfDesktop->lpVtbl->BindToObject(psfDesktop, pidlFolder, NULL, &IID_IShellFolder, &psf)))
{
LPENUMIDLIST penum;
if (SUCCEEDED(psf->lpVtbl->EnumObjects(psf, hwndOwner, grfFlags, &penum)))
{
PIDL pidl;
UINT celt;
while (penum->lpVtbl->Next(penum, 1, &pidl, &celt)==NOERROR && celt==1)
{
if (!(*pfn)(psf, hwndOwner, pidlFolder, pidl, pv))
{
ILFree(pidl);
break;
}
ILFree(pidl);
}
fRet = TRUE;
penum->lpVtbl->Release(penum);
}
psf->lpVtbl->Release(psf);
}
psfDesktop->lpVtbl->Release(psfDesktop);
}
return fRet;
}
BOOL EnumFolder_Callback(LPSHELLFOLDER psf, HWND hwndOwner, PIDL pidlFolder,
PIDL pidlItem, LPVOID pv)
{
DWORD dwAttribs = SFGAO_LINK|SFGAO_FOLDER;
PSMTIDYINFO psmti = pv;
BOOL fRet = FALSE;
Assert(psmti);
if (SUCCEEDED(psf->lpVtbl->GetAttributesOf(psf, 1, &pidlItem, &dwAttribs)))
{
// Is it a folder?
if (dwAttribs & SFGAO_FOLDER)
{
PIDL pidlRecurse = ILCombine(pidlFolder, pidlItem);
SMIList_AppendItem(psmti, pidlFolder, pidlItem, SMIF_FOLDER);
// Recurse.
if (pidlRecurse)
{
EnumFolder(hwndOwner, pidlRecurse, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, EnumFolder_Callback, psmti);
ILFree(pidlRecurse);
}
}
else if (dwAttribs & SFGAO_LINK)
{
// Regular link, add it to the list.
SMIList_AppendItem(psmti, pidlFolder, /*psf,*/ pidlItem, SMIF_NONE);
}
fRet = TRUE;
}
return fRet;
}
BOOL SMIList_Build(PSMTIDYINFO psmti)
{
BOOL fRet = FALSE;
PIDL pidlStartmenu;
PIDL pidlPrograms;
Assert(psmti);
Assert(psmti->hdsaSMI);
// Build a DPA of pidls for each item.
Dbg(TEXT("smw.smt_ea: Enumerating everything..."));
pidlStartmenu = SHCloneSpecialIDList(NULL, CSIDL_STARTMENU, TRUE);
if (pidlStartmenu)
{
pidlPrograms = SHCloneSpecialIDList(NULL, CSIDL_PROGRAMS, TRUE);
if (pidlPrograms)
{
if (SUCCEEDED(ICoCreateInstance(&CLSID_ShellLink, &IID_IShellLink, &psmti->psl)))
{
if (SUCCEEDED(psmti->psl->lpVtbl->QueryInterface(psmti->psl, &IID_IPersistFile, &psmti->ppf)))
{
// Enum Startmenu.
EnumFolder(NULL, pidlStartmenu, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS,
EnumFolder_Callback, psmti);
// Is programs under the StartMenu?
if (!ILIsParent(pidlStartmenu, pidlPrograms, FALSE))
{
// Nope, enum it seperately.
EnumFolder(NULL, pidlPrograms, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS,
EnumFolder_Callback, psmti);
}
psmti->ppf->lpVtbl->Release(psmti->ppf);
psmti->ppf = NULL;
fRet = TRUE;
}
psmti->psl->lpVtbl->Release(psmti->psl);
psmti->psl = NULL;
}
ILFree(pidlPrograms);
}
ILFree(pidlStartmenu);
}
return fRet;
}
// REVIEW UNDONE IANEL - Allow these defaults to be overriden from the
// registry (preserve them their too).
void SetDefaultOptions(HWND hDlg, LPPROPSHEETPAGE pps)
{
UINT idPage = PtrToUlong(pps->pszTemplate);
switch (idPage)
{
case DLG_SMINTRO:
CheckDlgButton(hDlg, IDC_REMOVE_BROKEN_SHORTCUTS, BST_CHECKED);
CheckDlgButton(hDlg, IDC_REMOVE_EMPTY_FOLDERS, BST_CHECKED);
CheckDlgButton(hDlg, IDC_MOVE_SINGLE_ITEMS, BST_CHECKED);
break;
case DLG_GROUP_READMES:
CheckRadioButton(hDlg, IDC_REMOVE_READMES, IDC_LEAVE_READMES_ALONE, IDC_GROUP_READMES);
break;
case DLG_UNUSED_SHORTCUTS:
CheckRadioButton(hDlg, IDC_REMOVE_UNUSED_SHORTCUTS, IDC_LEAVE_UNUSED_SHORTCUTS_ALONE, IDC_GROUP_UNUSED_SHORTCUTS);
break;
}
}
void OnSetActive(HWND hDlg, LPPROPSHEETPAGE pps)
{
PSMTIDYINFO psmti = (PSMTIDYINFO) pps->lParam;
UINT idPage = PtrToUlong(pps->pszTemplate);
LRESULT lRes = 0;
Assert(psmti);
Assert(idPage);
if (psmti->hbmp)
SendMessage(GetDlgItem(hDlg, IDC_WIZBMP), STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)psmti->hbmp);
// Only show pages that actually apply.
switch (idPage)
{
case DLG_SMINTRO:
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_NEXT);
break;
case DLG_SMFINISH:
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_FINISH|PSWIZB_BACK);
break;
case DLG_GROUP_READMES:
case DLG_UNUSED_SHORTCUTS:
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_NEXT|PSWIZB_BACK);
break;
}
SetDlgMsgResult(hDlg, WM_NOTIFY, lRes);
}
void OnKillActive(HWND hDlg, LPPROPSHEETPAGE pps)
{
PSMTIDYINFO psmti = (PSMTIDYINFO) pps->lParam;
UINT idPage = PtrToUlong(pps->pszTemplate);
LRESULT lRes = 0;
Assert(psmti);
Assert(idPage);
switch (idPage)
{
case DLG_SMINTRO:
KillActiveLostTargets(psmti, hDlg);
KillActiveEmptyFolders(psmti, hDlg);
KillActiveSingleItemFolder(psmti, hDlg);
break;
case DLG_GROUP_READMES:
KillActiveGroupReadMes(psmti, hDlg);
break;
case DLG_UNUSED_SHORTCUTS:
KillActiveUnusedShortcuts(psmti, hDlg);
break;
}
}
BOOL OnWizNotify(HWND hDlg, LPPROPSHEETPAGE pps, NMHDR *pnm)
{
switch (pnm->code)
{
case PSN_SETACTIVE:
OnSetActive(hDlg, pps);
break;
case PSN_KILLACTIVE:
OnKillActive(hDlg, pps);
break;
case PSN_WIZFINISH:
OnKillActive(hDlg, pps); // Should apply the changes of current page
OnFinish(hDlg, pps);
// fall through
case PSN_WIZNEXT:
case PSN_WIZBACK:
case PSN_RESET:
SetDlgMsgResult(hDlg, WM_NOTIFY, 0);
return FALSE;
default:
return FALSE;
}
return TRUE;
}
typedef BOOL (*PFCFGSTART)(HWND, BOOL);
void CallAppWiz(HWND hDlg, BOOL bDelItems)
{
HANDLE hmodWiz = LoadLibrary(TEXT("AppWiz.Cpl"));
if (hmodWiz)
{
PFCFGSTART pfnCfgStart = (PFCFGSTART)GetProcAddress(hmodWiz, "ConfigStartMenu");
if (pfnCfgStart)
{
pfnCfgStart(hDlg, bDelItems);
}
FreeLibrary(hmodWiz);
}
}
void OnCommand(HWND hDlg, WORD cmd)
{
switch (cmd)
{
case IDHELP:
break;
case IDC_ADD_SHORTCUTS:
CallAppWiz(hDlg, FALSE);
break;
case IDC_REMOVE_SHORTCUTS:
CallAppWiz(hDlg, TRUE);
break;
}
}
void SetFonts(PSMTIDYINFO psmti, HWND hDlg)
{
HWND hwndTitle = GetDlgItem(hDlg, IDC_TITLE);
if (hwndTitle)
{
if (!psmti->hfontLarge)
{
HFONT hfont = (HFONT)SendMessage(hwndTitle, WM_GETFONT, 0, 0);
if (hfont)
{
LOGFONT lf;
if (GetObject(hfont, SIZEOF(lf), &lf))
{
HDC hdc = GetDC(NULL);
lf.lfHeight = -MulDiv(14, GetDeviceCaps(hdc, LOGPIXELSY), POINTS_PER_INCH );
// lf.lfWeight = FW_BOLD;
ReleaseDC(NULL, hdc);
psmti->hfontLarge = CreateFontIndirect(&lf);
}
}
}
if (psmti->hfontLarge)
SendMessage(hwndTitle, WM_SETFONT, (WPARAM)psmti->hfontLarge, 0);
}
}
INT_PTR CALLBACK SMTidyProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
LPPROPSHEETPAGE pps = (LPPROPSHEETPAGE)(GetWindowLongPtr(hDlg, DWLP_USER));
switch(msg)
{
case WM_INITDIALOG:
{
LPPROPSHEETPAGE pps = (LPPROPSHEETPAGE)lParam;
PSMTIDYINFO psmti = (PSMTIDYINFO)(pps->lParam);
Assert(pps);
SetWindowLongPtr(hDlg, DWLP_USER, lParam);
SetDefaultOptions(hDlg, pps);
SetFonts(psmti, hDlg);
SetWindowPos(GetParent(hDlg), NULL, psmti->rc.left, psmti->rc.top, 0, 0, SWP_NOSIZE|SWP_NOZORDER);
break;
}
case WM_NOTIFY:
{
NMHDR *pnm = (NMHDR*)lParam;
return OnWizNotify(hDlg, pps, pnm);
}
case WM_DESTROY:
case WM_HELP:
case WM_CONTEXTMENU:
break;
case WM_COMMAND:
OnCommand(hDlg, LOWORD(wParam));
break;
default:
return FALSE;
}
return TRUE;
}
#define CMAXPAGES 10
void PropertySheet_AddPage(LPPROPSHEETHEADER ppsh, UINT id, DLGPROC pfn, LPVOID pv)
{
PROPSHEETPAGE psp;
if (ppsh->nPages >= CMAXPAGES)
{
Dbg(TEXT("smt.ps_ap: Too many pages."));
Assert(0);
return;
}
psp.dwSize = sizeof(psp);
psp.dwFlags = PSP_DEFAULT;
psp.hInstance = g_hinstApp;
psp.pszTemplate = MAKEINTRESOURCE(id);
psp.pfnDlgProc = pfn;
psp.lParam = (LPARAM)pv;
ppsh->phpage[ppsh->nPages] = CreatePropertySheetPage(&psp);
if (ppsh->phpage[ppsh->nPages])
ppsh->nPages++;
}
// StartMenu wizard.
BOOL TidyStartMenuWizard(PSMTIDYINFO psmti)
{
HPROPSHEETPAGE rPages[CMAXPAGES];
PROPSHEETHEADER psh;
psh.pszCaption = NULL;
psh.nPages = 0;
psh.nStartPage = 0;
psh.dwSize = sizeof(psh);
psh.dwFlags = PSH_PROPTITLE | PSH_WIZARD | PSH_WIZARDHASFINISH;
psh.hwndParent = psmti->hwnd;
psh.hInstance = g_hinstApp;
psh.phpage = rPages;
PropertySheet_AddPage(&psh, DLG_SMINTRO, SMTidyProc, psmti);
PropertySheet_AddPage(&psh, DLG_UNUSED_SHORTCUTS, SMTidyProc, psmti);
PropertySheet_AddPage(&psh, DLG_GROUP_READMES, SMTidyProc, psmti);
PropertySheet_AddPage(&psh, DLG_SMFINISH, SMTidyProc, psmti);
PropertySheet(&psh);
return TRUE;
}