smwiz.c
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 14k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. //----------------------------------------------------------------------------
  2. //
  3. //----------------------------------------------------------------------------
  4. #include "smtidy.h"
  5. #include "smwiz.h"
  6. #include "resource.h"
  7. #include "util.h"
  8. #include "killactv.h"
  9. #include "finish.h"
  10. //---------------------------------------------------------------------------
  11. #define POINTS_PER_INCH      72
  12. //---------------------------------------------------------------------------
  13. DWORD GetOriginalTargetAttribs(IShellLink *psl)
  14. {
  15.     DWORD dwRet = 0;
  16.     WIN32_FIND_DATA fd;
  17.     
  18.     if (SUCCEEDED(psl->lpVtbl->GetPath(psl, NULL, 0, &fd, 0)))
  19.         dwRet = fd.dwFileAttributes;
  20.     return dwRet;
  21. }
  22. //---------------------------------------------------------------------------
  23. // Given a pidl for a link, extract the appropriate info and append it to 
  24. // the app list.
  25. void SMIList_AppendItem(PSMTIDYINFO psmti, PIDL pidlFolder, PIDL pidlItem, DWORD dwFlags)
  26. {
  27.     TCHAR szPath[MAX_PATH];
  28.     WCHAR wszPath[MAX_PATH];
  29.     SMITEM smi;
  30.     PIDL pidl;
  31.         
  32.     Assert(psmti->hdsaSMI);
  33.     Assert(pidlFolder);
  34.     Assert(pidlItem);
  35.     Assert(psmti->psl);
  36.     Assert(psmti->ppf);
  37.         
  38.     
  39.     pidl = ILCombine(pidlFolder, pidlItem);
  40.     
  41.     memset(&smi, 0, SIZEOF(smi));
  42.     smi.dwFlags = dwFlags;
  43.     smi.pidlItem = pidl;
  44.     
  45.     SHGetPathFromIDList(pidl, szPath);
  46.     STRTOOLESTR(wszPath, szPath);
  47.     if (SUCCEEDED(psmti->ppf->lpVtbl->Load(psmti->ppf, wszPath, 0)))
  48.     {
  49.         PIDL pidlTarget;
  50.         if (SUCCEEDED(psmti->psl->lpVtbl->GetIDList(psmti->psl, &pidlTarget)))
  51.         {
  52.             SHGetPathFromIDList(pidlTarget, szPath);
  53.             if (*szPath)
  54.             {
  55.                 Sz_AllocCopy(szPath, &smi.pszTarget);
  56.                 smi.dwMatch = GetOriginalTargetAttribs(psmti->psl) & FILE_ATTRIBUTE_DIRECTORY;    // Needed for link tracking.
  57.             }
  58.             else
  59.             {
  60.                 smi.dwFlags |= SMIF_TARGET_NOT_FILE;
  61.             }
  62.         }
  63.     }
  64.     DSA_AppendItem(psmti->hdsaSMI, &smi);
  65. }
  66. //----------------------------------------------------------------------------
  67. typedef BOOL (*PFNENUMFOLDERCALLBACK)(LPSHELLFOLDER psf, HWND hwndOwner, PIDL pidlFolder, PIDL pidlItem, LPVOID pv);
  68. //----------------------------------------------------------------------------
  69. BOOL EnumFolder(HWND hwndOwner, PIDL pidlFolder, DWORD grfFlags, PFNENUMFOLDERCALLBACK pfn, LPVOID pv)
  70. {
  71.     LPSHELLFOLDER psf;
  72.     LPSHELLFOLDER psfDesktop;
  73.     BOOL fRet = FALSE;
  74.     if (SUCCEEDED(ICoCreateInstance(&CLSID_ShellDesktop, &IID_IShellFolder, &psfDesktop)))
  75.     {
  76.         if (SUCCEEDED(psfDesktop->lpVtbl->BindToObject(psfDesktop, pidlFolder, NULL, &IID_IShellFolder, &psf)))
  77.         {
  78.             LPENUMIDLIST penum;
  79.             if (SUCCEEDED(psf->lpVtbl->EnumObjects(psf, hwndOwner, grfFlags, &penum)))
  80.             {
  81.                 PIDL pidl;
  82.                 UINT celt;
  83.                 while (penum->lpVtbl->Next(penum, 1, &pidl, &celt)==NOERROR && celt==1)
  84.                 {
  85.                     if (!(*pfn)(psf, hwndOwner, pidlFolder, pidl, pv))
  86.                     {
  87.                         ILFree(pidl);
  88.                         break;
  89.                     }
  90.                     ILFree(pidl);
  91.                 }
  92.                 fRet = TRUE;
  93.                 penum->lpVtbl->Release(penum);
  94.             }
  95.             psf->lpVtbl->Release(psf);
  96.         }
  97.         psfDesktop->lpVtbl->Release(psfDesktop);
  98.     }
  99.     
  100.     return fRet;
  101. }
  102. //----------------------------------------------------------------------------
  103. BOOL EnumFolder_Callback(LPSHELLFOLDER psf, HWND hwndOwner, PIDL pidlFolder, 
  104.     PIDL pidlItem, LPVOID pv)
  105. {
  106.     DWORD dwAttribs = SFGAO_LINK|SFGAO_FOLDER;
  107.     PSMTIDYINFO psmti = pv;
  108.     BOOL fRet = FALSE;
  109.     Assert(psmti);
  110.             
  111.     if (SUCCEEDED(psf->lpVtbl->GetAttributesOf(psf, 1, &pidlItem, &dwAttribs)))
  112.     {
  113.         // Is it a folder?
  114.         if (dwAttribs & SFGAO_FOLDER)
  115.         {
  116.             PIDL pidlRecurse = ILCombine(pidlFolder, pidlItem);
  117.             SMIList_AppendItem(psmti, pidlFolder, pidlItem, SMIF_FOLDER);
  118.             // Recurse.
  119.             if (pidlRecurse)
  120.             {
  121.                 EnumFolder(hwndOwner, pidlRecurse, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, EnumFolder_Callback, psmti);
  122.                 ILFree(pidlRecurse);
  123.             }
  124.         }
  125.         else if (dwAttribs & SFGAO_LINK)
  126.         {
  127.             // Regular link, add it to the list.
  128.             SMIList_AppendItem(psmti, pidlFolder, /*psf,*/ pidlItem, SMIF_NONE);
  129.         }
  130.         fRet = TRUE;
  131.     }
  132.     
  133.     return fRet;
  134. }
  135. //----------------------------------------------------------------------------
  136. BOOL SMIList_Build(PSMTIDYINFO psmti)
  137. {
  138.     BOOL fRet = FALSE;
  139.     PIDL pidlStartmenu;
  140.     PIDL pidlPrograms;
  141.     
  142.     Assert(psmti);
  143.     Assert(psmti->hdsaSMI);
  144.     
  145.     // Build a DPA of pidls for each item.
  146.     Dbg(TEXT("smw.smt_ea: Enumerating everything..."));
  147.     pidlStartmenu = SHCloneSpecialIDList(NULL, CSIDL_STARTMENU, TRUE);
  148.     if (pidlStartmenu)
  149.     {
  150.         pidlPrograms = SHCloneSpecialIDList(NULL, CSIDL_PROGRAMS, TRUE);
  151.         if (pidlPrograms)
  152.         {
  153.             if (SUCCEEDED(ICoCreateInstance(&CLSID_ShellLink, &IID_IShellLink, &psmti->psl)))
  154.             {
  155.                 if (SUCCEEDED(psmti->psl->lpVtbl->QueryInterface(psmti->psl, &IID_IPersistFile, &psmti->ppf)))
  156.                 {
  157.                     // Enum Startmenu.
  158.                     EnumFolder(NULL, pidlStartmenu, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, 
  159.                         EnumFolder_Callback, psmti);
  160.                     // Is programs under the StartMenu?
  161.                     if (!ILIsParent(pidlStartmenu, pidlPrograms, FALSE))
  162.                     {
  163.                         // Nope, enum it seperately.
  164.                         EnumFolder(NULL, pidlPrograms, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, 
  165.                             EnumFolder_Callback, psmti);
  166.                     }
  167.                     psmti->ppf->lpVtbl->Release(psmti->ppf);
  168.                     psmti->ppf = NULL;
  169.                     fRet = TRUE;
  170.                 }
  171.                 psmti->psl->lpVtbl->Release(psmti->psl);
  172.                 psmti->psl = NULL;
  173.             }
  174.             ILFree(pidlPrograms);
  175.         }
  176.         ILFree(pidlStartmenu);
  177.     }
  178.     return fRet;
  179. }
  180. //----------------------------------------------------------------------------
  181. // REVIEW UNDONE IANEL - Allow these defaults to be overriden from the
  182. // registry (preserve them their too).
  183. void SetDefaultOptions(HWND hDlg, LPPROPSHEETPAGE pps)
  184. {
  185.     UINT idPage = PtrToUlong(pps->pszTemplate);
  186.     switch (idPage)
  187.     {
  188.         case DLG_SMINTRO:
  189.             CheckDlgButton(hDlg, IDC_REMOVE_BROKEN_SHORTCUTS, BST_CHECKED);
  190.             CheckDlgButton(hDlg, IDC_REMOVE_EMPTY_FOLDERS, BST_CHECKED);
  191.             CheckDlgButton(hDlg, IDC_MOVE_SINGLE_ITEMS, BST_CHECKED);
  192.             break;        
  193.         case DLG_GROUP_READMES:
  194.             CheckRadioButton(hDlg, IDC_REMOVE_READMES, IDC_LEAVE_READMES_ALONE, IDC_GROUP_READMES);
  195.             break;
  196.         case DLG_UNUSED_SHORTCUTS:
  197.             CheckRadioButton(hDlg, IDC_REMOVE_UNUSED_SHORTCUTS, IDC_LEAVE_UNUSED_SHORTCUTS_ALONE, IDC_GROUP_UNUSED_SHORTCUTS);
  198.             break;
  199.     }
  200. }
  201. //----------------------------------------------------------------------------
  202. void OnSetActive(HWND hDlg, LPPROPSHEETPAGE pps)
  203. {
  204.     PSMTIDYINFO psmti = (PSMTIDYINFO) pps->lParam;
  205.     UINT idPage = PtrToUlong(pps->pszTemplate);
  206.     LRESULT lRes = 0;
  207.     
  208.     Assert(psmti);
  209.     Assert(idPage);
  210.     
  211.     if (psmti->hbmp)
  212.         SendMessage(GetDlgItem(hDlg, IDC_WIZBMP), STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)psmti->hbmp);
  213.     // Only show pages that actually apply.
  214.     switch (idPage)
  215.     {
  216.         case DLG_SMINTRO:
  217.             PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_NEXT);
  218.             break;
  219.         case DLG_SMFINISH:
  220.             PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_FINISH|PSWIZB_BACK);
  221.             break;
  222.         case DLG_GROUP_READMES:
  223.         case DLG_UNUSED_SHORTCUTS:
  224.             PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_NEXT|PSWIZB_BACK);
  225.             break;
  226.     }
  227.     SetDlgMsgResult(hDlg, WM_NOTIFY, lRes);
  228. }
  229. //----------------------------------------------------------------------------
  230. void OnKillActive(HWND hDlg, LPPROPSHEETPAGE pps)
  231. {
  232.     PSMTIDYINFO psmti = (PSMTIDYINFO) pps->lParam;
  233.     UINT idPage = PtrToUlong(pps->pszTemplate);
  234.     LRESULT lRes = 0;
  235.     
  236.     Assert(psmti);
  237.     Assert(idPage);
  238.     
  239.     switch (idPage)
  240.     {
  241.         case DLG_SMINTRO:
  242.             KillActiveLostTargets(psmti, hDlg);
  243.             KillActiveEmptyFolders(psmti, hDlg);
  244.             KillActiveSingleItemFolder(psmti, hDlg);
  245.             break;
  246.         case DLG_GROUP_READMES:
  247.             KillActiveGroupReadMes(psmti, hDlg);
  248.             break;
  249.         case DLG_UNUSED_SHORTCUTS:
  250.             KillActiveUnusedShortcuts(psmti, hDlg);
  251.             break;
  252.     }
  253. }
  254. //----------------------------------------------------------------------------
  255. BOOL OnWizNotify(HWND hDlg, LPPROPSHEETPAGE pps, NMHDR *pnm)
  256. {
  257.     switch (pnm->code)
  258.     {
  259.         case PSN_SETACTIVE:
  260.             OnSetActive(hDlg, pps);
  261.             break;
  262.         case PSN_KILLACTIVE:
  263.             OnKillActive(hDlg, pps);
  264.             break;
  265.         case PSN_WIZFINISH:
  266.             OnKillActive(hDlg, pps);    // Should apply the changes of current page
  267.             OnFinish(hDlg, pps);
  268.             // fall through
  269.         case PSN_WIZNEXT:
  270.         case PSN_WIZBACK:
  271.         case PSN_RESET:
  272.             SetDlgMsgResult(hDlg, WM_NOTIFY, 0);
  273.             return FALSE;
  274.         default:
  275.             return FALSE;
  276.     }
  277.     return TRUE;
  278. }
  279. //----------------------------------------------------------------------------
  280. typedef BOOL (*PFCFGSTART)(HWND, BOOL);
  281. //----------------------------------------------------------------------------
  282. void CallAppWiz(HWND hDlg, BOOL bDelItems)
  283. {
  284.     HANDLE hmodWiz = LoadLibrary(TEXT("AppWiz.Cpl"));
  285.     if (hmodWiz) 
  286.     {
  287.         PFCFGSTART pfnCfgStart = (PFCFGSTART)GetProcAddress(hmodWiz, "ConfigStartMenu");
  288.         if (pfnCfgStart) 
  289.         {
  290.             pfnCfgStart(hDlg, bDelItems);
  291.         }
  292.         FreeLibrary(hmodWiz);
  293.     }
  294. }
  295. //----------------------------------------------------------------------------
  296. void OnCommand(HWND hDlg, WORD cmd)
  297. {                        
  298.     switch (cmd) 
  299.     {
  300.         case IDHELP:
  301.             break;
  302.         case IDC_ADD_SHORTCUTS:
  303.             CallAppWiz(hDlg, FALSE);
  304.             break;
  305.         case IDC_REMOVE_SHORTCUTS:
  306.             CallAppWiz(hDlg, TRUE);
  307.             break;
  308.     }
  309. }
  310. //----------------------------------------------------------------------------
  311. void SetFonts(PSMTIDYINFO psmti, HWND hDlg)
  312. {
  313.     HWND hwndTitle = GetDlgItem(hDlg, IDC_TITLE);
  314.     if (hwndTitle)
  315.     {
  316.         if (!psmti->hfontLarge)
  317.         {
  318.             HFONT hfont = (HFONT)SendMessage(hwndTitle, WM_GETFONT, 0, 0);
  319.             if (hfont)
  320.             {
  321.                 LOGFONT lf;
  322.                 if (GetObject(hfont, SIZEOF(lf), &lf))
  323.                 {
  324.                     HDC hdc = GetDC(NULL);
  325.                     lf.lfHeight = -MulDiv(14, GetDeviceCaps(hdc, LOGPIXELSY), POINTS_PER_INCH );
  326.                     // lf.lfWeight = FW_BOLD;
  327.                     ReleaseDC(NULL, hdc);
  328.                     psmti->hfontLarge = CreateFontIndirect(&lf);
  329.                     
  330.                 }
  331.             }
  332.         }
  333.         
  334.         if (psmti->hfontLarge)
  335.             SendMessage(hwndTitle, WM_SETFONT, (WPARAM)psmti->hfontLarge, 0);
  336.     }
  337. }
  338. //----------------------------------------------------------------------------
  339. INT_PTR CALLBACK SMTidyProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  340. {
  341.     LPPROPSHEETPAGE pps = (LPPROPSHEETPAGE)(GetWindowLongPtr(hDlg, DWLP_USER));
  342.     
  343.     switch(msg) 
  344.     {
  345.         case WM_INITDIALOG:
  346.         {
  347.             LPPROPSHEETPAGE pps = (LPPROPSHEETPAGE)lParam;
  348.             PSMTIDYINFO psmti = (PSMTIDYINFO)(pps->lParam);
  349.             Assert(pps);
  350.             SetWindowLongPtr(hDlg, DWLP_USER, lParam);
  351.             SetDefaultOptions(hDlg, pps);
  352.             SetFonts(psmti, hDlg);
  353.             SetWindowPos(GetParent(hDlg), NULL,  psmti->rc.left, psmti->rc.top, 0, 0, SWP_NOSIZE|SWP_NOZORDER);
  354.             break;
  355.         }
  356.         
  357.         case WM_NOTIFY:
  358.         {
  359.             NMHDR *pnm = (NMHDR*)lParam;
  360.             return OnWizNotify(hDlg, pps, pnm);
  361.         }
  362.         
  363.         case WM_DESTROY:
  364.         case WM_HELP:
  365.         case WM_CONTEXTMENU:
  366.             break;
  367.         case WM_COMMAND:
  368.             OnCommand(hDlg, LOWORD(wParam));
  369.             break;
  370.         default:
  371.             return FALSE;
  372.     }
  373.     return TRUE;
  374. }
  375. //----------------------------------------------------------------------------
  376. #define CMAXPAGES  10
  377. //----------------------------------------------------------------------------
  378. void PropertySheet_AddPage(LPPROPSHEETHEADER ppsh, UINT id, DLGPROC pfn, LPVOID pv)
  379. {
  380.     PROPSHEETPAGE psp;
  381.     if (ppsh->nPages >= CMAXPAGES)
  382.     {
  383.         Dbg(TEXT("smt.ps_ap: Too many pages."));
  384.         Assert(0);
  385.         return;
  386.     }
  387.     
  388.     psp.dwSize = sizeof(psp);
  389.     psp.dwFlags = PSP_DEFAULT;
  390.     psp.hInstance = g_hinstApp;
  391.     psp.pszTemplate = MAKEINTRESOURCE(id);
  392.     psp.pfnDlgProc = pfn;
  393.     psp.lParam = (LPARAM)pv;
  394.     ppsh->phpage[ppsh->nPages] = CreatePropertySheetPage(&psp);
  395.     
  396.     if (ppsh->phpage[ppsh->nPages])
  397.         ppsh->nPages++;
  398. //----------------------------------------------------------------------------
  399. // StartMenu wizard.
  400. BOOL TidyStartMenuWizard(PSMTIDYINFO psmti)
  401. {
  402.     HPROPSHEETPAGE rPages[CMAXPAGES];
  403.     PROPSHEETHEADER psh;
  404.     
  405.     psh.pszCaption = NULL;
  406.     psh.nPages = 0;
  407.     psh.nStartPage = 0;
  408.     psh.dwSize = sizeof(psh);
  409.     psh.dwFlags = PSH_PROPTITLE | PSH_WIZARD | PSH_WIZARDHASFINISH;
  410.     psh.hwndParent = psmti->hwnd;
  411.     psh.hInstance = g_hinstApp;
  412.     psh.phpage = rPages;
  413.     PropertySheet_AddPage(&psh, DLG_SMINTRO, SMTidyProc, psmti);
  414.     PropertySheet_AddPage(&psh, DLG_UNUSED_SHORTCUTS, SMTidyProc, psmti);
  415.     PropertySheet_AddPage(&psh, DLG_GROUP_READMES, SMTidyProc, psmti);
  416.     PropertySheet_AddPage(&psh, DLG_SMFINISH, SMTidyProc, psmti);
  417.     
  418.     PropertySheet(&psh);
  419.     return TRUE;
  420. }