Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1251 lines
33 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1993.
//
// File: thdcmds.cxx
//
// Contents: Derivatives of CCommand that implement the various search commands.
//
// Classes:
//
// Functions: TruncateFileName
// GetOULinkPaths
//
//
//
// History: 24-Sep-95 BillMo/MikeHi Created.
//
// Notes:
//
// Codework:
//
//--------------------------------------------------------------------------
#define NO_INCLUDE_UNION
#include "shellprv.h"
#pragma hdrstop
#ifdef ENABLE_TRACK
#include <olecairo.h>
#include "ids.h"
#include "CSafeStr.hxx"
#include "tracker.h"
#include "thdcmds.hxx"
HRESULT
SearchVolume(const TCHAR * ptszAncestor,
OBJECTID * poid,
WIN32_FIND_DATA * pfd);
BOOL
IsLocal(const TCHAR *pwszPath);
VOID
MakeRoot(TCHAR *ptszPath);
#define RELEASE_INTERFACE_POINTER( pInterface ) \
if( pInterface ) \
{ \
pInterface->Release(); \
pInterface = NULL; \
}
//+-------------------------------------------------------------------
//
// Function: TruncateFileName
//
// Synopsis: Take a complete filename (i.e. path included),
// and truncate the actual file name from it.
// For example, "C:\Directory\File.doc" becomes
// "C:\Directory". Note that "C:\Directory becomes "".
//
// Arguments: [pwszFileName]
// - The complete filename to be truncated.
// The truncated string is placed here.
//
// Returns: pwszFileName
//
// Algorithm: Find the last backslash, and set it to '\0'.
// If only a drive letter remains, the string is completely
// truncated.
//
// Signals: Nothing
//
// History: 13-Sep-95 MikeHill Created.
//
// Notes: None
//
//+-------------------------------------------------------------------
WCHAR * TruncateFileName( WCHAR * pwszFileName )
{
// ------
// Locals
// ------
WCHAR * pBackSlash = NULL;
// ---------------------
// Truncate the filename
// ---------------------
// Find the location of the last backslash.
// Does this need to be internationalized somehow?
if( pBackSlash = wcsrchr( pwszFileName, L'\\' ))
{
*pBackSlash = L'\0';
// If a portion of the filename remains, but it is only the drive
// letter, then the name can be considered completed truncated.
// I.e., "C:\Directory" becomes "", not "C:".
if( ( pBackSlash > pwszFileName ) // The string is non-empty.
&&
( *( pBackSlash - 1 ) == L':' ) // The string ends in ":"
)
{
*pwszFileName = L'\0'; // Return an empty string.
}
}// if( pBackSlash = wcrchr( ...
else
{
// There was no backslash in the filename, therefore the whole
// thing is truncated.
*pwszFileName = L'\0'; // Return an empty string.
}
// ------
// Return
// ------
return( pwszFileName );
} // TruncateFileName
//+-------------------------------------------------------------------
//
// Function: GetOULinkPaths
//
// Synopsis: Given a file's complete name, reduce it to
// the most specific OU, and get the ?? property
// from that OU. For example, if we are given
// "C:\Domain\OU1\OU2\Machine\Directory\File", we must
// return the ?? property (an array of BSTRs)
// from "C:\Domain\OU1\OU2".
//
// Arguments: [const TCHAR *] (unmodified)
// - The file name from which we'll extract an OU name.
//
// [CSafeStringVector *] (modified)
// - This object is initialized with a list of paths.
//
// Returns: [HRESULT]
//
// Algorithm: Extract the most specifiec OU name from the file name.
// Get an IDispatch for that OU.
// Get the ?? property.
//
// Signals: Nothing.
//
// History: 13-Sep-95 MikeHill Created.
//
// Notes: The caller is responsible for deleting the
// *ppszPaths (SAFEARRAY).
//
//+-------------------------------------------------------------------
HRESULT GetOULinkPaths( const TCHAR * ptszOriginalFileName,
CSafeStringVector* pcssvPaths )
{
// ------
// Locals
// ------
HRESULT hr = E_UNEXPECTED;
#if 0 // NOTYET
IMoniker* pIMoniker = NULL;
IUnknown* pIUnknown = NULL;
ILabelContainer* pILabelContainer = NULL;
IDispatch* pIDispatch = NULL;
// Make a copy of the original file name, since we're going
// to modify it.
WCHAR * pwszOUName = (WCHAR *) CoTaskMemAlloc( wcslen( pwszOriginalFileName ) * 2
+
SIZEOF( L'\0' ) );
if( !pwszOUName )
{
hr = E_UNEXPECTED; // ??
goto Exit;
}
else
{
wcscpy( pwszOUName, pwszOriginalFileName );
}
// ----------------------------------------
// Find the OU's name within the file name.
// ----------------------------------------
// Loop until we break (find the OU), or until there is nothing left of the path.
// At each iteration, the filename is shortened.
// E.g., "O:\Domain\OU\Machine\Directory\File" becomes "O:\Domain\OU\Machine\Directory".
// In this example, we'll break out of this loop when we find the string "O:\Domain\OU".
while( wcslen( TruncateFileName( pwszOUName ) ))
{
CLSID clsid;
// Get the class ID of the current OUName string.
// This will fail for machine and directory names.
if( SUCCEEDED( hr = SHXGetClassFile( pwszOUName, &clsid )))
{
if( IsEqualCLSID( clsid, CLSID_CDSFolder ))
{
// We've found the path to the OU.
break;
}
}
} // while( wcslen( TruncateFileName( pwszOUName ))
// ---------------------------
// Get an IDispatch for the OU
// ---------------------------
// Get a moniker for this OU.
if( FAILED( hr = CreateFileMoniker( pwszOUName, &pIMoniker )))
{
goto Exit;
}
// Bind the file moniker to get an IUnknown.
if( FAILED( hr = BindMoniker( pIMoniker,
0L,
IID_IUnknown,
(void **) &pIUnknown
) ) )
{
goto Exit;
}
// Get a label container.
if( FAILED( hr = pIUnknown->QueryInterface( IID_ILabelContainer,
(void **) &pILabelContainer
) ) )
{
goto Exit;
}
// Get an IDispatch.
if( FAILED( hr = pILabelContainer->GetLabel( IID_PSDomainConfiguration, //IID_PSDomainPolicy,
IID_IDispatch,
(IUnknown **) &pIDispatch
) ) )
{
goto Exit;
}
// -------------------
// Get the ?? Property
// -------------------
{ // Getting the ?? property
// Disp parameters (there are no arguments on a GetProperty)
DISPPARAMS dispparams = { NULL, NULL, 0, 0 };
VARIANT variant;
VariantInit( &variant );
EXCEPINFO excepinfo;
UINT iArgumentError;
if( FAILED( hr = pIDispatch->Invoke( PROPID_PSDomainConfiguration_DomainName, // ?? Property ID
IID_NULL, // ??
0, // Locale
DISPATCH_PROPERTYGET,
&dispparams,
&variant,
&excepinfo,
&iArgumentError
) ) )
{
goto Exit;
}
// Return the property to the caller.
pcssvPaths->InitFromSAFEARRAY( variant.parray );
hr = pcssvPaths->GetLastHResult();
} // Getting the ?? property
// ----
// Exit
// ----
Exit:
if( pwszOUName )
{
CoTaskMemFree( pwszOUName );
pwszOUName = NULL;
}
RELEASE_INTERFACE_POINTER( pIMoniker );
RELEASE_INTERFACE_POINTER( pIUnknown );
RELEASE_INTERFACE_POINTER( pILabelContainer );
RELEASE_INTERFACE_POINTER( pIDispatch );
#endif
return hr;
} // GetOULinkPaths
VOID
CTrackPool::_SetFound(CCommand *pCommand,
const WIN32_FIND_DATA *pfdNew,
const TCHAR *ptszFolder,
int iScore)
{
BOOL fPoolSucceeded = FALSE;
TakeResultMutex();
if (iScore > _iScore && // if the score is higher and ...
!fEventComplete() && // ... we havn't already set the main thread going and ...
(!fTerminatePool() || IsUiCommand(pCommand))) // threads are still searching or
// they're not searching but the ui is setting its result
{
_iScore = iScore;
_fdFound = *pfdNew;
if (ptszFolder != NULL)
PathCombine(_fdFound.cFileName, ptszFolder, pfdNew->cFileName);
if (_iScore >= MIN_NO_UI_SCORE)
{
fPoolSucceeded = TRUE;
TerminatePool();
}
}
DebugMsg(DM_TRACK, TEXT("CTrackPool::_SetFound() Better match found %s, %d, %s"),
_fdFound.cFileName,
_iScore,
_iScore >= MIN_NO_UI_SCORE ? TEXT("POOL TERMINATED") : TEXT("POOL NOT TERMINATED"));
ReleaseResultMutex();
if (fPoolSucceeded)
SetCompletionStatus(pCommand);
}
BOOL CTrackPool::StopSearchFromUI()
{
BOOL fStopped;
TakeResultMutex();
TerminatePool();
fStopped = !fEventComplete();
ReleaseResultMutex();
DebugMsg(DM_TRACK, TEXT("CTrackPool::StopSearchFromUI %s"),
fStopped ? TEXT("User browsed in time") : TEXT("User browsed too late"));
return(fStopped);
}
//+-------------------------------------------------------------------
//
// Member: CRegistryListCommand::DoCommand
//
// Synopsis: Read the given registry section multi-string and
// assign a command for each one to a CVolumeSearchCommand.
//
// Notes:
//
//--------------------------------------------------------------------
VOID
CRegistryListCommand::DoCommand()
{
HKEY hkey;
if (ERROR_SUCCESS == RegOpenKey(
HKEY_CURRENT_USER,
TEXT("SoftWare\\Microsoft\\LinkTrack"),
&hkey))
{
DWORD dwType;
BYTE abMultiStrings[4000];
DWORD cbData = SIZEOF(abMultiStrings);
if (ERROR_SUCCESS == RegQueryValueEx(
hkey, // handle of key to query
_ptszParam, // address of name of value to query
NULL, // reserved
&dwType, // address of buffer for value type
abMultiStrings, // address of data buffer
&cbData) && // address of data buffer size
dwType == REG_MULTI_SZ)
{
HRESULT hr = S_OK;
TCHAR *ptszBuf = (TCHAR *) abMultiStrings;
while (hr == S_OK && *ptszBuf != TEXT('\0'))
{
if (!IsLocal(ptszBuf))
{
CCommand *pCommand = new CVolumeSearchCommand(_pPool,
ptszBuf,
&hr);
if (hr == S_OK)
{
hr = _pPool->AssignCommandToThread(pCommand, 2);
}
else
{
delete pCommand;
}
}
ptszBuf += (lstrlen(ptszBuf) + 1);
}
}
RegCloseKey(hkey);
}
}
//+-------------------------------------------------------------------
//
// Member: COUListCommand::DoCommand
//
// Synopsis: Get the list of places to search from the OU object and
// create a volume search command for each.
//
// Notes:
//
//--------------------------------------------------------------------
VOID
COUListCommand::DoCommand()
{
#if 0 // NOTYET
CSafeStringVector cssv;
HRESULT hr;
hr = GetOULinkPaths( _ptszParam, &cssv );
for( long l = 0; hr == S_OK && l < cssv.GetCount(); l++ )
{
const TCHAR *pwszVol = cssv.GetString( l );
if (pwszVol != NULL)
{
CCommand *pCommand = new CVolumeSearchCommand(_pPool,
pwszVol,
&hr);
if (hr == S_OK)
{
hr = _pPool->AssignCommandToThread(pCommand, 2);
}
else
{
delete pCommand;
}
}
}
#endif
}
//+-------------------------------------------------------------------
//
// Member: CMappedDrivesCommand::DoCommand
//
// Synopsis: Get the list of places to search by enumerating
// drive letters and only using remote ones.
//
// Notes:
//
//--------------------------------------------------------------------
VOID
CMappedDrivesCommand::DoCommand()
{
HRESULT hr = S_OK;
TCHAR atszDrive[4];
atszDrive[0] = TEXT('A');
atszDrive[1] = TEXT(':');
atszDrive[2] = TEXT('\\');
atszDrive[3] = TEXT('\0');
for (; hr == S_OK && atszDrive[0] <= TEXT('Z'); atszDrive[0] ++)
{
if (GetDriveType(atszDrive) == DRIVE_REMOTE)
{
CCommand *pCommand = new CVolumeSearchCommand(_pPool,
atszDrive,
&hr);
if (hr == S_OK)
{
hr = _pPool->AssignCommandToThread(pCommand, 2);
}
else
{
delete pCommand;
}
}
}
}
//+-------------------------------------------------------------------
//
// Member: CVolumeSearchCommand::CVolumeSearchCommand
//
// Synopsis: Construct an object to search the specified volume.
//
// Notes:
//
//--------------------------------------------------------------------
CVolumeSearchCommand::CVolumeSearchCommand(CTrackPool *pPool,
const TCHAR *ptszVol,
HRESULT *phr) : CTrackCommand(pPool,
NULL,
phr)
{
ThdAssert(ptszVol != NULL);
int l = lstrlen(ptszVol);
BOOL fAddSlash = ptszVol[ l-1 ] != TEXT('\\');
ThdAssert(l != 0);
_ptszParam = (TCHAR*)LocalAlloc(LMEM_FIXED, SIZEOF(TCHAR)*(l + (fAddSlash ? 1 : 0) + 1));
if (_ptszParam != NULL)
{
lstrcpy(_ptszParam, ptszVol);
if (fAddSlash)
{
_ptszParam[l] = TEXT('\\');
_ptszParam[l+1] = TEXT('\0');
}
}
else
{
*phr = E_OUTOFMEMORY;
}
}
//+-------------------------------------------------------------------
//
// Member: CVolumeSearchCommand::DoCommand
//
// Synopsis: Search the given volume.
//
// Notes:
//
//--------------------------------------------------------------------
VOID
CVolumeSearchCommand::DoCommand()
{
WIN32_FIND_DATA fd;
if (S_OK == SearchVolume(_ptszParam, _pPool->GetObjectId(), &fd))
{
_pPool->SetFound(this, &fd, NULL, SCORE_OBJECTID_MATCH);
}
}
//+-------------------------------------------------------------------
//
// Member: CDownLevelCommand::CDownLevelCommand
//
// Synopsis: Create object to do downlevel search
//
// Notes:
//
//--------------------------------------------------------------------
CDownLevelCommand::CDownLevelCommand(CTrackPool *pPool,
const TCHAR *ptszParam,
HRESULT *phr) :
CTrackCommand(pPool,
ptszParam,
phr)
{
}
int
CDownLevelCommand::ScoreFindData(const TCHAR *pszDir)
{
int iScore = 0;
BOOL bSameName, bSameCreateDate, bSameWriteTime, bSameExt, bHasCreateDate;
bSameName = lstrcmpi(_pfdOrig->cFileName, _fdTemp.cFileName) == 0;
bSameExt = lstrcmpi(PathFindExtension(_pfdOrig->cFileName), PathFindExtension(_fdTemp.cFileName)) == 0;
bHasCreateDate = !IsNullTime(&_fdTemp.ftCreationTime);
bSameCreateDate = bHasCreateDate &&
(CompareFileTime(&_fdTemp.ftCreationTime, &_pfdOrig->ftCreationTime) == 0);
bSameWriteTime = !IsNullTime(&_fdTemp.ftLastWriteTime) &&
(CompareFileTime(&_fdTemp.ftLastWriteTime, &_pfdOrig->ftLastWriteTime) == 0);
if (bSameName || bSameCreateDate)
{
if (bSameName)
iScore += bHasCreateDate ? 16 : 32;
if (bSameCreateDate)
{
iScore += 32;
if (bSameExt)
iScore += 8;
}
if (bSameWriteTime)
iScore += 8;
if (_fdTemp.nFileSizeLow == _pfdOrig->nFileSizeLow)
iScore += 4;
// if it is in the same folder as the original give it a slight bonus
if (lstrcmpi(pszDir, _szSearchOrigin) == 0)
iScore += 2;
}
else
{
// doesn't have create date, apply different rules
if (bSameExt)
iScore += 8;
if (bSameWriteTime)
iScore += 8;
if (_fdTemp.nFileSizeLow == _pfdOrig->nFileSizeLow)
iScore += 4;
}
return iScore;
}
BOOL BeenThereDoneThat(LPCTSTR pszOriginal, LPCTSTR pszPath)
{
return PathCommonPrefix(pszOriginal, pszPath, NULL) == lstrlen(pszPath);
}
typedef struct _PATH_NODE {
struct _PATH_NODE *pNext;
int cDepth; // levels from top of search
// I choose to store this rather than use two lists for
// simplicity; even though using two lists would result
// in slightly less memory.
TCHAR szPath[1];
} PATH_NODE;
PATH_NODE *AllocPathNode(LPCTSTR pszStr)
{
PATH_NODE *p = (PATH_NODE*)LocalAlloc(LPTR, lstrlen(pszStr)*SIZEOF(TCHAR) + sizeof(PATH_NODE));
if (p)
lstrcpy(p->szPath, pszStr);
return p;
}
//+-------------------------------------------------------------------
//
// Member: CDownLevelCommand::SearchInFolder
//
// Synopsis: Breadth first search in the folder given by member _szWorkPath.
//
// Arguments: [cLevels] -- number of directory levels to search
// -1 is infinite.
// 0 is this directory only
// 1 is this directory + immediate children
//
// Returns: FALSE if search to be stopped.
//
// Notes:
//
//--------------------------------------------------------------------
BOOL
CDownLevelCommand::SearchInFolder(int cLevels)
{
PATH_NODE *pFree, *pFirst, *pLast; // list in FIFO order
// initial list of the one folder we want to look in
pLast = pFirst = AllocPathNode(_szWorkPath);
while (pFirst && fContinue())
{
TCHAR szPath[MAX_PATH];
HANDLE hfind;
PathCombine(szPath, pFirst->szPath, c_szStarDotStar);
hfind = FindFirstFile(szPath, &_fdTemp);
if (hfind != INVALID_HANDLE_VALUE)
{
do {
if (_fdTemp.cFileName[0] != TEXT('.'))
{
DWORD dwFind = _fdTemp.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
if (!(dwFind ^ _dwMatch) && !PathIsLink(_fdTemp.cFileName))
{
// both are files or folders, see how it scores
// store the score and fully qualified path
_pPool->SetFound(this, &_fdTemp, pFirst->szPath, ScoreFindData(pFirst->szPath));
}
if (_fdTemp.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
PathCombine(szPath, pFirst->szPath, _fdTemp.cFileName);
if (!BeenThereDoneThat(_szSearchOrigin, szPath) && !IsFileInBitBucket(szPath))
{
if (cLevels == -1 || pFirst->cDepth + 1 <= cLevels)
{
PATH_NODE *p = AllocPathNode(szPath);
if (p)
{
p->cDepth = pFirst->cDepth + 1;
pLast->pNext = p;
pLast = p;
}
}
}
}
}
} while (fContinue() && FindNextFile(hfind, &_fdTemp));
FindClose(hfind);
}
// remove the element we just searched from the list
// leaving other elements we may have added
// Assert(pFirst && pLast);
pFree = pFirst;
pFirst = pFirst->pNext;
// Assert(pFirst || pFree == pLast);
LocalFree(pFree);
}
// if we were canceled make sure we clean up
while (pFirst)
{
pFree = pFirst;
pFirst = pFirst->pNext;
LocalFree(pFree);
}
return(fContinue());
}
//+-------------------------------------------------------------------
//
// Member: CDownLevelCommand::DoCommand
//
// Synopsis: Search by creation date and name.
//
// Notes:
//
//--------------------------------------------------------------------
VOID
CDownLevelCommand::DoCommand()
{
BOOL fLocal;
_pfdOrig = _pPool->GetOrigFindData();
_dwMatch = _pfdOrig->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY; // must match bits
//
// find first extant parent directory
//
lstrcpy(_szSearchOrigin, _ptszParam);
PathRemoveFileSpec(_szSearchOrigin);
while (!PathIsDirectory(_szSearchOrigin))
{
if (PathIsRoot(_szSearchOrigin) || !PathRemoveFileSpec(_szSearchOrigin))
{
goto Ret;
}
}
//
// search up from old location
//
lstrcpy(_szWorkPath, _szSearchOrigin);
MakeRoot(_szWorkPath);
fLocal = IsLocal(_szWorkPath);
lstrcpy(_szWorkPath, _szSearchOrigin);
if (!(GetTrackFlags() & TRACK_LOCALONLY) || fLocal)
{
int cUp = LNKTRACK_HINTED_UPLEVELS;
while (cUp-- != 0 && SearchInFolder(LNKTRACK_HINTED_DOWNLEVELS))
{
if (PathIsRoot(_szWorkPath) || !PathRemoveFileSpec(_szWorkPath))
break;
}
}
if (fContinue())
{
LPITEMIDLIST pidl;
//
// search down from desktop
//
HRESULT hr = SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
if (hr == NOERROR)
{
if (SHGetPathFromIDList(pidl, _szWorkPath))
{
MakeRoot(_szWorkPath);
if (!(GetTrackFlags() & TRACK_LOCALONLY) || IsLocal(_szWorkPath))
{
SHGetPathFromIDList(pidl, _szWorkPath);
SearchInFolder(LNKTRACK_DESKTOP_DOWNLEVELS);
}
}
ILFree(pidl);
}
}
if (fContinue() && !(GetTrackFlags() & TRACK_LASTONLY))
{
//
// search down from root of fixed drives
//
lstrcpy(_szWorkPath, TEXT("C:\\"));
for (; fContinue() && _szWorkPath[0] <= TEXT('Z'); _szWorkPath[0]++)
{
if (GetDriveType(_szWorkPath) == DRIVE_FIXED)
{
SearchInFolder(LNKTRACK_ROOT_DOWNLEVELS);
}
}
}
if (fContinue())
{
//
// resume search of last volume (should do an exclude list)
//
lstrcpy(_szWorkPath, _szSearchOrigin);
if (!(GetTrackFlags() & TRACK_LOCALONLY) || fLocal)
{
while (SearchInFolder(-1))
{
if (PathIsRoot(_szWorkPath) || !PathRemoveFileSpec(_szWorkPath))
break;
}
}
}
Ret: ;
DebugMsg(DM_TRACK, TEXT("CDownlevelCommand::DoCommand completing"));
}
//+-------------------------------------------------------------------
//
// Member: CCancelWindowCommand::CCancelWindowCommand
//
// Synopsis: Initialize object for UI thread.
//
// Arguments: [pPool] -- pointer to thread pool
// [ptszParam] -- name of object to search for
// [ppcw] -- pointer to ICancelWindow implementation
// this pointer assumes the reference ownership
// by copying the pointer and zeroing it out.
// [phr] -- must set to failure on error
//
// Notes:
//
//--------------------------------------------------------------------
CCancelWindowCommand::CCancelWindowCommand(CTrackPool *pPool,
const TCHAR *ptszParam,
ICancelWindow **ppcw,
HRESULT *phr) : CTrackCommand(pPool, ptszParam, phr)
{
_pcw = *ppcw;
*ppcw = NULL;
}
CCancelWindowCommand::~CCancelWindowCommand()
{
delete _pcw;
}
//+-------------------------------------------------------------------
//
// Member: CCancelWindowCommand::DoCommand
//
// Synopsis: Put up the browse dialog.
//
// Returns: S_OK if path returned, E_FAIL otherwise.
//
// Algorithm:
//
// Notes: When this routine returns the thread pool will exit
//
//--------------------------------------------------------------------
VOID
CCancelWindowCommand::DoCommand()
{
WIN32_FIND_DATA fd;
int iScore = 0;
int id;
id = _pcw->DoCancelWindow(this, _ptszParam);
if (id == IDOK)
{
HANDLE hFind = FindFirstFile(_pcw->GetPath(), &fd);
if (hFind != INVALID_HANDLE_VALUE)
{
iScore = SCORE_USER_PROVIDED;
FindClose(hFind);
}
}
else
if (id == IDCANCEL)
{
iScore = SCORE_USER_CANCELLED;
}
if (iScore != 0)
_pPool->SetFound(this, &fd, NULL, iScore);
}
//+-------------------------------------------------------------------
//
// Member: CCancelWindowCommand::StopSearchFromUI
//
// Synopsis: Cancel the search as a result of cancel
//
// Returns: TRUE if search stopped, FALSE if too late to stop.
//
// Notes: This is called by the ui to determine whether or
// not it is too late to stop the search and if not
// stops the search.
//
//--------------------------------------------------------------------
BOOL
CCancelWindowCommand::StopSearchFromUI()
{
return _pPool->StopSearchFromUI();
}
//+-------------------------------------------------------------------
//
// Member: CCancelWindowCommand::CancelFromPool
//
// Synopsis: Called by a thread in the pool indicating it has
// found the object, or some other reason to cancel UI.
//
// Notes:
//
//--------------------------------------------------------------------
inline VOID CCancelWindowCommand::CancelFromPool()
{
_pcw->CancelCancelWindow();
}
//+-------------------------------------------------------------------
//
// Function: LinkFindDlgProc
//
// Synopsis: Does cancel dialog for shell shortcuts.
//
// Notes:
//
//--------------------------------------------------------------------
int CALLBACK LinkFindDlgProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
CCancelWindow *pcw = (CCancelWindow *)GetWindowLong(hDlg, DWL_USER);
switch (wMsg) {
case WM_INITDIALOG:
SetWindowLong(hDlg, DWL_USER, lParam);
pcw = (CCancelWindow *)lParam;
pcw->_hdlg = hDlg;
SetEvent(pcw->_hCreateDone);
{
DWORD idThread;
TCHAR szFmt[128];
TCHAR szTemp[MAX_PATH + ARRAYSIZE(szFmt)];
GetDlgItemText(hDlg, IDD_NAME, szFmt, ARRAYSIZE(szFmt));
wsprintf(szTemp, szFmt, PathFindFileName(pcw->_szFileName));
SetDlgItemText(hDlg, IDD_NAME, szTemp);
HWND hwndAni = GetDlgItem(hDlg, IDD_STATUS);
Animate_Open(hwndAni, MAKEINTRESOURCE(IDA_SEARCH)); // open the resource
Animate_Play(hwndAni, 0, -1, -1); // play from start to finish and repeat
}
break;
case WM_COMMAND:
switch (GET_WM_COMMAND_ID(wParam, lParam)) {
case IDD_BROWSE:
Animate_Stop(GetDlgItem(hDlg, IDD_STATUS));
//
// this causes all other threads to stop searching
//
if (!pcw->_pStop->StopSearchFromUI())
{
wParam = IDNO;
}
else
if (GetFileNameFromBrowse(hDlg,
pcw->_szFileName,
ARRAYSIZE(pcw->_szFileName),
NULL,
NULL,
NULL,
NULL))
{
// In this successful case, the path is set and
// the dialog will end, returning to DoCancelWindow,
// which will then cause CTask::DoTask to set this as
// the successful command which will cause
// CThreadPool::WaitForSuccessOrCompletion to return.
wParam = IDOK;
}
else
{
// see cancel case below.
wParam = IDCANCEL;
}
EndDialog(hDlg, GET_WM_COMMAND_ID(wParam, lParam));
break;
case IDCANCEL:
//
// this causes all other threads to stop searching
// and for the Ui command to return into DoCancelWindow
// which then will cause this thread to exit without
// calling SetCompletionStatus.
//
// this will then cause the pool to terminate without
// having set a successful command and thus the search
// is cancelled.
//
pcw->_pStop->StopSearchFromUI();
case IDNO:
EndDialog(hDlg, GET_WM_COMMAND_ID(wParam, lParam));
break;
}
break;
default:
return FALSE;
}
return TRUE;
}
//+-------------------------------------------------------------------
//
// Member: CCancelWindow::CCancelWindow
//
// Synopsis: Initializes the object. Does not create a window yet.
//
// Notes: We can't create the window in one thread and then
// process the messages in another thread.
//
//--------------------------------------------------------------------
CCancelWindow::CCancelWindow(HWND hwndOwner, HRESULT *phr)
: _hwndOwner(hwndOwner), _hdlg(NULL)
{
_hCreateDone = CreateEvent(NULL, TRUE, FALSE, NULL);
if (_hCreateDone != NULL)
{
*phr = S_OK;
}
// else *phr is already initialized to E_OUTOFMEMORY by caller.
}
CCancelWindow::~CCancelWindow()
{
if (_hCreateDone != NULL)
CloseHandle(_hCreateDone);
}
//+-------------------------------------------------------------------
//
// Member: CCancelWindow::DoCancelWindow
//
// Synopsis: Put up the cancel window, block in message pump.
//
// Arguments: [pStop] -- interface to callback on when window enters
// get file name dialog.
//
// Returns: IDOK -- got path
// IDCANCEL -- user cancelled
// IDNO -- CancelCancelWindow was called
// Notes:
//
//--------------------------------------------------------------------
int
CCancelWindow::DoCancelWindow(IStopSearchFromUI * pStop, const TCHAR *ptszFileName)
{
_pStop = pStop;
lstrcpy(_szFileName, ptszFileName);
int id = DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(DLG_LINK_SEARCH),
_hwndOwner,
LinkFindDlgProc,
(LPARAM)this);
// make sure the thread calling CancelCancelWindow gets to run.
SetEvent(_hCreateDone);
DebugMsg(DM_TRACK, TEXT("Dialog returns ID=%d"), id);
return(id);
}
//+-------------------------------------------------------------------
//
// Member: CCancelWindow::CancelCancelWindow
//
// Synopsis: Called by any thread to cancel the cancel window.
//
// Notes: Called by CThreadPool::SetCompletionStatus via the
// special Ui command support when the thread pool job
// is being completed by another command.
//
//--------------------------------------------------------------------
VOID
CCancelWindow::CancelCancelWindow()
{
// make sure _hdlg is valid by waiting until WM_INITDIALOG has been
// called (or in failure case when DialogBoxParam fails the handle may
// be NULL.) There is a minute chance that after the WM_INITDIALOG has
// assigned the handle that the DialogBoxParam fails and then reuses
// the handle for something else... oh well.
WaitForSingleObject(_hCreateDone, INFINITE);
if (_hdlg != NULL)
{
DebugMsg(DM_TRACK, TEXT("Posting IDNO to dialog"));
if (PostMessage(_hdlg, WM_COMMAND, IDNO, 0))
_hdlg = NULL;
}
}
//+-------------------------------------------------------------------
//
// Member: CCancelWindow::GetPath
//
// Synopsis: Get the path after DoCancelWindow returns S_OK
//
//--------------------------------------------------------------------
const TCHAR *
CCancelWindow::GetPath()
{
return(_szFileName);
}
#endif