windows-nt/Source/XPSP1/NT/shell/cpls/appwzdui/tasks.cpp
2020-09-26 16:20:57 +08:00

322 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"
// Do not build this file if on Win9X or NT4
#ifndef DOWNLEVEL_PLATFORM
#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;
}
#endif //DOWNLEVEL_PLATFORM