|
|
//
// CleanupWiz.cpp
//
#include "CleanupWiz.h"
#include "resource.h"
#include "dblnul.h"
#include <windowsx.h> // for SetWindowFont
#include <varutil.h>
#include <commctrl.h>
#include <shlwapi.h>
#include <shguidp.h>
#include <ieguidp.h>
// UEM stuff: including this source file is the
// recommended way of using it in your project
// (see comments in the file itself for the reason)
#include "..\inc\uassist.cpp"
////////////////////////////////////////////
//
// Globals, constants, externs etc...
//
////////////////////////////////////////////
// none of these strings are ever localized, so it's safe to use them
const LPTSTR c_szRegStrSHELLFOLDERS = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"); const LPTSTR c_szRegStrDESKTOPNAMESPACE = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Desktop\\NameSpace"); const LPTSTR c_szRegStrPROFILELIST = TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList"); const LPTSTR c_szRegStrMSNCODES = TEXT("Software\\Microsoft\\MSN6\\Setup\\MSN\\Codes"); const LPTSTR c_szRegStrPATH_OCMANAGER = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Setup\\OC Manager\\Subcomponents"); const LPTSTR c_szRegStrWMP_PATH_SETUP = TEXT("Software\\Microsoft\\MediaPlayer\\Setup");
const LPTSTR c_szRegStrPROFILESDIR = TEXT("ProfilesDirectory"); const LPTSTR c_szRegStrALLUSERS = TEXT("AllUsersProfile"); const LPTSTR c_szRegStrDEFAULTUSER = TEXT("DefaultUserProfile"); const LPTSTR c_szRegStrDESKTOP = TEXT("Desktop"); const LPTSTR c_szRegStrMSN_IAONLY = TEXT("IAOnly"); const LPTSTR c_szDESKTOP_DIR = TEXT("Desktop"); // backup in case we can't get the localized version
const LPTSTR c_szRegStrIEACCESS = TEXT("IEAccess"); const LPTSTR c_szRegStrYES = TEXT("yes"); const LPTSTR c_szRegStrWMP_REGVALUE = TEXT("DesktopShortcut"); const LPTSTR c_szDEFAULT_USER = TEXT("Default User");
const LPTSTR c_szVAL_TIME = TEXT("Last used time"); const LPTSTR c_szVAL_DELTA_DAYS = TEXT("Days between clean up"); const LPTSTR c_szVAL_DONTRUN = TEXT("NoRun");
const LPTSTR c_szVALUE_STARTPANEL = TEXT("NewStartPanel"); const LPTSTR c_szVALUE_CLASSICMENU = TEXT("ClassicStartMenu");
const LPTSTR c_szOEM_TITLEVAL = TEXT("DesktopShortcutsFolderName"); const LPTSTR c_szOEM_DISABLE = TEXT("DesktopShortcutsCleanupDisable"); const LPTSTR c_szOEM_SEVENDAY_DISABLE = TEXT("OemDesktopCleanupDisable");
extern HINSTANCE g_hInst; STDMETHODIMP GetItemCLSID(IShellFolder2 *psf, LPCITEMIDLIST pidlLast, CLSID *pclsid);
//
// number of items to grow dsa by
//
const int c_GROWBYSIZE = 4;
//
// number of pages in the wizard
//
const int c_NUM_PAGES = 3;
//
// dialog prompt text length
//
const int c_MAX_PROMPT_TEXT = 1024; const int c_MAX_HEADER_LEN = 64; const int c_MAX_DATE_LEN = 40;
//
// file modified more than 60 days back is candidate for cleanup
// this value can be overriden by policy
//
const int c_NUMDAYSTODECAY = 60;
//
// Needed for hiding regitems
//
#define DEFINE_SCID(name, fmtid, pid) const SHCOLUMNID name = { fmtid, pid }
DEFINE_SCID(SCID_DESCRIPTIONID, PSGUID_SHELLDETAILS, PID_DESCRIPTIONID);
//
// pointer to member function typedef
//
typedef INT_PTR (STDMETHODCALLTYPE CCleanupWiz::* PCFC_DlgProcFn)(HWND, UINT, WPARAM, LPARAM);
//
// struct for helping us manage our dialog procs
//
typedef struct { CCleanupWiz * pcfc; PCFC_DlgProcFn pfnDlgProc; } DLGPROCINFO, *PDLGPROCINFO;
//
// enum for columns
//
typedef enum eColIndex { FC_COL_SHORTCUT, FC_COL_DATE };
//////////////////////////////////////////////////////
//
// iDays can be negative or positive, indicating time in the past or future
//
//
#define FTsPerDayOver1000 (10000*60*60*24) // we've got (1000 x 10,000) 100ns intervals per second
STDAPI_(void) GetFileTimeNDaysFromGivenTime(const FILETIME *pftGiven, FILETIME * pftReturn, int iDays) { __int64 i64 = *((__int64 *) pftGiven); i64 += Int32x32To64(iDays*1000,FTsPerDayOver1000); *pftReturn = *((FILETIME *) &i64); }
STDAPI_(void) GetFileTimeNDaysFromCurrentTime(FILETIME *pf, int iDays) { SYSTEMTIME st; FILETIME ftNow; GetLocalTime(&st); SystemTimeToFileTime(&st, &ftNow); GetFileTimeNDaysFromGivenTime(&ftNow, pf, iDays); }
/////////////////////////////////////////////////
//
//
// The CCleanupWiz class implementation
//
//
/////////////////////////////////////////////////
CCleanupWiz::CCleanupWiz(): _psf(NULL), _hdsaItems(NULL), _hTitleFont(NULL), _iDeltaDays(0), _dwCleanMode(CLEANUP_MODE_NORMAL) { INITCOMMONCONTROLSEX icce; icce.dwSize = sizeof(icce); icce.dwICC = ICC_LISTVIEW_CLASSES; _bInited = InitCommonControlsEx(&icce) && SUCCEEDED(SHGetDesktopFolder(&_psf)); };
CCleanupWiz::~CCleanupWiz() { _CleanUpDSA(); ATOMICRELEASE(_psf); };
STDMETHODIMP CCleanupWiz::Run(DWORD dwCleanMode, HWND hwndParent) { HRESULT hr; if (!_bInited) { hr = E_FAIL; } else { _dwCleanMode = dwCleanMode; if (CLEANUP_MODE_SILENT == _dwCleanMode) { hr = _RunSilent(); } else { hr = _RunInteractive(hwndParent); } }
return hr; }
STDMETHODIMP CCleanupWiz::_RunInteractive(HWND hwndParent) { HRESULT hr; _iDeltaDays = GetNumDaysBetweenCleanup();
if (_iDeltaDays < 0) { _iDeltaDays = c_NUMDAYSTODECAY; //initial default value
}
LoadString(g_hInst, IDS_ARCHIVEFOLDER, _szFolderName, MAX_PATH); // init the common control classes we need
hr = _LoadDesktopContents(); if (SUCCEEDED(hr)) { UINT cItems = DSA_GetItemCount(_hdsaItems); if (CLEANUP_MODE_NORMAL == _dwCleanMode) { if (cItems > 0) // if there are items, we want to notify and proceed only if the user wants us to.
{ hr = _ShowBalloonNotification(); } else { hr = S_FALSE; } } else { ASSERT(CLEANUP_MODE_ALL == _dwCleanMode); hr = S_OK; // run manually, we show everything
}
if (S_OK == hr) { _cItemsOnDesktop = cItems; hr = _InitializeAndLaunchWizard(hwndParent); }
_LogUsage(); // set registry values to indicate the last run time
} return hr; }
//
// Creates the property pages for the wizard and launches the wizard
//
//
STDMETHODIMP CCleanupWiz::_InitializeAndLaunchWizard(HWND hwndParent) { HRESULT hr = S_OK; DLGPROCINFO adpi[c_NUM_PAGES]; HPROPSHEETPAGE ahpsp[c_NUM_PAGES]; PROPSHEETPAGE psp = {0}; if (!_hTitleFont) { NONCLIENTMETRICS ncm = {0}; ncm.cbSize = sizeof(ncm); SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0); LOGFONT TitleLogFont = ncm.lfMessageFont; TitleLogFont.lfWeight = FW_BOLD;
TCHAR szFont[128]; LoadString(g_hInst, IDS_TITLELOGFONT, szFont, ARRAYSIZE(szFont)); if (SUCCEEDED(StringCchCopy(TitleLogFont.lfFaceName, ARRAYSIZE(TitleLogFont.lfFaceName), szFont))) { HDC hdc = GetDC(NULL); INT FontSize = 12; TitleLogFont.lfHeight = 0 - GetDeviceCaps(hdc, LOGPIXELSY) * FontSize / 72; _hTitleFont = CreateFontIndirect(&TitleLogFont); ReleaseDC(NULL, hdc); } } //
// Intro Page
//
adpi[0].pcfc = this; adpi[0].pfnDlgProc = &CCleanupWiz::_IntroPageDlgProc; psp.dwSize = sizeof(psp); psp.dwFlags = PSP_DEFAULT|PSP_HIDEHEADER; psp.hInstance = g_hInst; psp.lParam = (LPARAM) &adpi[0]; psp.pfnDlgProc = s_StubDlgProc; psp.pszTemplate = MAKEINTRESOURCE(IDD_INTRO); ahpsp[0] = CreatePropertySheetPage(&psp); //
// Choose files page
//
adpi[1].pcfc = this; adpi[1].pfnDlgProc = &CCleanupWiz::_ChooseFilesPageDlgProc; psp.hInstance = g_hInst; psp.dwFlags = PSP_DEFAULT|PSP_USEHEADERTITLE| PSP_USEHEADERSUBTITLE; psp.lParam = (LPARAM) &adpi[1]; psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_CHOOSEFILES); psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_CHOOSEFILES_INFO); psp.pszTemplate = MAKEINTRESOURCE(IDD_CHOOSEFILES); psp.pfnDlgProc = s_StubDlgProc; ahpsp[1] = CreatePropertySheetPage(&psp); //
// Completion Page
//
adpi[2].pcfc = this; adpi[2].pfnDlgProc = &CCleanupWiz::_FinishPageDlgProc; psp.dwFlags = PSP_DEFAULT|PSP_HIDEHEADER; psp.hInstance = g_hInst; psp.lParam = (LPARAM) &adpi[2]; psp.pfnDlgProc = s_StubDlgProc; psp.pszTemplate = MAKEINTRESOURCE(IDD_FINISH); ahpsp[2] = CreatePropertySheetPage(&psp); //
// The wizard property sheet
//
PROPSHEETHEADER psh = {0}; psh.dwSize = sizeof(psh); psh.hInstance = g_hInst; psh.hwndParent = hwndParent; psh.phpage = ahpsp; psh.dwFlags = PSH_WIZARD97|PSH_WATERMARK|PSH_HEADER; psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK); psh.pszbmHeader = MAKEINTRESOURCE(IDB_LOGO); psh.nStartPage = _cItemsOnDesktop ? 0 : c_NUM_PAGES - 1; // if there are no pages on desktop, start on final page
psh.nPages = c_NUM_PAGES; PropertySheet(&psh); return hr; }
//
// Pops up a balloon notification tip which asks the user
// if he wants to clean up the desktop.
//
// returns S_OK if user wants us to cleanup.
//
STDMETHODIMP CCleanupWiz::_ShowBalloonNotification() { IUserNotification *pun; HRESULT hr = CoCreateInstance(CLSID_UserNotification, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IUserNotification, &pun)); if (SUCCEEDED(hr)) { TCHAR szTitle[64], szMsg[256]; // we leave enough room for localization bloat
LoadString(g_hInst, IDS_NOTIFICATION_TITLE, szTitle, ARRAYSIZE(szTitle)); LoadString(g_hInst, IDS_NOTIFICATION_TEXT, szMsg, ARRAYSIZE(szMsg)); // these pun->Set functions can't fail...
pun->SetIconInfo(LoadIcon(g_hInst, MAKEINTRESOURCE(IDI_WIZ_ICON)), szTitle); pun->SetBalloonInfo(szTitle, szMsg, NIIF_WARNING); pun->SetBalloonRetry(20 * 1000, -1, 1); // try once, for 20 seconds
// returns S_OK if user wants to continue, ERROR_CANCELLED if timedout
// or canncelled otherwise.
hr = pun->Show(NULL, 0); // we don't support iquerycontinue, we will just wait
pun->Release(); } return hr; }
//
// Gets the list of items on the desktop that should be cleaned
//
// if dwCleanMode == CLEANUP_MODE_NORMAL, it only loads items which have not been used recently
// if dwCleanMode == CLEANUP_MODE_ALL, it loads all items on the desktop, marking those which have not been used recently
//
//
STDMETHODIMP CCleanupWiz::_LoadDesktopContents() { ASSERT(_psf); ASSERT((CLEANUP_MODE_ALL == _dwCleanMode) || (CLEANUP_MODE_NORMAL == _dwCleanMode)); IEnumIDList * ppenum; DWORD grfFlags = SHCONTF_NONFOLDERS; HRESULT hr = _psf->EnumObjects(NULL, grfFlags, &ppenum); if (SUCCEEDED(hr)) { _CleanUpDSA(); _hdsaItems = DSA_Create(sizeof(FOLDERITEMDATA), c_GROWBYSIZE); if (_hdsaItems) { ULONG celtFetched; FOLDERITEMDATA fid = {0}; hr = S_OK; while(SUCCEEDED(hr) && (S_OK == ppenum->Next(1,&fid.pidl, &celtFetched))) { if (_IsSupportedType(fid.pidl)) // only support links and regitems
{ // note, the call to _IsCandidateForRemoval also obtains the last
// used timestamp for the item
BOOL bShouldRemove = _IsCandidateForRemoval(fid.pidl, &fid.ftLastUsed); if ( (CLEANUP_MODE_ALL == _dwCleanMode) || bShouldRemove) { SHFILEINFO sfi = {0}; if (SHGetFileInfo((LPCTSTR) fid.pidl, 0, &sfi, sizeof(sfi), SHGFI_PIDL | SHGFI_DISPLAYNAME | SHGFI_ICON | SHGFI_SMALLICON )) { if (Str_SetPtr(&(fid.pszName), sfi.szDisplayName)) { fid.hIcon = sfi.hIcon; fid.bSelected = bShouldRemove; if (-1 != DSA_AppendItem(_hdsaItems, &fid)) { // All is well, the item has succesfully been added
// to the dsa, we zero out the fields so as not to
// free those resources now, they will be freed when the
// dsa is destroyed.
ZeroMemory(&fid, sizeof(fid)); continue; } else { hr = E_OUTOFMEMORY; } } } } } // Common cleanup path for various failure cases above,
// we did not add this item to the dsa, so cleanup now.
_CleanUpDSAItem(&fid); } //
// If we did not load any items into the dsa, we return S_FALSE
//
if (SUCCEEDED(hr)) { hr = DSA_GetItemCount(_hdsaItems) > 0 ? S_OK : S_FALSE; } } else { // we failed to allocate memory for the DSA
hr = E_OUTOFMEMORY; } ppenum->Release(); } return hr; }
//
// Gets the list of items on the desktop that should be cleaned
//
// if dwCleanMode == CLEANUP_MODE_SILENT, it loads all items on all desktops, marking them all
//
//
STDMETHODIMP CCleanupWiz::_LoadMergedDesktopContents() { ASSERT(_psf); IEnumIDList * ppenum; DWORD grfFlags = _dwCleanMode == CLEANUP_MODE_SILENT ? SHCONTF_FOLDERS | SHCONTF_NONFOLDERS: SHCONTF_NONFOLDERS; HRESULT hr = _psf->EnumObjects(NULL, grfFlags, &ppenum); if (SUCCEEDED(hr)) { _CleanUpDSA(); _hdsaItems = DSA_Create(sizeof(FOLDERITEMDATA), c_GROWBYSIZE); if (_hdsaItems) { ULONG celtFetched; FOLDERITEMDATA fid = {0}; hr = S_OK; while(SUCCEEDED(hr) && (S_OK == ppenum->Next(1,&fid.pidl, &celtFetched))) { if (_IsSupportedType(fid.pidl)) // only support links and regitems
{ // note, the call to _IsCandidateForRemoval also obtains the last
// used timestamp for the item
BOOL bShouldRemove = ((CLEANUP_MODE_SILENT == _dwCleanMode) || (_IsCandidateForRemoval(fid.pidl, &fid.ftLastUsed))); if ( (CLEANUP_MODE_ALL == _dwCleanMode) || bShouldRemove) { SHFILEINFO sfi = {0}; if (SHGetFileInfo((LPCTSTR) fid.pidl, 0, &sfi, sizeof(sfi), SHGFI_PIDL | SHGFI_DISPLAYNAME | SHGFI_ICON | SHGFI_SMALLICON )) { if (Str_SetPtr(&(fid.pszName), sfi.szDisplayName)) { fid.hIcon = sfi.hIcon; fid.bSelected = bShouldRemove; if (-1 != DSA_AppendItem(_hdsaItems, &fid)) { // All is well, the item has succesfully been added
// to the dsa, we zero out the fields so as not to
// free those resources now, they will be freed when the
// dsa is destroyed.
ZeroMemory(&fid, sizeof(fid)); continue; } else { hr = E_OUTOFMEMORY; } } } } } // Common cleanup path for various failure cases above,
// we did not add this item to the dsa, so cleanup now.
_CleanUpDSAItem(&fid); } //
// If we did not load any items into the dsa, we return S_FALSE
//
if (SUCCEEDED(hr)) { hr = DSA_GetItemCount(_hdsaItems) > 0 ? S_OK : S_FALSE; } } else { // we failed to allocate memory for the DSA
hr = E_OUTOFMEMORY; } ppenum->Release(); } return hr; }
//
// Expects the given pidl to be a link or regitem. Determines if it is a candidate for removal based
// on when was the last time it was used.
//
STDMETHODIMP_(BOOL) CCleanupWiz::_IsCandidateForRemoval(LPCITEMIDLIST pidl, FILETIME * pftLastUsed) { BOOL bRet = FALSE; // be conservative, if we do not know anything about the
// object we will not volunteer to remove it
int cHit = 0; TCHAR szName[MAX_PATH]; ASSERT(_psf); //
// we store UEM usage info for the regitems and links on the desktop
//
if (SUCCEEDED(DisplayNameOf(_psf, pidl, SHGDN_INFOLDER | SHGDN_FORPARSING, szName, ARRAYSIZE(szName)))) { if (SUCCEEDED(_GetUEMInfo(-1, (LPARAM) szName, &cHit, pftLastUsed))) { FILETIME ft; GetFileTimeNDaysFromCurrentTime(&ft, -_iDeltaDays); #ifdef DEBUG
SYSTEMTIME st; FileTimeToSystemTime(&ft, &st); #endif
bRet = (CompareFileTime(pftLastUsed, &ft) < 0); } } return bRet; }
STDMETHODIMP CCleanupWiz::_ShouldShow(IShellFolder* psf, LPCITEMIDLIST pidlFolder, LPCITEMIDLIST pidlItem) { HRESULT hr; IShellFolder2 *psf2; hr = psf->QueryInterface(IID_PPV_ARG(IShellFolder2, &psf2)); if (SUCCEEDED(hr)) { // Get the GUID in the pidl, which requires IShellFolder2.
CLSID guidItem; hr = GetItemCLSID(psf2, pidlItem, &guidItem); if (SUCCEEDED(hr)) { SHELLSTATE ss = {0}; SHGetSetSettings(&ss, SSF_STARTPANELON, FALSE); //See if the StartPanel is on!
TCHAR szRegPath[MAX_PATH]; //Get the proper registry path based on if StartPanel is ON/OFF
hr = StringCchPrintf(szRegPath, ARRAYSIZE(szRegPath), REGSTR_PATH_HIDDEN_DESKTOP_ICONS, (ss.fStartPanelOn ? c_szVALUE_STARTPANEL : c_szVALUE_CLASSICMENU)); if (SUCCEEDED(hr)) { //Convert the guid to a string
TCHAR szGuidValue[MAX_GUID_STRING_LEN]; SHStringFromGUID(guidItem, szGuidValue, ARRAYSIZE(szGuidValue)); //See if this item is turned off in the registry.
if (SHRegGetBoolUSValue(szRegPath, szGuidValue, FALSE, /* default */FALSE)) hr = S_FALSE; //They want to hide it; So, return S_FALSE.
if (SHRestricted(REST_NOMYCOMPUTERICON) && IsEqualCLSID(CLSID_MyComputer, guidItem)) hr = S_FALSE; } } psf2->Release(); } // if we fail for some reason, be generous and say that we should offer to clean this up
if (FAILED(hr)) { hr = S_OK; }
return hr; }
//
// Normal, All: We only support removing regitems and links from the desktop
// Silent: WE NEVER GET HERE FROM SILENT
//
STDMETHODIMP_(BOOL) CCleanupWiz::_IsSupportedType(LPCITEMIDLIST pidl) { ASSERT(_dwCleanMode != CLEANUP_MODE_SILENT); BOOL fRetVal = FALSE; eFILETYPE eType = _GetItemType(pidl); if (FC_TYPE_REGITEM == eType) // handle regitems
{ fRetVal = TRUE; if (S_OK != _ShouldShow(_psf, NULL, pidl)) // regitems must succeed _ShouldShow
{ fRetVal = FALSE; } else { IShellFolder2 *psf2; CLSID guidItem; if (SUCCEEDED(_psf->QueryInterface(IID_PPV_ARG(IShellFolder2, &psf2)))) // must not be one of the shell desktop items
{ if (SUCCEEDED(GetItemCLSID(psf2, pidl, &guidItem)) && (IsEqualCLSID(CLSID_MyComputer, guidItem) || IsEqualCLSID(CLSID_MyDocuments, guidItem) || IsEqualCLSID(CLSID_NetworkPlaces, guidItem) || IsEqualCLSID(CLSID_RecycleBin, guidItem))) { fRetVal = FALSE; } psf2->Release(); } } } else if (FC_TYPE_LINK == eType) // handle links
{ fRetVal = TRUE; TCHAR szName[MAX_PATH]; if (SUCCEEDED(SHGetNameAndFlags(pidl, SHGDN_INFOLDER | SHGDN_FORPARSING, szName, ARRAYSIZE(szName), NULL))) { if (!lstrcmp(szName, _szFolderName)) // must not be the folder we're cleaning things up to
{ fRetVal = FALSE; } } } return fRetVal; }
//
// Returns the type of the pidl.
// We are only interested in Links and Regitems, so we return FC_TYPE_OTHER for
// all other items.
//
STDMETHODIMP_(eFILETYPE) CCleanupWiz::_GetItemType(LPCITEMIDLIST pidl) { eFILETYPE eftVal = FC_TYPE_OTHER; TCHAR szName[MAX_PATH]; TCHAR szPath[MAX_PATH]; IShellLink *psl; ASSERT(_psf); if (FAILED(SHGetNameAndFlags(pidl, SHGDN_INFOLDER | SHGDN_FORPARSING, szName, ARRAYSIZE(szName), NULL))) { szName[0] = 0; } if (FAILED(SHGetNameAndFlags(pidl, SHGDN_FORPARSING, szPath, ARRAYSIZE(szPath), NULL))) { szPath[0] = 0; } if(_IsRegItemName(szName)) { eftVal = FC_TYPE_REGITEM; } else if (SUCCEEDED( _psf->GetUIObjectOf(NULL, 1, &pidl, IID_PPV_ARG_NULL(IShellLink, &psl)))) { eftVal = FC_TYPE_LINK; psl->Release(); } else if (PathIsDirectory(szPath)) { eftVal = FC_TYPE_FOLDER; } else { //
// Maybe this item is a kind of .{GUID} object we created to restore
// regitems. In that case we want to actually restore the regitem
// at this point by marking it as unhidden.
//
LPTSTR pszExt = PathFindExtension(szName); if (TEXT('.') == *pszExt // it is a file extension
&& lstrlen(++pszExt) == (GUIDSTR_MAX - 1) // AND the extension is of the right length
// note: GUIDSTR_MAX includes the terminating NULL
// while lstrlen does not, hence the expression
&& TEXT('{') == *pszExt) // AND looks like it is a guid...
{ // we most prob have a bonafide guid string
// pszExt now points to the beginning of the GUID string
TCHAR szGUIDName[ARRAYSIZE(TEXT("::")) + GUIDSTR_MAX]; // put it in the regitem SHGDN_FORPARSING name format, which is like
//
// "::{16B280C6-EE70-11D1-9066-00C04FD9189D}"
//
if (SUCCEEDED(StringCchPrintf(szGUIDName, ARRAYSIZE(szGUIDName), TEXT("::%s"), pszExt))) { LPITEMIDLIST pidlGUID; DWORD dwAttrib = SFGAO_NONENUMERATED; //
// get the pidl of the regitem, if this call succeeds, it means we do have
// a corresponding regitem in the desktop's namespace
//
if (SUCCEEDED(_psf->ParseDisplayName(NULL, NULL, szGUIDName, NULL, &pidlGUID, &dwAttrib))) { //
// check if the regitem is marked as hidden
//
if (dwAttrib & SFGAO_NONENUMERATED) { //
// One last check before we enable the regitem:
// Does the regitem have the same display name as the .CLSID file.
// In case the user has restored this .CLSID file and renamed it we will
// not attempt to restore the regitem as it may confuse the user.
//
TCHAR szNameRegItem[MAX_PATH]; if (SUCCEEDED((DisplayNameOf(_psf, pidl, SHGDN_NORMAL, szName, ARRAYSIZE(szName)))) && SUCCEEDED((DisplayNameOf(_psf, pidlGUID, SHGDN_NORMAL, szNameRegItem, ARRAYSIZE(szNameRegItem)))) && lstrcmp(szName, szNameRegItem) == 0) { if (SUCCEEDED(_HideRegPidl(pidlGUID, FALSE))) { // delete the file corresponding to the regitem
if (SUCCEEDED(DisplayNameOf(_psf, pidl, SHGDN_NORMAL | SHGDN_FORPARSING, szName, ARRAYSIZE(szName)))) { DeleteFile(szName); // too bad if we fail, we will just
// have two identical icons on the desktop
} //
// Log the current time as the last used time of the regitem.
// We just re-enabled this regitem but we do not have the
// usage info for the corresponding .{CLSID} which the user had
// been using so far. So we will be conservative and say that
// it was used right now, so that it does not become a candidate
// for removal soon. As this is a regitem that the user restored
// after the wizard removed it, so it is a fair assumption that
// the user has used it after restoring it and is not a candidate
// for cleanup right now.
//
UEMFireEvent(&UEMIID_SHELL, UEME_RUNPATH, UEMF_XEVENT, -1, (LPARAM)szGUIDName); } } } ILFree(pidlGUID); } } } } return eftVal; }
//
// Determines if a filename is that of a regitem
//
// a regitem's SHGDN_INFOLDER | SHGDN_FORPARSING name is always "::{someguid}"
//
// CDefview::_LogDesktopLinksAndRegitems() uses the same test to determine
// if a given pidl is a regitem. This case can lead to false positives if
// you have other items on the desktop which have infoder parsing names
// beginning with "::{", but as ':' is not presently allowed in filenames
// it should not be a problem.
//
STDMETHODIMP_(BOOL) CCleanupWiz::_IsRegItemName(LPTSTR pszName) { return (pszName[0] == TEXT(':') && pszName[1] == TEXT(':') && pszName[2] == TEXT('{')); }
STDMETHODIMP_(BOOL) CCleanupWiz::_CreateFakeRegItem(LPCTSTR pszDestPath, LPCTSTR pszName, LPCTSTR pszGUID) { BOOL fRetVal = FALSE; TCHAR szLinkName[MAX_PATH]; if (SUCCEEDED(StringCchCopy(szLinkName, ARRAYSIZE(szLinkName), pszDestPath)) && PathAppend(szLinkName, pszName) && SUCCEEDED(StringCchCat(szLinkName, ARRAYSIZE(szLinkName), TEXT("."))) && SUCCEEDED(StringCchCat(szLinkName, ARRAYSIZE(szLinkName), pszGUID))) { //
// We use the CREATE_ALWAYS flag so that if the file already exists
// in the Unused Desktop Files folder, we will go ahead and hide the
// regitem.
//
HANDLE hFile = CreateFile(szLinkName, 0, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile != INVALID_HANDLE_VALUE) { // we created/opened the shortcut, now hide the regitem and close
// the shortcut file
fRetVal = TRUE; CloseHandle(hFile); } } return fRetVal; }
//
// Given path to an exe, returns the UEM hit count and last used date for it
//
STDMETHODIMP CCleanupWiz::_GetUEMInfo(WPARAM wParam, LPARAM lParam, int * pcHit, FILETIME * pftLastUsed) { UEMINFO uei; uei.cbSize = sizeof(uei); uei.dwMask = UEIM_HIT | UEIM_FILETIME; HRESULT hr = UEMQueryEvent(&UEMIID_SHELL, UEME_RUNPATH, wParam, lParam, &uei); if (SUCCEEDED(hr)) { *pcHit = uei.cHit; *pftLastUsed = uei.ftExecute; } return hr; }
STDMETHODIMP_(BOOL) CCleanupWiz::_ShouldProcess() { BOOL fRetVal = FALSE; if (_dwCleanMode == CLEANUP_MODE_SILENT) { fRetVal = TRUE; } else { int cItems = DSA_GetItemCount(_hdsaItems); for (int i = 0; i < cItems; i++) { FOLDERITEMDATA * pfid = (FOLDERITEMDATA *) DSA_GetItemPtr(_hdsaItems, i); if (pfid && pfid->bSelected) { fRetVal = TRUE; break; } } } return fRetVal; }
//
// Process the list of items. At this point _hdsaItems only contains the
// items that the user wants to delete
//
STDMETHODIMP CCleanupWiz::_ProcessItems() { TCHAR szFolderLocation[MAX_PATH]; // desktop folder
HRESULT hr = S_OK; if (_ShouldProcess()) { LPITEMIDLIST pidlCommonDesktop = NULL; ASSERT(_psf); // use the archive folder on the desktop
if (CLEANUP_MODE_SILENT != _dwCleanMode) { hr = DisplayNameOf(_psf, NULL, SHGDN_FORPARSING, szFolderLocation, ARRAYSIZE(szFolderLocation)); } else // use the archive folder in Program Files
{ hr = SHGetFolderLocation(NULL, CSIDL_PROGRAM_FILES , NULL, 0, &pidlCommonDesktop); if (SUCCEEDED(hr)) { hr = DisplayNameOf(_psf, pidlCommonDesktop, SHGDN_FORPARSING, szFolderLocation, ARRAYSIZE(szFolderLocation)); } } if (SUCCEEDED(hr)) { ASSERTMSG(*_szFolderName, "Desktop Cleaner: Archive Folder Name not present"); // create the full path of the archive folder
TCHAR szFolderPath[MAX_PATH]; hr = StringCchCopy(szFolderPath, ARRAYSIZE(szFolderPath), szFolderLocation); if (SUCCEEDED(hr)) { if (!PathAppend(szFolderPath, _szFolderName)) { hr = E_FAIL; } else { //
// We have to make sure that this folder exists, as otherwise, if we try to move
// a single shortcut using SHFileOperation, that file will be renamed to the target
// name instead of being put in a folder with that name.
//
SECURITY_ATTRIBUTES sa; sa.nLength = sizeof (sa); sa.lpSecurityDescriptor = NULL; // we get the default attributes for this process
sa.bInheritHandle = FALSE; int iRetVal = SHCreateDirectoryEx(NULL, szFolderPath, &sa); if (ERROR_SUCCESS == iRetVal || ERROR_FILE_EXISTS == iRetVal || ERROR_ALREADY_EXISTS == iRetVal) { DblNulTermList dnSourceFiles; TCHAR szFileName[MAX_PATH + 1]; // to pad an extra null char for SHFileOpStruct
//
//
// now we can start on the files we need to move
//
int cItems = DSA_GetItemCount(_hdsaItems); for (int i = 0; i < cItems; i++) { FOLDERITEMDATA * pfid = (FOLDERITEMDATA *) DSA_GetItemPtr(_hdsaItems, i); if (pfid && (pfid->bSelected || _dwCleanMode == CLEANUP_MODE_SILENT) && SUCCEEDED(DisplayNameOf(_psf,pfid->pidl, SHGDN_FORPARSING, szFileName, ARRAYSIZE(szFileName) - 1))) { if (_IsRegItemName(szFileName)) { // if its a regitem, we create a "Item Name.{GUID}" file
// and mark the regitem as hidden.
//
if (_CreateFakeRegItem(szFolderPath, pfid->pszName, szFileName+2)) { _HideRegPidl(pfid->pidl, TRUE); } } else // not a regitem, will move it
{ dnSourceFiles.AddString(szFileName); } } } if (dnSourceFiles.Count() > 0) { DblNulTermList dnTargetFolder; dnTargetFolder.AddString(szFolderPath); SHFILEOPSTRUCT sfo; sfo.hwnd = NULL; sfo.wFunc = FO_MOVE; sfo.pFrom = (LPCTSTR) dnSourceFiles; sfo.pTo = (LPCTSTR) dnTargetFolder; sfo.fFlags = FOF_NORECURSION | FOF_NOCONFIRMMKDIR | FOF_ALLOWUNDO ; hr = SHFileOperation(&sfo); } SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH, (LPCVOID) szFolderPath, 0); SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH, (LPCVOID) szFolderLocation, 0); } else { // we failed to create the Unused Desktop Files folder
hr = E_FAIL; } } } } } return hr; }
////////////////////////////////////////////////////////
//
// DialogProcs
//
// TODO: test for accessibilty issues
//
////////////////////////////////////////////////////////
INT_PTR STDMETHODCALLTYPE CCleanupWiz::_IntroPageDlgProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam) { INT_PTR ipRet = FALSE; switch (wMsg) { case WM_INITDIALOG: { HWND hWnd = GetDlgItem(hDlg, IDC_TEXT_TITLE_WELCOME); if (_hTitleFont) { SetWindowFont(hWnd, _hTitleFont, TRUE); } } break; case WM_NOTIFY : { LPNMHDR lpnm = (LPNMHDR) lParam; switch (lpnm->code) { case PSN_SETACTIVE: PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_NEXT); break; } break; } } return ipRet; }
INT_PTR STDMETHODCALLTYPE CCleanupWiz::_ChooseFilesPageDlgProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam) { INT_PTR ipRet = FALSE; HWND hwLV = NULL; switch (wMsg) { case WM_INITDIALOG: _InitChoosePage(hDlg); ipRet = TRUE; break; case WM_NOTIFY : LPNMHDR lpnm = (LPNMHDR) lParam; switch (lpnm->code) { case PSN_SETACTIVE: PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_NEXT | PSWIZB_BACK); hwLV = GetDlgItem(hDlg, IDC_LV_PROMPT); _SetCheckedState(hwLV); break; case PSN_WIZNEXT: // remember the items the user selected
hwLV = GetDlgItem(hDlg, IDC_LV_PROMPT); _MarkSelectedItems(hwLV); break; case PSN_WIZBACK: // remember the items the user selected
hwLV = GetDlgItem(hDlg, IDC_LV_PROMPT); _MarkSelectedItems(hwLV); break; } break; } return ipRet; }
INT_PTR STDMETHODCALLTYPE CCleanupWiz::_FinishPageDlgProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam) { INT_PTR ipRet = FALSE; switch (wMsg) { case WM_INITDIALOG: _InitFinishPage(hDlg); ipRet = TRUE; break; case WM_NOTIFY : { LPNMHDR lpnm = (LPNMHDR) lParam; switch (lpnm->code) { case PSN_SETACTIVE: PropSheet_SetWizButtons(GetParent(hDlg), _cItemsOnDesktop ? PSWIZB_BACK | PSWIZB_FINISH : PSWIZB_FINISH); // selection can change so need to do this everytime you come to this page
_RefreshFinishPage(hDlg); break; case PSN_WIZFINISH: // process the items now
_ProcessItems(); break; } break; } } return ipRet; }
//
// stub dialog proc which redirects calls to the right dialog procs
//
INT_PTR CALLBACK CCleanupWiz::s_StubDlgProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam) { PDLGPROCINFO pInfo = (PDLGPROCINFO) GetWindowLongPtr(hDlg, DWLP_USER); if (WM_INITDIALOG == wMsg) { pInfo = (PDLGPROCINFO) ((LPPROPSHEETPAGE) lParam) -> lParam; SetWindowLongPtr(hDlg, DWLP_USER, (LPARAM) pInfo); } if (pInfo) { CCleanupWiz * pThis = pInfo->pcfc; PCFC_DlgProcFn pfn = pInfo->pfnDlgProc; return (pThis->*pfn)(hDlg, wMsg, wParam, lParam); } return FALSE; }
STDMETHODIMP CCleanupWiz::_InitListBox(HWND hWndListView) { ListView_SetExtendedListViewStyle(hWndListView, LVS_EX_SUBITEMIMAGES); //
// add the columns
//
LVCOLUMN lvcDate; TCHAR szDateHeader[c_MAX_HEADER_LEN]; lvcDate.mask = LVCF_SUBITEM | LVCF_WIDTH | LVCF_TEXT ; lvcDate.iSubItem = FC_COL_SHORTCUT; lvcDate.cx = 200; LoadString(g_hInst, IDS_HEADER_ITEM, szDateHeader, ARRAYSIZE(szDateHeader)); lvcDate.pszText = szDateHeader; ListView_InsertColumn(hWndListView, FC_COL_SHORTCUT, &lvcDate); lvcDate.mask = LVCF_SUBITEM | LVCF_FMT | LVCF_WIDTH | LVCF_TEXT ; lvcDate.iSubItem = FC_COL_DATE; lvcDate.fmt = LVCFMT_LEFT; lvcDate.cx = 1; LoadString(g_hInst, IDS_HEADER_DATE, szDateHeader, ARRAYSIZE(szDateHeader)); lvcDate.pszText = szDateHeader; ListView_InsertColumn(hWndListView, FC_COL_DATE, &lvcDate); ListView_SetColumnWidth(hWndListView, FC_COL_DATE, LVSCW_AUTOSIZE_USEHEADER); return S_OK; }
STDMETHODIMP CCleanupWiz::_InitChoosePage(HWND hDlg) { HWND hWndListView = GetDlgItem(hDlg, IDC_LV_PROMPT); _InitListBox(hWndListView); //
// add the images
//
HIMAGELIST hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_MASK | ILC_COLOR32 , c_GROWBYSIZE, c_GROWBYSIZE); int cItems = DSA_GetItemCount(_hdsaItems); for (int i = 0; i < cItems; i++) { FOLDERITEMDATA * pfid = (FOLDERITEMDATA *) DSA_GetItemPtr(_hdsaItems, i); if (pfid) { ImageList_AddIcon(hSmall, pfid->hIcon); } } ListView_SetImageList(hWndListView, hSmall, LVSIL_SMALL); //
// set the checkboxes style
//
ListView_SetExtendedListViewStyleEx(hWndListView, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES); _PopulateListView(hWndListView); return S_OK; }
STDMETHODIMP CCleanupWiz::_InitFinishPage(HWND hDlg) { HWND hWnd = GetDlgItem(hDlg, IDC_TEXT_TITLE_WELCOME); if (_hTitleFont) { SetWindowFont(hWnd, _hTitleFont, TRUE); } HIMAGELIST hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_MASK | ILC_COLOR32, c_GROWBYSIZE, c_GROWBYSIZE); int cItems = DSA_GetItemCount(_hdsaItems); for (int i = 0; i < cItems; i++) { FOLDERITEMDATA * pfid = (FOLDERITEMDATA *) DSA_GetItemPtr(_hdsaItems, i); if (pfid) { ImageList_AddIcon(hSmall, pfid->hIcon); } } ListView_SetImageList(GetDlgItem(hDlg, IDC_LV_INFORM), hSmall, LVSIL_SMALL); return S_OK; }
STDMETHODIMP CCleanupWiz::_RefreshFinishPage(HWND hDlg) { HRESULT hr; HWND hWndListView = GetDlgItem(hDlg, IDC_LV_INFORM); ListView_DeleteAllItems(hWndListView); int cMovedItems = _PopulateListViewFinish(hWndListView); // set the informative text to reflect how many items were moved
HWND hWnd = GetDlgItem(hDlg, IDC_TEXT_INFORM); TCHAR szDisplayText[c_MAX_PROMPT_TEXT]; ShowWindow(GetDlgItem(hDlg, IDC_LV_INFORM), BOOLIFY(cMovedItems)); ShowWindow(GetDlgItem(hDlg, IDC_TEXT_SHORTCUTS), BOOLIFY(cMovedItems)); ShowWindow(GetDlgItem(hDlg, IDC_TEXT_CHANGE), BOOLIFY(cMovedItems)); if ( 0 == cMovedItems) { LoadString(g_hInst, _cItemsOnDesktop ? IDS_INFORM_NONE : IDS_INFORM_NONEFOUND, szDisplayText, ARRAYSIZE(szDisplayText)); hr = S_OK; } else if (1 == cMovedItems) { LoadString(g_hInst, IDS_INFORM_SINGLE, szDisplayText, ARRAYSIZE(szDisplayText)); hr = S_OK; } else { TCHAR szRawText[c_MAX_PROMPT_TEXT]; LoadString(g_hInst, IDS_INFORM, szRawText, ARRAYSIZE(szRawText)); hr = StringCchPrintf(szDisplayText, ARRAYSIZE(szDisplayText), szRawText, cMovedItems); } SetWindowText(hWnd, szDisplayText); return hr; }
STDMETHODIMP_(int) CCleanupWiz::_PopulateListView(HWND hWndListView) { LVITEM lvi = {0}; int cRet = 0; int cItems = DSA_GetItemCount(_hdsaItems); for (int i = 0; i < cItems; i++) { FOLDERITEMDATA * pfid = (FOLDERITEMDATA *) DSA_GetItemPtr(_hdsaItems, i); lvi.mask = LVIF_TEXT | LVIF_IMAGE; lvi.pszText = pfid->pszName; lvi.iImage = i; lvi.iItem = i; lvi.iSubItem = FC_COL_SHORTCUT; ListView_InsertItem(hWndListView, &lvi); cRet++; // set the last used date
TCHAR szDate[c_MAX_DATE_LEN]; if (SUCCEEDED(_GetDateFromFileTime(pfid->ftLastUsed, szDate, ARRAYSIZE(szDate)))) { ListView_SetItemText(hWndListView, i, FC_COL_DATE, szDate); } } return cRet; }
STDMETHODIMP_(int) CCleanupWiz::_PopulateListViewFinish(HWND hWndListView) { LVITEM lvi = {0}; lvi.mask = LVIF_TEXT | LVIF_IMAGE ; int cRet = 0; int cItems = DSA_GetItemCount(_hdsaItems); for (int i = 0; i < cItems; i++) { FOLDERITEMDATA * pfid = (FOLDERITEMDATA *) DSA_GetItemPtr(_hdsaItems, i); //
// it's the Finish Page, we only show the items we were asked to move
//
if (pfid && pfid->bSelected) { lvi.pszText = pfid->pszName; lvi.iImage = i; lvi.iItem = i; ListView_InsertItem(hWndListView, &lvi); cRet++; } } return cRet; }
//
// Converts a given FILETIME date into s displayable string
//
STDMETHODIMP CCleanupWiz::_GetDateFromFileTime(FILETIME ftLastUsed, LPTSTR pszDate, int cch ) { HRESULT hr; if (0 == ftLastUsed.dwHighDateTime && 0 == ftLastUsed.dwLowDateTime) { LoadString(g_hInst, IDS_NEVER, pszDate, cch); hr = S_OK; { hr = E_FAIL; } } else { DWORD dwFlags = FDTF_SHORTDATE; if (0 == SHFormatDateTime(&ftLastUsed, &dwFlags, pszDate, cch)) { hr = E_FAIL; } else { hr = S_OK; } } return hr; }
//
// Marks listview items as checked or unchecked
//
STDMETHODIMP CCleanupWiz::_SetCheckedState(HWND hWndListView) { int cItems = DSA_GetItemCount(_hdsaItems); for (int i = 0; i < cItems; i++) { FOLDERITEMDATA * pfid = (FOLDERITEMDATA *) DSA_GetItemPtr(_hdsaItems, i); if (pfid) { ListView_SetCheckState(hWndListView, i, pfid->bSelected); } } return S_OK; }
//
// Reverse of above, updates our list based on user selection.
//
STDMETHODIMP CCleanupWiz::_MarkSelectedItems(HWND hWndListView) { int cItems = ListView_GetItemCount(hWndListView); for (int iLV = 0; iLV < cItems; iLV++) { FOLDERITEMDATA * pfid = (FOLDERITEMDATA *) DSA_GetItemPtr(_hdsaItems, iLV); if (pfid) { pfid->bSelected = ListView_GetCheckState(hWndListView, iLV); } } return S_OK; }
//
// These methods clean up _hdsaItems and free the allocated memory
//
STDMETHODIMP_(void) CCleanupWiz::_CleanUpDSA() { if (_hdsaItems != NULL) { for (int i = DSA_GetItemCount(_hdsaItems)-1; i >= 0; i--) { FOLDERITEMDATA * pfid = (FOLDERITEMDATA *) DSA_GetItemPtr(_hdsaItems,i); if (pfid) { _CleanUpDSAItem(pfid); } } DSA_Destroy(_hdsaItems); _hdsaItems = NULL; } }
STDMETHODIMP CCleanupWiz::_CleanUpDSAItem(FOLDERITEMDATA * pfid) { if (pfid->pidl) { ILFree(pfid->pidl); } if (pfid->pszName) { Str_SetPtr(&(pfid->pszName), NULL); } if (pfid->hIcon) { DestroyIcon(pfid->hIcon); } ZeroMemory(pfid, sizeof(*pfid)); return S_OK; }
//////////////////////
//
// Hide regitems
//
//////////////////////
//
// Helper routines used below.
// Cloned from shell32/util.cpp
//
STDMETHODIMP GetItemCLSID(IShellFolder2 *psf, LPCITEMIDLIST pidlLast, CLSID *pclsid) { VARIANT var; HRESULT hr = psf->GetDetailsEx(pidlLast, &SCID_DESCRIPTIONID, &var); if (SUCCEEDED(hr)) { SHDESCRIPTIONID did; hr = VariantToBuffer(&var, (void *)&did, sizeof(did)); if (SUCCEEDED(hr)) *pclsid = did.clsid; VariantClear(&var); } return hr; }
//
// Given a regitem, it sets the SFGAO_NONENUMERATED bit on it so that
// that it no longer shows up in the folder.
//
// Since we are primarily only interested in cleaning up desktop clutter,
// that means we don't have to worry about all possible kinds of regitems.
// Our main target is apps like Outlook which create regitems instead of
// .lnk shortcuts. So our code does not have to be as complex as the
// regfldr.cpp version for deleting regitems, which has to account for
// everything, from legacy regitems to delegate folders.
//
//
STDMETHODIMP CCleanupWiz::_HideRegPidl(LPCITEMIDLIST pidlr, BOOL fHide) { IShellFolder2 *psf2; HRESULT hr = _psf->QueryInterface(IID_PPV_ARG(IShellFolder2, &psf2)); if (SUCCEEDED(hr)) { CLSID clsid; hr = GetItemCLSID(psf2, pidlr, &clsid); if (SUCCEEDED(hr)) { hr = _HideRegItem(&clsid, fHide, NULL); } psf2->Release(); } return hr; }
STDMETHODIMP CCleanupWiz::_HideRegItem(CLSID* pclsid, BOOL fHide, BOOL* pfWasVisible) { HKEY hkey; if (pfWasVisible) { *pfWasVisible = FALSE; } HRESULT hr = SHRegGetCLSIDKey(*pclsid, TEXT("ShellFolder"), FALSE, TRUE, &hkey); if(SUCCEEDED(hr)) { DWORD dwAttr, dwErr; DWORD dwType = 0; DWORD cbSize = sizeof(dwAttr); if (ERROR_SUCCESS == RegQueryValueEx(hkey, TEXT("Attributes"), NULL, &dwType, (BYTE *) &dwAttr, &cbSize)) { if (pfWasVisible) { *pfWasVisible = !(dwAttr & SFGAO_NONENUMERATED); } fHide ? dwAttr |= SFGAO_NONENUMERATED : dwAttr &= ~SFGAO_NONENUMERATED; } else { // attributes do not exist, so we will try creating them
fHide ? dwAttr = SFGAO_NONENUMERATED : dwAttr = 0; } dwErr = RegSetValueEx(hkey, TEXT("Attributes"), NULL, dwType, (BYTE *) &dwAttr, cbSize); hr = HRESULT_FROM_WIN32(dwErr); RegCloseKey(hkey); } return hr; }
//
// Method writes out the last used time in the registry and the
// number of days it was checkin for
//
STDMETHODIMP CCleanupWiz::_LogUsage() { FILETIME ft; SYSTEMTIME st; GetLocalTime(&st); SystemTimeToFileTime(&st, &ft); //
// we ignore if any of these calls fail, as we cannot really do anything
// in that case. the next time we run, we will run maybe sooner that expected.
//
SHRegSetUSValue(REGSTR_PATH_CLEANUPWIZ, c_szVAL_TIME, REG_BINARY, &ft, sizeof(ft), SHREGSET_FORCE_HKCU); SHRegSetUSValue(REGSTR_PATH_CLEANUPWIZ, c_szVAL_DELTA_DAYS, REG_DWORD,(DWORD *) &_iDeltaDays, sizeof(_iDeltaDays), SHREGSET_FORCE_HKCU); //
// TODO: also write out to log file here
//
return S_OK; }
//
// returns the current value from the policy key or the user settings
//
STDMETHODIMP_(int) CCleanupWiz::GetNumDaysBetweenCleanup() { DWORD dwData; DWORD dwType; DWORD cch = sizeof (DWORD); int iDays = -1; // if the value does not exist
//
// ISSUE-2000/12/01-AIDANL Removed REGSTR_POLICY_CLEANUP, don't think we need both, but want to
// leave this note in case issues come up later.
//
if (ERROR_SUCCESS == (SHRegGetUSValue(REGSTR_PATH_CLEANUPWIZ, c_szVAL_DELTA_DAYS, &dwType, &dwData, &cch,FALSE, NULL, 0))) { iDays = dwData; } return iDays; }
// helper functions
STDAPI_(BOOL) IsUserAGuest() { return SHTestTokenMembership(NULL, DOMAIN_ALIAS_RID_GUESTS); }
|