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

405 lines
13 KiB
C++

//---------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation
//
// File: slowfind.cpp
//
// Implements CProgFilesAppFinder
// CStartMenuAppFinder
// History:
// 3-01-98 by dli implemented CProgFilesAppFinder
// 4-15-98 by dli implemented CStartMenuAppFinder
//------------------------------------------------------------------------
#include "priv.h"
// Do not build this file if on Win9X or NT4
#ifndef DOWNLEVEL_PLATFORM
#include "appsize.h"
#include "findapp.h"
#include "slowfind.h"
// Todo: Remember the find result somewhere in the registry or cache it in code
// so that we don't waste time repeatedly computing it.
//
// App Folder Finder tree walker callback class
//
class CProgFilesAppFinder : public CAppFolderSize
{
friend BOOL SlowFindAppFolder(LPCTSTR pszFullName, LPCTSTR pszShortName, LPTSTR pszFolder);
public:
CProgFilesAppFinder(LPCTSTR pszFullName, LPCTSTR pszShortName, BOOL * pfFound, LPTSTR pszFolder);
// *** IShellTreeWalkerCallBack methods ***
virtual STDMETHODIMP EnterFolder(LPCWSTR pwszFolder, TREEWALKERSTATS *ptws, WIN32_FIND_DATAW * pwfd);
HRESULT SearchInFolder(LPCTSTR pszStart);
void SetRootSearch(BOOL bRootSearch);
protected:
LPCTSTR _pszFullName;
LPCTSTR _pszShortName;
// The Result
LPTSTR _pszFolder;
// Best match found
int _iBest;
int _iCurDepth;
// found it or not?
BOOL * _pfFound;
// are we searching from root dirs like c:?
BOOL _fRootSearch;
// system directory used by the root search
TCHAR _szSystemDir[MAX_PATH];
};
CProgFilesAppFinder::CProgFilesAppFinder(LPCTSTR pszFullName, LPCTSTR pszShortName, BOOL * pfFound, LPTSTR pszFolder) :
CAppFolderSize(NULL), _pszFullName(pszFullName), _pszShortName(pszShortName), _pfFound(pfFound), _pszFolder(pszFolder)
{
ASSERT(IS_VALID_STRING_PTR(pszFullName, -1) || IS_VALID_STRING_PTR(pszShortName, -1));
ASSERT(IS_VALID_STRING_PTR(pszFolder, -1));
ASSERT(pfFound);
ASSERT(*pfFound == FALSE);
ASSERT(_fRootSearch == FALSE);
}
void CProgFilesAppFinder::SetRootSearch(BOOL bRootSearch)
{
_fRootSearch = bRootSearch;
GetSystemDirectory(_szSystemDir, ARRAYSIZE(_szSystemDir));
}
//
// IShellTreeWalkerCallBack::EnterFolder
//
HRESULT CProgFilesAppFinder::EnterFolder(LPCWSTR pwszFolder, TREEWALKERSTATS *ptws, WIN32_FIND_DATAW * pwfd)
{
HRESULT hres = S_OK;
TCHAR szFolder[MAX_PATH];
ASSERT(IS_VALID_STRING_PTRW(pwszFolder, -1));
#ifdef UNICODE
lstrcpy(szFolder, pwszFolder);
#else
WideCharToMultiByte(CP_ACP, 0,
pwszFolder, -1,
szFolder, ARRAYSIZE(szFolder), NULL, NULL);
#endif
TraceMsg(TF_SLOWFIND, "Enter Folder: %s -- %s Depth %d", _pszFullName, szFolder, ptws->nDepth);
LPTSTR pszName = PathFindFileName(szFolder);
// Don't go into common files or where we already have seen
// FEATURE: These should be in the registry.
if (_fRootSearch)
{
if (!lstrcmpi(pszName, TEXT("Program Files")) || !lstrcmpi(pszName, TEXT("Windows")) ||
!lstrcmpi(pszName, TEXT("Temp")) || !lstrcmpi(pszName, TEXT("Users")) || StrStrI(pszName, TEXT("WINNT")) ||
!lstrcmpi(_szSystemDir, szFolder))
return S_FALSE;
}
else if (!lstrcmpi(pszName, TEXT("Common Files")) || !lstrcmpi(pszName, TEXT("Windows NT"))
|| !lstrcmpi(pszName, TEXT("Plus!")) || !lstrcmpi(pszName, TEXT("Uninstall Information")))
return S_FALSE;
if (pszName)
{
int iMatch = MatchAppName(pszName, _pszFullName, _pszShortName, TRUE);
// The deeper the match folder is down the tree, the better a match
// it is.
if ((iMatch > _iBest) || ((iMatch > 0) && (ptws->nDepth > _iCurDepth)))
{
_iBest = iMatch;
_iCurDepth = ptws->nDepth;
TraceMsg(TF_SLOWFIND, "Slow Match Found: %s -- %s Depth %d", _pszFullName, szFolder, _iCurDepth);
ASSERT(IS_VALID_STRING_PTR(_pszFolder, -1));
lstrcpy(_pszFolder, szFolder);
if (iMatch == MATCH_LEVEL_HIGH)
{
*_pfFound = TRUE;
hres = E_FAIL;
}
}
}
if (SUCCEEDED(hres))
hres = CAppFolderSize::EnterFolder(pwszFolder, ptws, pwfd);
return hres;
}
//
// Wrapper around WalkTree
//
HRESULT CProgFilesAppFinder::SearchInFolder(LPCTSTR pszStart)
{
HRESULT hres = E_FAIL;
WCHAR wszDir[MAX_PATH];
DWORD dwSearchFlags = WT_MAXDEPTH | WT_NOTIFYFOLDERENTER | WT_FOLDERONLY;
SHTCharToUnicode(pszStart, wszDir, SIZECHARS(wszDir));
if (_pstw)
hres = _pstw->WalkTree(dwSearchFlags, wszDir, NULL, MAX_PROGFILES_SEARCH_DEPTH, SAFECAST(this, IShellTreeWalkerCallBack *));
return hres;
}
CStartMenuAppFinder::CStartMenuAppFinder(LPCTSTR pszFullName, LPCTSTR pszShortName, LPTSTR pszFolder) :
CAppFolderSize(NULL), _pszFullName(pszFullName), _pszShortName(pszShortName), _pszFolder(pszFolder)
{
ASSERT(IS_VALID_STRING_PTR(pszFullName, -1) || IS_VALID_STRING_PTR(pszShortName, -1));
ASSERT(IS_VALID_STRING_PTR(pszFolder, -1));
}
//
// get the target of a shortcut.
//
// NOTE: pszPath is WCHAR string
//
HRESULT GetShortcutTarget(LPCWSTR pszLinkPath, LPTSTR pszTargetPath, UINT cchTargetPath)
{
IShellLink* psl;
HRESULT hres = E_FAIL;
HRESULT hresT = LoadFromFile(CLSID_ShellLink, pszLinkPath, IID_PPV_ARG(IShellLink, &psl));
if (SUCCEEDED(hresT))
{
IShellLinkDataList* psldl;
hresT = psl->QueryInterface(IID_PPV_ARG(IShellLinkDataList, &psldl));
if (SUCCEEDED(hresT))
{
EXP_DARWIN_LINK* pexpDarwin;
BOOL bDarwin = FALSE;
hresT = psldl->CopyDataBlock(EXP_DARWIN_ID_SIG, (void**)&pexpDarwin);
if (SUCCEEDED(hresT))
{
// This is a darwin link, so we return S_FALSE here.
LocalFree(pexpDarwin);
bDarwin = TRUE;
}
hresT = psl->GetPath(pszTargetPath, cchTargetPath, NULL, NULL);
if (hresT == S_OK)
{
// Return S_FALSE for the darwin apps.
hres = bDarwin ? S_FALSE : hresT;
}
psldl->Release();
}
psl->Release();
}
return hres;
}
//
// IShellTreeWalkerCallBack::EnterFolder
//
HRESULT CStartMenuAppFinder::EnterFolder(LPCWSTR pwszFolder, TREEWALKERSTATS *ptws, WIN32_FIND_DATAW * pwfd)
{
TCHAR szFolder[MAX_PATH];
ASSERT(IS_VALID_STRING_PTRW(pwszFolder, -1));
SHUnicodeToTChar(pwszFolder, szFolder, SIZECHARS(szFolder));
LPTSTR pszName = PathFindFileName(szFolder);
// Skip menus like the "Administrative Tools" and the "Accessories"
// FEATURE (scotth): these strings should be resourced-based
if (FindSubWord(pszName, TEXT("Administrative")) ||
FindSubWord(pszName, TEXT("Accessories")))
{
return S_FALSE;
}
return CAppFolderSize::EnterFolder(pwszFolder, ptws, pwfd);
}
/*-------------------------------------------------------------------------
Purpose: Checks if the given shortcut filename closely matches this
app's fullname or shortname. Returns TRUE if it does.
*/
BOOL CStartMenuAppFinder::_MatchSMLinkWithApp(LPCTSTR pszLnkFile)
{
TCHAR szLnkFile[MAX_PATH];
ASSERT(IS_VALID_STRING_PTR(pszLnkFile, -1));
lstrcpyn(szLnkFile, pszLnkFile, SIZECHARS(szLnkFile));
LPTSTR pszFileName = PathFindFileName(szLnkFile);
PathRemoveExtension(pszFileName);
if (MATCH_LEVEL_NORMAL <= MatchAppName(pszFileName, _pszFullName, _pszShortName, FALSE))
return TRUE;
PathRemoveFileSpec(szLnkFile);
LPTSTR pszDirName = PathFindFileName(szLnkFile);
if (MatchAppName(pszFileName, _pszFullName, _pszShortName, FALSE) >= MATCH_LEVEL_NORMAL)
return TRUE;
return FALSE;
}
//
// IShellTreeWalkerCallBack::FoundFile
//
HRESULT CStartMenuAppFinder::FoundFile(LPCWSTR pwszFile, TREEWALKERSTATS *ptws, WIN32_FIND_DATAW * pwfd)
{
HRESULT hres = S_OK;
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_FALSE;
TCHAR szTargetFile[MAX_PATH];
HRESULT hresT = GetShortcutTarget(pwszFile, szTargetFile, ARRAYSIZE(szTargetFile));
if (hresT == S_OK)
{
if(!PathIsRoot(szTargetFile) && !PathIsUnderWindows(szTargetFile) && !PathIsSetup(szTargetFile, 3)
&& !PathIsCommonFiles(szTargetFile))
{
TraceMsg(TF_SLOWFIND, "CSMAF:Target %s -- %s %s", _pszFullName, szTargetFile);
PathRemoveFileSpec(szTargetFile);
if (!PathIsRoot(szTargetFile))
{
int iMatch = FindBestMatch(szTargetFile, _pszFullName, _pszShortName, FALSE, _pszFolder);
// The deeper the match folder is down the tree, the better a match
// it is.
if (iMatch > _iBest)
{
_iBest = iMatch;
ASSERT(IS_VALID_STRING_PTR(_pszFolder, -1));
ASSERT(PathIsPrefix(_pszFolder, szTargetFile));
TraceMsg(TF_SLOWFIND, "CSMAF: Slow Match Found: %s -- %s", _pszFullName, szLnkFile);
if (iMatch == MATCH_LEVEL_HIGH)
hres = E_FAIL;
}
}
}
}
if (SUCCEEDED(hres))
hres = CAppFolderSize::FoundFile(pwszFile, ptws, pwfd);
return hres;
}
//
// Wrapper around WalkTree
//
HRESULT CStartMenuAppFinder::SearchInFolder(LPCTSTR pszStart)
{
HRESULT hres = E_FAIL;
DWORD dwSearchFlags = WT_MAXDEPTH | WT_NOTIFYFOLDERENTER | WT_FOLDERFIRST;
if (_pstw)
hres = _pstw->WalkTree(dwSearchFlags, pszStart, L"*.lnk", MAX_STARTMENU_SEARCH_DEPTH, SAFECAST(this, IShellTreeWalkerCallBack *));
return hres;
}
//
// NOTE: assuming pszFolder was allocated MAX_PATH long
// pszFolder will contain the result as return
//
BOOL SlowFindAppFolder(LPCTSTR pszFullName, LPCTSTR pszShortName, LPTSTR pszFolder)
{
ASSERT(IS_VALID_STRING_PTR(pszFolder, -1));
ASSERT(IS_VALID_STRING_PTR(pszFullName, -1) || IS_VALID_STRING_PTR(pszShortName, -1));
int iMatch = MATCH_LEVEL_NOMATCH;
// Search from the start menu
CStartMenuAppFinder * psmaf = new CStartMenuAppFinder(pszFullName, pszShortName, pszFolder);
if (psmaf)
{
if (SUCCEEDED(psmaf->Initialize()))
{
TCHAR szStartMenu[MAX_PATH];
if (SHGetSpecialFolderPath(NULL, szStartMenu, CSIDL_COMMON_STARTMENU, FALSE))
psmaf->SearchInFolder(szStartMenu);
if ((psmaf->_iBest == MATCH_LEVEL_NOMATCH) && (SHGetSpecialFolderPath(NULL, szStartMenu, CSIDL_STARTMENU, FALSE)))
psmaf->SearchInFolder(szStartMenu);
iMatch = psmaf->_iBest;
}
psmaf->Release();
}
if (iMatch == MATCH_LEVEL_NOMATCH)
{
BOOL fFound = FALSE;
// Start searching from stratch, no hints on where to start what so ever
CProgFilesAppFinder * psaff = new CProgFilesAppFinder(pszFullName, pszShortName, &fFound, pszFolder);
if (psaff)
{
if (SUCCEEDED(psaff->Initialize()))
{
// search down from "Program Files" directory under root of all fixed drives
TCHAR szDrive[4];
TCHAR szProgFiles[30];
lstrcpy(szDrive, TEXT("A:\\"));
lstrcpy(szProgFiles, TEXT("A:\\Program Files"));
for (; !fFound && szDrive[0] <= TEXT('Z'); szProgFiles[0]++, szDrive[0]++)
{
ASSERT(szDrive[0] == szProgFiles[0]);
if (GetDriveType(szDrive) == DRIVE_FIXED)
psaff->SearchInFolder(szProgFiles);
}
}
if (!fFound)
{
psaff->SetRootSearch(TRUE);
TCHAR szDrive[4];
lstrcpy(szDrive, TEXT("A:\\"));
for (; !fFound && szDrive[0] <= TEXT('Z'); szDrive[0]++)
{
if (GetDriveType(szDrive) == DRIVE_FIXED)
psaff->SearchInFolder(szDrive);
}
}
iMatch = psaff->_iBest;
psaff->Release();
}
if (iMatch > MATCH_LEVEL_NOMATCH)
TraceMsg(TF_ALWAYS, "CPFAF: Found %s at %s", pszFullName, pszFolder);
}
else
TraceMsg(TF_ALWAYS, "CSMAF: Found %s at %s", pszFullName, pszFolder);
return iMatch;
}
#endif //DOWNLEVEL_PLATFORM