|
|
//---------------------------------------------------------------------------
//
// 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"
#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));
StringCchCopy(szFolder, ARRAYSIZE(szFolder), pwszFolder);
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]; StringCchCopy(szDrive, ARRAYSIZE(szDrive), TEXT("A:\\")); StringCchCopy(szProgFiles, ARRAYSIZE(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]; StringCchCopy(szDrive, ARRAYSIZE(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; }
|