//--------------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation // // File: tasks.cpp // App Management tasks running on the secondary thread // // History: // 2-26-98 by dli implemented CAppUemInfoTask //------------------------------------------------------------------------ #include "priv.h" #include "shguidp.h" #include "uemapp.h" #include "appsize.h" #include "findapp.h" #include "tasks.h" #include "slowfind.h" #include "dump.h" #include "util.h" // Utility function to get times used or last used time for "exe" files void ExtractExeInfo(LPCTSTR pszExe, PSLOWAPPINFO psai, BOOL bNoImageChange) { ASSERT(IS_VALID_STRING_PTR(pszExe, -1)); // Got to have a legal psai ASSERT(psai); // Get the "times used" info UEMINFO uei = {0}; uei.cbSize = SIZEOF(uei); uei.dwMask = UEIM_HIT; if (SUCCEEDED(UEMQueryEvent(&UEMIID_SHELL, UEME_RUNPATH, (WPARAM)-1, (LPARAM)pszExe, &uei))) { if (uei.cHit > psai->iTimesUsed) psai->iTimesUsed = uei.cHit; } // Get the most recent access time HANDLE hFile = CreateFile(pszExe, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL ); if( INVALID_HANDLE_VALUE != hFile ) { FILETIME ftCreate, ftAccessed, ftWrite; if (GetFileTime(hFile, &ftCreate, &ftAccessed, &ftWrite)) { // Is the creation and accessed dates identical, and is the // UEM's statistic useless? if (0 == CompareFileTime(&ftAccessed, &ftCreate) && 0 == psai->ftLastUsed.dwHighDateTime) { // Yes; then it doesn't look like anyone has used it psai->ftLastUsed.dwHighDateTime = NOTUSED_HIGHDATETIME; psai->ftLastUsed.dwLowDateTime = NOTUSED_LOWDATETIME; if (!bNoImageChange && (psai->pszImage == NULL)) SHStrDup(pszExe, &psai->pszImage); } else if (CompareFileTime(&ftAccessed, &psai->ftLastUsed) > 0) { // No; someone must have used this program psai->ftLastUsed = ftAccessed; if (!bNoImageChange) { // If there was an exe file for the icon, release that if (psai->pszImage) SHFree(psai->pszImage); // Set the icon image of this app to this exe's icon // because this exe is the most recently used one. SHStrDup(pszExe, &psai->pszImage); } } } CloseHandle(hFile); } } const static struct { LPTSTR szAppName; LPTSTR szExeName; } s_rgAppHacks[] = { { TEXT("Microsoft Office"), TEXT("msoffice.exe")}, }; //-------------------------------------------------------------------------------- // CAppInfoFinder class //-------------------------------------------------------------------------------- static const WCHAR sc_wszStarDotExe[] = L"*.exe"; // Use the TreeWalker to find the application "exe" file class CAppInfoFinder : public CAppFolderSize { public: CAppInfoFinder(PSLOWAPPINFO psai, BOOL fSize, LPCTSTR pszHintExe, BOOL fNoImageChange); // *** IShellTreeWalkerCallBack methods (override) *** STDMETHOD(FoundFile) (LPCWSTR pwszFolder, TREEWALKERSTATS *ptws, WIN32_FIND_DATAW * pwfd); HRESULT SearchInFolder(LPCTSTR pszFolder); protected: PSLOWAPPINFO _psai; BOOL _fComputeSize; // Compute size or not BOOL _fNoImageChange; // Do not change image from now on. TCHAR _szHintExe[MAX_PATH]; }; // constructor CAppInfoFinder::CAppInfoFinder(PSLOWAPPINFO psai, BOOL fSize, LPCTSTR pszHintExe, BOOL fNoImageChange) : _fComputeSize(fSize), _fNoImageChange(fNoImageChange), _psai(psai), CAppFolderSize(&psai->ullSize) { if (pszHintExe) { lstrcpyn(_szHintExe, pszHintExe, ARRAYSIZE(_szHintExe)); } } /*------------------------------------------------------------------------- Purpose: IShellTreeWalkerCallBack::FoundFile Extracts the exe info that we want if the given file matches an exe spec. The info is stored in the _psai member variable. */ HRESULT CAppInfoFinder::FoundFile(LPCWSTR pwszFile, TREEWALKERSTATS *ptws, WIN32_FIND_DATAW * pwfdw) { HRESULT hres = S_OK; ASSERT(IS_VALID_STRING_PTRW(pwszFile, -1)); if (PathMatchSpecW(pwfdw->cFileName, sc_wszStarDotExe)) { TCHAR szPath[MAX_PATH]; TraceMsg(TF_SLOWFIND, "Found Exe File: %s", pwszFile); SHUnicodeToTChar(pwszFile, szPath, ARRAYSIZE(szPath)); if (!PathIsSetup(szPath, 2)) { ExtractExeInfo(szPath, _psai, _fNoImageChange); if (_szHintExe[0] != TEXT('\0')) { // Does this exe match our app's Hint icon exe? if (!lstrcmpi(_szHintExe, PathFindFileName(szPath))) { // Yes, Bingo!! Use this icon. // If there was an exe file for the icon, release that if (_psai->pszImage) SHFree(_psai->pszImage); // Set the icon image of this app to this exe's icon SHStrDup(szPath, &_psai->pszImage); _fNoImageChange = TRUE; } } } } if (_fComputeSize) hres = CAppFolderSize::FoundFile(pwszFile, ptws, pwfdw); return hres; } /*------------------------------------------------------------------------- Purpose: Method to kick off the tree walk, starting at pszFolder. */ HRESULT CAppInfoFinder::SearchInFolder(LPCTSTR pszFolder) { HRESULT hres = E_FAIL; WCHAR wszDir[MAX_PATH]; SHTCharToUnicode(pszFolder, wszDir, SIZECHARS(wszDir)); if (_pstw) hres = _pstw->WalkTree(0, wszDir, NULL, 0, SAFECAST(this, IShellTreeWalkerCallBack *)); return hres; } //-------------------------------------------------------------------------------- // CAppInfoFinderSM class //-------------------------------------------------------------------------------- // Use the TreeWalker to find the application "exe" file class CAppInfoFinderSM : public CStartMenuAppFinder { public: CAppInfoFinderSM(LPCTSTR pszFullName, LPCTSTR pszShortName, PSLOWAPPINFO psai); // *** IShellTreeWalkerCallBack methods *** virtual STDMETHODIMP FoundFile(LPCWSTR pwszFolder, TREEWALKERSTATS *ptws, WIN32_FIND_DATAW * pwfd); protected: PSLOWAPPINFO _psai; TCHAR _szFakeFolder[MAX_PATH]; }; // constructor CAppInfoFinderSM::CAppInfoFinderSM(LPCTSTR pszFullName, LPCTSTR pszShortName, PSLOWAPPINFO psai) : _psai(psai),CStartMenuAppFinder(pszFullName, pszShortName, _szFakeFolder) { } /*------------------------------------------------------------------------- Purpose: IShellTreeWalkerCallBack::FoundFile Extracts the exe info that we want if the given file matches an exe spec. The info is stored in the _psai member variable. */ HRESULT CAppInfoFinderSM::FoundFile(LPCWSTR pwszFile, TREEWALKERSTATS *ptws, WIN32_FIND_DATAW * pwfd) { TCHAR szLnkFile[MAX_PATH]; ASSERT(IS_VALID_STRING_PTRW(pwszFile, -1)); SHUnicodeToTChar(pwszFile, szLnkFile, ARRAYSIZE(szLnkFile)); TraceMsg(TF_SLOWFIND, "CSMAF:Lnk %s -- %s %s", _pszFullName, szLnkFile); if (!_MatchSMLinkWithApp(szLnkFile)) return S_OK; TCHAR szTargetFile[MAX_PATH]; HRESULT hresT = GetShortcutTarget(szLnkFile, szTargetFile, ARRAYSIZE(szTargetFile)); if ((S_FALSE == hresT) || ((S_OK == hresT) && !PathIsRoot(szTargetFile) && !PathIsUnderWindows(szTargetFile) && !PathIsSetup(szTargetFile, 1))) { LPCTSTR pszName = PathFindFileName(szTargetFile); if (PathMatchSpec(pszName, sc_wszStarDotExe)) ExtractExeInfo(szTargetFile, _psai, FALSE); } return S_OK; } LPTSTR LookUpHintExes(LPCTSTR pszAppName, LPTSTR pszHintExe, DWORD cbHintExe) { // Open the reg key HKEY hkeyIconHints = NULL; LPTSTR pszRet = NULL; if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\App Management\\Icon Hints") , 0, KEY_READ, &hkeyIconHints)) { DWORD dwType; // Look up in the registry for this cpl name if ((ERROR_SUCCESS == SHQueryValueEx(hkeyIconHints, pszAppName, NULL, &dwType, pszHintExe, &cbHintExe)) && (dwType == REG_SZ)) { pszRet = pszHintExe; } RegCloseKey(hkeyIconHints); } return pszRet; } // use the tree walker to find the "exe" file for the application HRESULT FindAppInfo(LPCTSTR pszFolder, LPCTSTR pszFullName, LPCTSTR pszShortName, PSLOWAPPINFO psai, BOOL bChanged) { // If there is no output string, a folder and a name, we can't do anything ASSERT(IS_VALID_WRITE_PTR(psai, SLOWAPPINFO)); if (pszFolder) { // We only compute sizes for locally installed apps and apps installed // on fixed drives. Ex: On board or external hard drives. // We purposely not compute size for network apps, apps on the CD ROMs and so on BOOL bGetSize = bChanged && PathIsLocalAndFixed(pszFolder); TCHAR szHintExe[MAX_PATH]; LPTSTR pszHintExe = LookUpHintExes(pszFullName, szHintExe, SIZEOF(szHintExe)); CAppInfoFinder * paef = new CAppInfoFinder(psai, bGetSize, pszHintExe, !bChanged); if (paef) { if (SUCCEEDED(paef->Initialize())) paef->SearchInFolder(pszFolder); paef->Release(); } } if (bChanged) { CAppInfoFinderSM * paifsm = new CAppInfoFinderSM(pszFullName, pszShortName, psai); if (paifsm) { if (SUCCEEDED(paifsm->Initialize())) { TCHAR szStartMenu[MAX_PATH]; if (SHGetSpecialFolderPath(NULL, szStartMenu, CSIDL_COMMON_PROGRAMS, FALSE)) paifsm->SearchInFolder(szStartMenu); if (SHGetSpecialFolderPath(NULL, szStartMenu, CSIDL_PROGRAMS, FALSE)) paifsm->SearchInFolder(szStartMenu); } paifsm->Release(); } } return S_OK; }