321 lines
10 KiB
C++
321 lines
10 KiB
C++
//---------------------------------------------------------------------------
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
|