2418 lines
43 KiB
C++
2418 lines
43 KiB
C++
/*++
|
|
|
|
Copyright (C) Microsoft Corporation, 1998 - 1999
|
|
All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
findloc.cxx
|
|
|
|
Abstract:
|
|
|
|
This module provides all the functions for browsing the
|
|
physical location tree stored in an Active Directory
|
|
|
|
Author:
|
|
|
|
Lazar Ivanov (LazarI) 23-Nov-1998
|
|
Steve Kiraly (SteveKi) 24-Nov-1998
|
|
Lazar Ivanov (LazarI) Nov-28-2000 - redesign the tokenizer
|
|
Weihai Chen (WeihaiC) Mar-28-2001 - use DS search to enumerate location data
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.hxx"
|
|
#pragma hdrstop
|
|
|
|
#include "dsinterf.hxx"
|
|
#include "findloc.hxx"
|
|
#include "physloc.hxx"
|
|
|
|
enum
|
|
{
|
|
kDSIconIndex = 1,
|
|
};
|
|
|
|
/******************************************************************************
|
|
|
|
Utility functions
|
|
|
|
******************************************************************************/
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
vRecursiveGetSel
|
|
|
|
Description:
|
|
|
|
Finds the selecton string denoted by parent nodes
|
|
of the current treeview item, then appends
|
|
string of the current item
|
|
|
|
Arguments:
|
|
|
|
hTree - handle to treeview control
|
|
pItem - pointer to current item
|
|
strSel - reference to string to fill in
|
|
hStop - tree item to stop recursing
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Notes:
|
|
|
|
|
|
--*/
|
|
|
|
VOID
|
|
vRecursiveGetSel (
|
|
IN HWND hTree,
|
|
IN const TVITEM *pItem,
|
|
OUT TString &strSel,
|
|
IN HTREEITEM hStop
|
|
)
|
|
{
|
|
TVITEM tvParent;
|
|
TCHAR szItem[TPhysicalLocation::kMaxPhysicalLocation];
|
|
TStatusB bStatus;
|
|
|
|
tvParent.mask = TVIF_TEXT|TVIF_HANDLE;
|
|
tvParent.pszText = szItem;
|
|
tvParent.cchTextMax = TPhysicalLocation::kMaxPhysicalLocation;
|
|
|
|
//
|
|
// If we're at the root, init the string
|
|
//
|
|
if ((tvParent.hItem = TreeView_GetParent (hTree, pItem->hItem))==hStop)
|
|
{
|
|
bStatus DBGCHK = strSel.bUpdate (pItem->pszText);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Get the string denoted by my parent nodes, then append my string
|
|
//
|
|
TreeView_GetItem (hTree, &tvParent);
|
|
vRecursiveGetSel (hTree, &tvParent, strSel, hStop);
|
|
bStatus DBGCHK = strSel.bCat (pItem->pszText);
|
|
}
|
|
|
|
//
|
|
// Append a slash
|
|
//
|
|
bStatus DBGCHK = strSel.bCat (gszSlash);
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
Tokenize
|
|
|
|
Description:
|
|
|
|
Replace any valid separators with NULL in the dest string
|
|
|
|
Arguments:
|
|
|
|
LPTSTR pszDest - where to put the dest string
|
|
UNIT nMaxLength - size of the buffer of dest
|
|
LPCTSTR pszSrc - source string
|
|
LPTSTR *pszStart - start markup
|
|
LPTSTR *pszEnd - end markup
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
VOID
|
|
Tokenize(
|
|
OUT LPTSTR pszDest,
|
|
IN UINT nMaxLength,
|
|
IN LPCTSTR pszSrc,
|
|
OUT LPTSTR *pszStart,
|
|
OUT LPTSTR *pszEnd
|
|
)
|
|
{
|
|
ASSERT(pszDest);
|
|
ASSERT(nMaxLength);
|
|
ASSERT(pszSrc);
|
|
ASSERT(pszStart);
|
|
ASSERT(pszEnd);
|
|
|
|
// make a copy
|
|
lstrcpyn(pszDest, pszSrc, nMaxLength);
|
|
|
|
// replace all the valid separators with zeros
|
|
int i, iLen = lstrlen(pszDest);
|
|
for( i=0; i<iLen; i++ )
|
|
{
|
|
if( TEXT('\\') == pszDest[i] || TEXT('/') == pszDest[i] )
|
|
{
|
|
pszDest[i] = 0;
|
|
}
|
|
}
|
|
|
|
// initialize the walk pointers
|
|
*pszStart = pszDest;
|
|
*pszEnd = pszDest + iLen;
|
|
}
|
|
|
|
/******************************************************************************
|
|
|
|
TLocData methods
|
|
|
|
******************************************************************************/
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TLocData constructor
|
|
|
|
Description:
|
|
|
|
Creates the TLocData, the TLocData is the data that is shared between
|
|
the UI thread and the background thread. To ensure the data's life time
|
|
refrence counting is used.
|
|
|
|
Arguments:
|
|
|
|
pszClassName
|
|
pszWindowName - the class name and window name of toplevel window
|
|
where the message will be posted when data is ready
|
|
uMsgDataReady - the user message posted, which should be posted
|
|
bFindPhysicalLocation - should expand default
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
TLocData::
|
|
TLocData(
|
|
IN LPCTSTR pszClassName,
|
|
IN LPCTSTR pszPropertyName,
|
|
IN UINT uMsgDataReady,
|
|
IN BOOL bFindPhysicalLocation
|
|
) :
|
|
_uMsgDataReady(uMsgDataReady),
|
|
_bFindPhysicalLocation(bFindPhysicalLocation),
|
|
_bIsDataReady(FALSE),
|
|
_strWindowClass( pszClassName ),
|
|
_strPropertyName( pszPropertyName )
|
|
{
|
|
_bValid = _strWindowClass.bValid() && _strPropertyName.bValid();
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TLocData destructor
|
|
|
|
Description:
|
|
|
|
Deletes the linked list nodes
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Notes:
|
|
|
|
|
|
--*/
|
|
|
|
TLocData::
|
|
~TLocData(
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// Free the locations list
|
|
//
|
|
TLoc *pLoc;
|
|
while( !_LocationList_bEmpty() )
|
|
{
|
|
pLoc = _LocationList_pHead();
|
|
pLoc->_Location_vDelinkSelf();
|
|
delete pLoc;
|
|
}
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
bValid
|
|
|
|
Description:
|
|
|
|
Class valid check routine.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
TRUE - class is valid and usable,
|
|
FALSE - class is not usable.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
TLocData::
|
|
bValid(
|
|
VOID
|
|
) const
|
|
{
|
|
return _bValid;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TLocData::vNotifyUIDataIsReady
|
|
|
|
Description:
|
|
|
|
Notify the UI the background work is done
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
VOID
|
|
TLocData::
|
|
vNotifyUIDataIsReady(
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// Check if the data is ready first
|
|
//
|
|
if( _bIsDataReady )
|
|
{
|
|
for (HWND hWnd = FindWindow(_strWindowClass, NULL); hWnd; hWnd = GetWindow(hWnd, GW_HWNDNEXT))
|
|
{
|
|
TCHAR szBuffer[MAX_PATH];
|
|
|
|
if( !GetClassName(hWnd, szBuffer, COUNTOF(szBuffer)) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// check again ensure that class name is same
|
|
// if we obtained this handle from GetWindow( ... )
|
|
//
|
|
if( !_tcsicmp( szBuffer, _strWindowClass ) )
|
|
{
|
|
HANDLE hProp = GetProp( hWnd, _strPropertyName );
|
|
|
|
//
|
|
// Just verify who we are?
|
|
//
|
|
if( hProp == reinterpret_cast<HANDLE>(this) )
|
|
{
|
|
//
|
|
// Apropriate window found - post the message
|
|
//
|
|
PostMessage( hWnd, _uMsgDataReady, 0, reinterpret_cast<LPARAM>(this) );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TLocData::FindLocationsThread
|
|
|
|
Description:
|
|
|
|
static thread procedure, invokes the real worker proc
|
|
|
|
Arguments:
|
|
|
|
pData - TLocData object pointer to call
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
VOID
|
|
TLocData::
|
|
FindLocationsThread (
|
|
IN TLocData *pData
|
|
)
|
|
{
|
|
//
|
|
// Explore the locations (this is a
|
|
// slow resource access operation)
|
|
//
|
|
pData->vDoTheWork();
|
|
|
|
//
|
|
// Data is consistent to be used here
|
|
//
|
|
pData->_bIsDataReady = TRUE;
|
|
|
|
//
|
|
// Notify UI we are ready
|
|
//
|
|
pData->vNotifyUIDataIsReady();
|
|
|
|
//
|
|
// Unhook from data
|
|
//
|
|
pData->cDecRef();
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TLocData::vRefZeroed
|
|
|
|
Description:
|
|
|
|
Called when ref count reaches zero. Deletes the object
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
VOID
|
|
TLocData::
|
|
vRefZeroed(
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// No more clients - just kill myself, game over
|
|
//
|
|
delete this;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TLocData::bSearchLocations
|
|
|
|
Description:
|
|
|
|
Opens the Active Directory and searches the configuration
|
|
container to find the location property of each Subnet.
|
|
|
|
Arguments:
|
|
|
|
ds - The active directory object
|
|
|
|
Return Value:
|
|
|
|
TRUE - on success
|
|
FALSE - on failure
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
BOOL
|
|
TLocData::
|
|
bSearchLocations(
|
|
IN TDirectoryService &ds
|
|
)
|
|
{
|
|
static const DWORD kMaxPageSize = 10000;
|
|
static ADS_SEARCHPREF_INFO prefInfo[3];
|
|
static LPWSTR ppszPropertyName[] = {
|
|
const_cast<LPWSTR>(gszLocation)
|
|
};
|
|
|
|
TString strConfig;
|
|
TString strSubnet;
|
|
ADS_SEARCH_HANDLE hSearch = NULL;
|
|
ADS_SEARCH_COLUMN column;
|
|
IDirectorySearch* pDsSearch = NULL;
|
|
TStatusB bStatus;
|
|
TStatusH hResult;
|
|
DWORD cItems;
|
|
|
|
//
|
|
// Set search preferences
|
|
//
|
|
|
|
//
|
|
// one level search
|
|
//
|
|
prefInfo[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
|
|
prefInfo[0].vValue.dwType = ADSTYPE_INTEGER;
|
|
prefInfo[0].vValue.Integer = ADS_SCOPE_ONELEVEL;
|
|
|
|
//
|
|
// async search
|
|
//
|
|
prefInfo[1].dwSearchPref = ADS_SEARCHPREF_ASYNCHRONOUS;
|
|
prefInfo[1].vValue.dwType = ADSTYPE_BOOLEAN;
|
|
prefInfo[1].vValue.Boolean = TRUE;
|
|
|
|
//
|
|
// paged results
|
|
//
|
|
prefInfo[2].dwSearchPref = ADS_SEARCHPREF_PAGESIZE;
|
|
prefInfo[2].vValue.dwType = ADSTYPE_INTEGER;
|
|
prefInfo[2].vValue.Integer = kMaxPageSize;
|
|
|
|
//
|
|
// Get the configuration path
|
|
//
|
|
bStatus DBGCHK = ds.GetConfigurationContainer (strConfig);
|
|
|
|
if (bStatus)
|
|
{
|
|
TString strLDAPPrefix;
|
|
|
|
//
|
|
// Append config path to the subnet string
|
|
//
|
|
bStatus DBGCHK = strSubnet.bUpdate( gszLdapPrefix ) &&
|
|
strSubnet.bCat( gszSubnetContainter ) &&
|
|
strSubnet.bCat( gszComma ) &&
|
|
strSubnet.bCat( strConfig );
|
|
|
|
if(bStatus)
|
|
{
|
|
//
|
|
// Get container interface for the subnets object
|
|
//
|
|
hResult DBGCHK = ds.ADsGetObject ( const_cast<LPTSTR>(static_cast<LPCTSTR>(strSubnet)),
|
|
IID_IDirectorySearch,
|
|
reinterpret_cast<LPVOID*>(&pDsSearch));
|
|
if (SUCCEEDED(hResult))
|
|
{
|
|
//
|
|
// Search for the subnet objects
|
|
//
|
|
|
|
hResult DBGCHK = pDsSearch->SetSearchPreference(prefInfo, ARRAYSIZE(prefInfo));
|
|
}
|
|
|
|
if (SUCCEEDED (hResult))
|
|
{
|
|
hResult DBGCHK = pDsSearch->ExecuteSearch(L"(Objectclass=*)",
|
|
ppszPropertyName,
|
|
ARRAYSIZE (ppszPropertyName),
|
|
&hSearch);
|
|
}
|
|
|
|
for (cItems = 0 ; cItems < kMaxPageSize && SUCCEEDED (hResult); cItems++)
|
|
{
|
|
hResult DBGCHK = pDsSearch->GetNextRow(hSearch);
|
|
|
|
if (hResult == S_ADS_NOMORE_ROWS)
|
|
{
|
|
//
|
|
// we have more data so lets continue
|
|
//
|
|
hResult DBGCHK = S_OK;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Get the Name and display it in the list.
|
|
//
|
|
hResult DBGCHK = pDsSearch->GetColumn( hSearch, ppszPropertyName[0], &column );
|
|
|
|
if (SUCCEEDED(hResult))
|
|
{
|
|
switch (column.dwADsType)
|
|
{
|
|
case ADSTYPE_CASE_IGNORE_STRING:
|
|
|
|
if (column.pADsValues->CaseIgnoreString && column.pADsValues->CaseIgnoreString[0])
|
|
{
|
|
//
|
|
// This subnet has a location property
|
|
//
|
|
TLoc *pLoc = new TLoc();
|
|
|
|
if( VALID_PTR(pLoc) )
|
|
{
|
|
pLoc->strLocation.bUpdate( column.pADsValues->CaseIgnoreString );
|
|
_LocationList_vAppend(pLoc);
|
|
}
|
|
else
|
|
{
|
|
hResult DBGCHK = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
hResult DBGCHK = E_INVALIDARG;
|
|
break;
|
|
}
|
|
|
|
pDsSearch->FreeColumn(&column);
|
|
}
|
|
else if (hResult == E_ADS_COLUMN_NOT_SET)
|
|
{
|
|
//
|
|
// The location data is not available for this subnet, ignore
|
|
//
|
|
hResult DBGCHK = S_OK;
|
|
}
|
|
}
|
|
|
|
if (hSearch)
|
|
{
|
|
pDsSearch->CloseSearchHandle (hSearch);
|
|
}
|
|
|
|
if (pDsSearch)
|
|
{
|
|
pDsSearch->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Make this final check
|
|
//
|
|
if(bStatus)
|
|
{
|
|
bStatus DBGCHK = SUCCEEDED(hResult);
|
|
}
|
|
|
|
return bStatus;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TLocData::vDoTheWork
|
|
|
|
Description:
|
|
|
|
Opens the Active Directory and searches the configuration
|
|
container to find the location property of each Subnet.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
VOID
|
|
TLocData::
|
|
vDoTheWork(
|
|
VOID
|
|
)
|
|
{
|
|
TStatusB bStatus;
|
|
|
|
TDirectoryService ds;
|
|
bStatus DBGCHK = ds.bValid();
|
|
|
|
//
|
|
// Lookup for the DS name first
|
|
//
|
|
if( bStatus )
|
|
{
|
|
bStatus DBGCHK = ds.bGetDirectoryName( _strDSName );
|
|
}
|
|
|
|
//
|
|
// Enumerate the subnet objects
|
|
//
|
|
if( bStatus )
|
|
{
|
|
bStatus DBGCHK = bSearchLocations (ds);
|
|
}
|
|
|
|
//
|
|
// Find out the exact location of the current machine
|
|
//
|
|
if( bStatus )
|
|
{
|
|
TPhysicalLocation physLoc;
|
|
|
|
if (_bFindPhysicalLocation && physLoc.Discover())
|
|
{
|
|
physLoc.GetExact (_strDefault);
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************************************************************
|
|
TLocData::TLoc
|
|
******************************************************************************/
|
|
|
|
TLocData::
|
|
TLoc::
|
|
TLoc(
|
|
VOID
|
|
)
|
|
{
|
|
}
|
|
|
|
TLocData::
|
|
TLoc::
|
|
~TLoc(
|
|
VOID
|
|
)
|
|
{
|
|
}
|
|
|
|
/******************************************************************************
|
|
|
|
TLocTree methods
|
|
|
|
******************************************************************************/
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TLocTree constructor
|
|
|
|
Description:
|
|
|
|
Creates the imagelist for the tree control and inserts the
|
|
root string that describes the choices.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
TLocTree::
|
|
TLocTree(
|
|
IN HWND hwnd
|
|
)
|
|
{
|
|
HICON hIcon;
|
|
TCHAR szIconLocation[MAX_PATH];
|
|
INT iIconIndex;
|
|
TStatusB bStatus;
|
|
|
|
_hwndTree = hwnd;
|
|
_iGlobe = 0;
|
|
_iSite = 0;
|
|
|
|
_bWaitData = TRUE;
|
|
_hCursorWait = LoadCursor(NULL, IDC_WAIT);
|
|
_DefProc = NULL;
|
|
|
|
//
|
|
// Create the simple imagelist
|
|
// If this fails, the tree items just won't have icons
|
|
//
|
|
bStatus DBGCHK = Shell_GetImageLists( NULL, &_hIml );
|
|
|
|
if (_hIml)
|
|
{
|
|
IDsDisplaySpecifier *pDisplay = NULL;
|
|
|
|
//
|
|
// Use IDsDisplaySpecifier::GetIcon to find path to the icons
|
|
// for sites and subnets.
|
|
//
|
|
if (SUCCEEDED(CoCreateInstance(CLSID_DsDisplaySpecifier,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IDsDisplaySpecifier,
|
|
reinterpret_cast<LPVOID *>(&pDisplay))))
|
|
{
|
|
_iGlobe = Shell_GetCachedImageIndex (gszDSIconFile,
|
|
kDSIconIndex,
|
|
0);
|
|
|
|
pDisplay->GetIconLocation (gszSiteIconClass,
|
|
DSGIF_GETDEFAULTICON,
|
|
szIconLocation,
|
|
MAX_PATH,
|
|
&iIconIndex);
|
|
|
|
_iSite = Shell_GetCachedImageIndex (szIconLocation,
|
|
iIconIndex,
|
|
0);
|
|
pDisplay->Release();
|
|
|
|
TreeView_SetImageList (_hwndTree, _hIml, TVSIL_NORMAL);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Subclass tree control to handle WM_SETCURSOR message
|
|
//
|
|
_DefProc = reinterpret_cast<WNDPROC>( GetWindowLongPtr( _hwndTree, GWLP_WNDPROC ) );
|
|
SetWindowLongPtr( _hwndTree, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this) );
|
|
SetWindowLongPtr( _hwndTree, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(&TLocTree::ThunkProc) );
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TLocTree destructor
|
|
|
|
Description:
|
|
|
|
Destroys the image list
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
TLocTree::
|
|
~TLocTree(
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// Unsubclass here
|
|
//
|
|
SetWindowLongPtr( _hwndTree, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(_DefProc) );
|
|
SetWindowLongPtr( _hwndTree, GWLP_USERDATA, 0 );
|
|
|
|
//
|
|
// No longer need the shared image list
|
|
//
|
|
if (_hIml)
|
|
{
|
|
TreeView_SetImageList (_hwndTree, NULL, TVSIL_NORMAL);
|
|
}
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TLocTree::vResetTree
|
|
|
|
Description:
|
|
|
|
Resets the tree content
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
VOID
|
|
TLocTree::
|
|
vResetTree(
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// Delete all items and start waiting
|
|
// new data
|
|
//
|
|
TreeView_DeleteAllItems( _hwndTree );
|
|
_bWaitData = TRUE;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TLocTree::vBuildTree
|
|
|
|
Description:
|
|
|
|
Build the tree control from a ready data
|
|
|
|
Arguments:
|
|
|
|
pLocData - Where to get data from
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
VOID
|
|
TLocTree::
|
|
vBuildTree(
|
|
IN const TLocData *pLocData
|
|
)
|
|
{
|
|
//
|
|
// Check to reset the data
|
|
//
|
|
if( !_bWaitData )
|
|
{
|
|
vResetTree( );
|
|
}
|
|
|
|
if( !pLocData->_LocationList_bEmpty() )
|
|
{
|
|
//
|
|
// Build the tree and Fill the tree with the data.
|
|
//
|
|
vInsertRootString( pLocData );
|
|
vFillTree( pLocData );
|
|
}
|
|
|
|
//
|
|
// Stop waiting data
|
|
//
|
|
_bWaitData = FALSE;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TLocTree::vInsertRootString
|
|
|
|
Description:
|
|
|
|
Inserts the root string in the tree control
|
|
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
VOID
|
|
TLocTree::
|
|
vInsertRootString(
|
|
IN const TLocData *pLocData
|
|
)
|
|
{
|
|
TVINSERTSTRUCT tviStruct;
|
|
TString strRoot;
|
|
TStatusB bStatus;
|
|
TDirectoryService ds;
|
|
TString strDSName;
|
|
|
|
//
|
|
// Insert the Root-level string that describes the control
|
|
// This will be a combination of "Entire " + <directory name>
|
|
//
|
|
tviStruct.hParent = NULL;
|
|
tviStruct.hInsertAfter = TVI_ROOT;
|
|
tviStruct.item.mask = TVIF_TEXT|TVIF_IMAGE|TVIF_SELECTEDIMAGE;
|
|
tviStruct.item.iImage = _iGlobe;
|
|
tviStruct.item.iSelectedImage = _iGlobe;
|
|
|
|
bStatus DBGCHK = strRoot.bLoadString( ghInst, IDS_LOCTREEROOT ) &&
|
|
strRoot.bCat( pLocData->_strDSName );
|
|
|
|
tviStruct.item.pszText = const_cast<LPTSTR>(static_cast<LPCTSTR>(strRoot));
|
|
tviStruct.item.cchTextMax = strRoot.uLen();
|
|
|
|
_hRoot = TreeView_InsertItem (_hwndTree, &tviStruct);
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TLocTree::bInsertLocString
|
|
|
|
Description:
|
|
|
|
Add the given location string to the tree control.
|
|
Each level of the hierarchy is indicated by the '/'
|
|
delimiter. Prevents duplicate entries at each level of
|
|
the tree.
|
|
|
|
Arguments:
|
|
|
|
strLoc - location string to insert, Must be '/' delimited
|
|
|
|
Return Value:
|
|
|
|
TRUE - on success
|
|
FALSE - on failure
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
TLocTree::
|
|
bInsertLocString(
|
|
IN const TString &strLoc
|
|
) const
|
|
{
|
|
// Start at the root.
|
|
// For each '/' delimited string in szLoc,
|
|
// add a level to the tree and insert the
|
|
// string as a child node of the current node.
|
|
// At each level don't insert duplicates.
|
|
//
|
|
HTREEITEM hCurrent, hChild;
|
|
TVINSERTSTRUCT tviItem;
|
|
TVITEM* pItem = &tviItem.item;
|
|
DWORD dwErr;
|
|
TCHAR szBuffer[512];
|
|
LPTSTR psz, pszMax;
|
|
|
|
if (!_hwndTree)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// tokenize the input string
|
|
Tokenize(szBuffer, ARRAYSIZE(szBuffer), strLoc, &psz, &pszMax);
|
|
|
|
// initialize the item to insert
|
|
memset(pItem, 0, sizeof(TVITEM));
|
|
pItem->mask = TVIF_TEXT|TVIF_IMAGE|TVIF_SELECTEDIMAGE;
|
|
pItem->iImage = _iSite;
|
|
pItem->iSelectedImage = _iSite;
|
|
tviItem.hInsertAfter = TVI_SORT;
|
|
|
|
hCurrent = _hRoot;
|
|
while( hCurrent )
|
|
{
|
|
// find a valid token
|
|
while( 0 == *psz && psz < pszMax )
|
|
{
|
|
psz++;
|
|
}
|
|
|
|
// if we've gone past the buffer break the loop
|
|
if( psz >= pszMax )
|
|
{
|
|
break;
|
|
}
|
|
|
|
pItem->pszText = psz;
|
|
tviItem.hParent = hCurrent;
|
|
|
|
// if the current name already exists at this level don't insert
|
|
if( hChild = IsAChild(psz, hCurrent) )
|
|
{
|
|
hCurrent = hChild;
|
|
}
|
|
else
|
|
{
|
|
hCurrent = TreeView_InsertItem (_hwndTree, &tviItem);
|
|
}
|
|
|
|
// advance the token pointer
|
|
psz += lstrlen(psz);
|
|
}
|
|
|
|
return hCurrent ? TRUE : FALSE;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TLocTree::IsAChild
|
|
|
|
Description:
|
|
|
|
Determines if szLoc exists at the level of the
|
|
tree whose parent is hParent. If so, return
|
|
the handle of the node containing szLoc
|
|
|
|
Arguments:
|
|
|
|
szLoc - string to search for
|
|
hParent - parent node
|
|
|
|
Return Value:
|
|
|
|
Handle to treeview item matching szLoc, or NULL if not found
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
HTREEITEM
|
|
TLocTree::
|
|
IsAChild(
|
|
IN LPCTSTR szLoc,
|
|
IN HTREEITEM hParent
|
|
) const
|
|
{
|
|
TVITEM tvItem;
|
|
HTREEITEM hItem;
|
|
TCHAR szItemText[TPhysicalLocation::kMaxPhysicalLocation];
|
|
BOOL bMatch = FALSE;
|
|
|
|
tvItem.mask = TVIF_TEXT | TVIF_HANDLE;
|
|
tvItem.pszText = szItemText;
|
|
tvItem.cchTextMax = TPhysicalLocation::kMaxPhysicalLocation;
|
|
|
|
hItem = TreeView_GetChild (_hwndTree, hParent);
|
|
while (hItem && !bMatch)
|
|
{
|
|
tvItem.hItem = hItem;
|
|
TreeView_GetItem (_hwndTree, &tvItem);
|
|
bMatch = !_tcsicmp (szLoc, szItemText);
|
|
|
|
if (bMatch)
|
|
{
|
|
break;
|
|
}
|
|
|
|
hItem = TreeView_GetNextSibling (_hwndTree, hItem);
|
|
}
|
|
|
|
if (!bMatch)
|
|
{
|
|
hItem = NULL;
|
|
}
|
|
|
|
return hItem;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TLocTree::uGetSelectedLocation
|
|
|
|
Description:
|
|
|
|
Walks the tree control from the selected item to
|
|
the root, building the slash-delimited location
|
|
string name.
|
|
|
|
Arguments:
|
|
|
|
strLoc - string to update
|
|
|
|
Return Value:
|
|
|
|
TRUE - on success
|
|
FALSE - otherwise
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
TLocTree::
|
|
bGetSelectedLocation(
|
|
OUT TString &strLoc
|
|
) const
|
|
{
|
|
TVITEM tvItem;
|
|
TStatusB status;
|
|
TCHAR szTemp[TPhysicalLocation::kMaxPhysicalLocation];
|
|
|
|
tvItem.mask = TVIF_TEXT|TVIF_HANDLE;
|
|
tvItem.cchTextMax = TPhysicalLocation::kMaxPhysicalLocation;
|
|
tvItem.pszText = szTemp;
|
|
|
|
//
|
|
// Get the selected item
|
|
//
|
|
tvItem.hItem = TreeView_GetSelection (_hwndTree);
|
|
|
|
if (tvItem.hItem == _hRoot)
|
|
{
|
|
status DBGCHK = strLoc.bUpdate(_T("\0"));
|
|
return status;
|
|
}
|
|
|
|
status DBGCHK = TreeView_GetItem (_hwndTree, &tvItem);
|
|
|
|
if (status)
|
|
{
|
|
vRecursiveGetSel (_hwndTree, &tvItem, strLoc, _hRoot);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TLocTree::vExpandTree
|
|
|
|
Description:
|
|
|
|
Expands the tree view control to make visible the node
|
|
corresponding to the given location string
|
|
|
|
Arguments:
|
|
|
|
strExpand - slash-delimited location string to expand tree by
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
VOID
|
|
TLocTree::
|
|
vExpandTree(
|
|
IN const TString &strExpand
|
|
) const
|
|
{
|
|
if( strExpand.uLen() )
|
|
{
|
|
HTREEITEM hParent, hItem;
|
|
TCHAR szBuffer[512];
|
|
LPTSTR psz, pszMax;
|
|
|
|
// tokenize the input string
|
|
Tokenize(szBuffer, ARRAYSIZE(szBuffer), strExpand, &psz, &pszMax);
|
|
|
|
hParent = _hRoot;
|
|
for( ;; )
|
|
{
|
|
// find a valid token
|
|
while( 0 == *psz && psz < pszMax )
|
|
{
|
|
psz++;
|
|
}
|
|
|
|
// if we've gone past the buffer break the loop
|
|
if( psz >= pszMax )
|
|
{
|
|
break;
|
|
}
|
|
|
|
if( hItem = IsAChild(psz, hParent) )
|
|
{
|
|
// a valid child - remember
|
|
hParent = hItem;
|
|
|
|
// advance to the next token
|
|
psz += lstrlen(psz);
|
|
}
|
|
else
|
|
{
|
|
// not a child, bail out
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (hParent)
|
|
{
|
|
TreeView_EnsureVisible(_hwndTree, hParent);
|
|
TreeView_SelectItem(_hwndTree, hParent);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
vFillTree
|
|
|
|
Description:
|
|
|
|
Walks through the linked list and adds strings to the TLocTree object
|
|
|
|
Arguments:
|
|
|
|
pLocData - Where to get data from
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
VOID
|
|
TLocTree::
|
|
vFillTree(
|
|
IN const TLocData *pLocData
|
|
) const
|
|
{
|
|
TIter Iter;
|
|
TLocData::TLoc *pLoc;
|
|
|
|
TStatusB status = TRUE;
|
|
for( pLocData->_LocationList_vIterInit(Iter), Iter.vNext(); Iter.bValid(); Iter.vNext() )
|
|
{
|
|
pLoc = pLocData->_LocationList_pConvert( Iter );
|
|
status DBGCHK = bInsertLocString( pLoc->strLocation );
|
|
}
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TLocTree::ThunkProc
|
|
|
|
Description:
|
|
|
|
Thunk control proc (for subclassing)
|
|
|
|
Arguments:
|
|
|
|
Standard window proc parameters
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
LRESULT CALLBACK
|
|
TLocTree::
|
|
ThunkProc(
|
|
IN HWND hwnd,
|
|
IN UINT uMsg,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam
|
|
)
|
|
{
|
|
LRESULT lResult = 0;
|
|
TLocTree *This = reinterpret_cast<TLocTree*>( GetWindowLongPtr( hwnd, GWLP_USERDATA ) );
|
|
|
|
if( This )
|
|
{
|
|
if( WM_DESTROY == uMsg || WM_NCDESTROY == uMsg )
|
|
{
|
|
lResult = This->nHandleMessage( uMsg, wParam, lParam );
|
|
|
|
SetWindowLongPtr( hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(This->_DefProc) );
|
|
SetWindowLongPtr( hwnd, GWLP_USERDATA, 0 );
|
|
}
|
|
else
|
|
{
|
|
SPLASSERT( hwnd == This->_hwndTree );
|
|
lResult = This->nHandleMessage( uMsg, wParam, lParam );
|
|
|
|
if( !lResult )
|
|
{
|
|
//
|
|
// Message is not handled go to
|
|
// default processing
|
|
//
|
|
lResult = This->_DefProc( hwnd, uMsg, wParam, lParam );
|
|
}
|
|
}
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TLocTree::nHandleMessage
|
|
|
|
Description:
|
|
|
|
Message handler function
|
|
|
|
Arguments:
|
|
|
|
Standard window proc parameters
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
LRESULT
|
|
TLocTree::
|
|
nHandleMessage(
|
|
IN UINT uMsg,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam
|
|
)
|
|
{
|
|
//
|
|
// assume message is processed
|
|
//
|
|
LRESULT lResult = 1;
|
|
|
|
switch( uMsg )
|
|
{
|
|
case WM_SETCURSOR:
|
|
{
|
|
if( _bWaitData )
|
|
{
|
|
//
|
|
// Set hourglass cursor
|
|
//
|
|
SetCursor( _hCursorWait );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Message is not processed - go default processing
|
|
//
|
|
lResult = 0;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
//
|
|
// Message is not processed - go default processing
|
|
//
|
|
lResult = 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
/******************************************************************************
|
|
|
|
TFindLocDlg functions
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TFindLocDlg::bGenerateGUIDAsString
|
|
|
|
Description:
|
|
|
|
This function will generate a GUID,
|
|
convert it to string and return it
|
|
|
|
Arguments:
|
|
|
|
pstrGUID - where to place the genearted GUID
|
|
|
|
Return Value:
|
|
|
|
TRUE on success
|
|
FALSE on failure
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
TFindLocDlg::
|
|
bGenerateGUIDAsString(
|
|
OUT TString *pstrGUID
|
|
)
|
|
{
|
|
static const TCHAR szRegFormat[] = _T("{%08lX-%04X-%04x-%02X%02X-%02X%02X%02X%02X%02X%02X}");
|
|
|
|
//
|
|
// Assume failue
|
|
//
|
|
TStatusB bStatus = FALSE;
|
|
|
|
HRESULT hResult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
|
|
|
if( SUCCEEDED(hResult) )
|
|
{
|
|
GUID guid;
|
|
bStatus DBGCHK = SUCCEEDED(CoCreateGuid(&guid));
|
|
|
|
if( bStatus )
|
|
{
|
|
//
|
|
// Generate a registry format GUID string
|
|
//
|
|
bStatus DBGCHK = pstrGUID->bFormat( szRegFormat,
|
|
// first copy...
|
|
guid.Data1, guid.Data2, guid.Data3,
|
|
guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
|
|
guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7],
|
|
// second copy...
|
|
guid.Data1, guid.Data2, guid.Data3,
|
|
guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
|
|
guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
|
|
}
|
|
|
|
//
|
|
// Uninitialize COM after we finish
|
|
//
|
|
CoUninitialize( );
|
|
}
|
|
|
|
return bStatus;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TFindLocDlg constructor
|
|
|
|
Description:
|
|
|
|
Constructs TFindLocDlg object
|
|
|
|
Arguments:
|
|
|
|
flags - UI controlling flags (show/hide help button)
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
TFindLocDlg::
|
|
TFindLocDlg(
|
|
IN ELocationUI flags
|
|
) :
|
|
_pLocData(NULL),
|
|
_pTree(NULL),
|
|
_UIFlags(flags),
|
|
_bValid(TRUE),
|
|
_uMsgDataReady(0)
|
|
{
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TFindLocDlg destructor
|
|
|
|
Description:
|
|
|
|
Releases refcount on the location object
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
TFindLocDlg::
|
|
~TFindLocDlg(
|
|
VOID
|
|
)
|
|
{
|
|
if (VALID_PTR(_pLocData))
|
|
{
|
|
_pLocData->cDecRef();
|
|
}
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TFindLocDlg::bDoModal
|
|
|
|
Description:
|
|
|
|
Invokes the browse location dialog
|
|
|
|
Arguments:
|
|
|
|
hParent - hwnd of parent window
|
|
pstrDefault - default selection string, this is optional
|
|
|
|
Return Value:
|
|
|
|
TRUE - if dialog creation succeeds
|
|
FALSE - otherwise
|
|
|
|
Notes:
|
|
|
|
pstrDefault has NULL default value
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
TFindLocDlg::
|
|
bDoModal(
|
|
IN HWND hParent,
|
|
OUT TString *pstrDefault OPTIONAL
|
|
)
|
|
{
|
|
TStatusB bStatus;
|
|
bStatus DBGNOCHK = TRUE;
|
|
|
|
if (pstrDefault)
|
|
{
|
|
bStatus DBGCHK = _strDefault.bUpdate( *pstrDefault );
|
|
}
|
|
|
|
//
|
|
// Register the window message, this message is used to inform the
|
|
// UI thread that the data fetched by the background thread is ready.
|
|
//
|
|
_uMsgDataReady = RegisterWindowMessage( _T("WM_BACKGROUNDTASKISREADY") );
|
|
|
|
//
|
|
// Check if we succeeded to register the message
|
|
// and update the default location
|
|
//
|
|
if( _bValid && _uMsgDataReady && bStatus )
|
|
{
|
|
//
|
|
// Check if data is not obtained from a previous call
|
|
// of bDoModal() function - if not then start background
|
|
// thread to explore locations from the directory
|
|
// service
|
|
//
|
|
if( !_pLocData )
|
|
{
|
|
//
|
|
// Generate the special property name
|
|
//
|
|
bStatus DBGCHK = bGenerateGUIDAsString( &_strPropertyName );
|
|
|
|
if( bStatus )
|
|
{
|
|
_pLocData = new TLocData( _T("#32770"), _strPropertyName, _uMsgDataReady, _strDefault.bEmpty() );
|
|
bStatus DBGCHK = VALID_PTR( _pLocData );
|
|
|
|
if( bStatus )
|
|
{
|
|
_pLocData->vIncRef( );
|
|
|
|
//
|
|
// Spin the background explorer thread here
|
|
//
|
|
bStatus DBGCHK = bStartTheBackgroundThread();
|
|
}
|
|
else
|
|
{
|
|
delete _pLocData;
|
|
_pLocData = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Data is expected to be ready here or to be in
|
|
// process of exploration in background
|
|
//
|
|
if( bStatus )
|
|
{
|
|
//
|
|
// Everything looks fine - just show the UI
|
|
//
|
|
bStatus DBGCHK= (BOOL)DialogBoxParam( ghInst,
|
|
MAKEINTRESOURCE(DLG_BROWSE_LOC),
|
|
hParent,
|
|
MGenericDialog::SetupDlgProc,
|
|
reinterpret_cast<LPARAM>(this) );
|
|
}
|
|
}
|
|
|
|
return bStatus;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TFindLocDlg::uGetLocation
|
|
|
|
Description:
|
|
|
|
Fills in the location string selected when the dialog was open.
|
|
|
|
Arguments:
|
|
|
|
strLocation - TString to update
|
|
|
|
Return Value:
|
|
|
|
TRUE - on success,
|
|
FALSE - otherwise
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
TFindLocDlg::
|
|
bGetLocation(
|
|
OUT TString &strLocation
|
|
)
|
|
{
|
|
TStatusB bStatus;
|
|
bStatus DBGCHK = strLocation.bUpdate ((LPCTSTR)_strSelLocation);
|
|
return bStatus;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TFindLocDlg::vDataIsReady
|
|
|
|
Description:
|
|
|
|
Called when the background thread completes its work.
|
|
Always stops the wait cursor.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Notes:
|
|
|
|
|
|
--*/
|
|
|
|
VOID
|
|
TFindLocDlg::
|
|
vDataIsReady(
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// Make sure the animation stops
|
|
//
|
|
vStopAnim();
|
|
|
|
//
|
|
// Fill in the tree control, and select the default string
|
|
//
|
|
_pTree->vBuildTree( _pLocData );
|
|
|
|
if( !_pLocData->_LocationList_bEmpty() )
|
|
{
|
|
//
|
|
// Expand the default location here
|
|
//
|
|
if (!_strDefault.bEmpty())
|
|
{
|
|
_pTree->vExpandTree(_strDefault);
|
|
}
|
|
else
|
|
{
|
|
_pTree->vExpandTree(_pLocData->_strDefault);
|
|
}
|
|
|
|
//
|
|
// Enable the OK button
|
|
//
|
|
EnableWindow (GetDlgItem (_hDlg, IDOK), TRUE);
|
|
}
|
|
|
|
//
|
|
// Place the focus in the tree control
|
|
//
|
|
PostMessage( _hDlg, WM_NEXTDLGCTL, reinterpret_cast<WPARAM>( GetDlgItem(_hDlg, IDC_LOCTREE) ), 1L );
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TFindLocDlg::vOnOK
|
|
|
|
Description:
|
|
|
|
Called when the OK button is pressed.
|
|
Updates current selection string
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Notes:
|
|
|
|
|
|
--*/
|
|
|
|
VOID
|
|
TFindLocDlg::
|
|
vOnOK(
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// Get the selected location and close the dialog
|
|
//
|
|
_pTree->bGetSelectedLocation (_strSelLocation);
|
|
EndDialog (_hDlg, IDOK);
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TFindLocDlg::vOnDestroy
|
|
|
|
Description:
|
|
|
|
Cleans up data allocated for current
|
|
dialog window instance
|
|
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Notes:
|
|
|
|
|
|
--*/
|
|
|
|
VOID
|
|
TFindLocDlg::
|
|
vOnDestroy(
|
|
VOID
|
|
)
|
|
{
|
|
if (VALID_PTR(_pTree))
|
|
{
|
|
delete _pTree;
|
|
_pTree = NULL;
|
|
}
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TFindLocDlg::bHandleMessage
|
|
|
|
|
|
Description:
|
|
|
|
Dispatches messages to appropriate handlers.
|
|
|
|
|
|
Arguments:
|
|
|
|
uMsg - message value
|
|
wParam, lParam - message params
|
|
|
|
Return Value:
|
|
|
|
TRUE - if message is handled,
|
|
FALSE - otherwise
|
|
|
|
Notes:
|
|
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
TFindLocDlg::
|
|
bHandleMessage(
|
|
IN UINT uMsg,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam
|
|
)
|
|
{
|
|
BOOL bHandled = TRUE;
|
|
|
|
//
|
|
// Check our registered message first
|
|
//
|
|
if( _uMsgDataReady == uMsg && reinterpret_cast<LPARAM>(_pLocData) == lParam )
|
|
{
|
|
vDataIsReady( );
|
|
bHandled = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Standard message processing
|
|
//
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
bHandled = bOnInitDialog();
|
|
}
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
{
|
|
//
|
|
// Handle WM_COMMAND messages
|
|
//
|
|
bHandled = bOnCommand( LOWORD(wParam) );
|
|
}
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
{
|
|
//
|
|
// The only WM_NOTIFY source on the dialog is the TreeView
|
|
//
|
|
bHandled = bOnTreeNotify (reinterpret_cast<LPNMTREEVIEW>(lParam));
|
|
}
|
|
break;
|
|
|
|
|
|
case WM_HELP:
|
|
case WM_CONTEXTMENU:
|
|
{
|
|
//
|
|
// Help messages
|
|
//
|
|
PrintUIHelp( uMsg, _hDlg, wParam, lParam );
|
|
}
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
{
|
|
vOnDestroy ();
|
|
}
|
|
break;
|
|
|
|
case WM_CTLCOLORSTATIC:
|
|
{
|
|
bHandled = bOnCtlColorStatic( reinterpret_cast<HDC>(wParam),
|
|
reinterpret_cast<HWND>(lParam) );
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
bHandled = FALSE;
|
|
}
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
return bHandled;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TFindLocDlg::bOnInitDialog
|
|
|
|
Description:
|
|
|
|
Instantiates the TLocTree object and attempts to
|
|
initialize it if needed. Disable the OK button until
|
|
the worker thread completes.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
TRUE - on success
|
|
FALSE - on failure
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
TFindLocDlg::
|
|
bOnInitDialog(
|
|
VOID
|
|
)
|
|
{
|
|
DWORD dwResult;
|
|
TStatusB bStatus;
|
|
|
|
_pTree = new TLocTree (GetDlgItem(_hDlg, IDC_LOCTREE));
|
|
bStatus DBGCHK = VALID_PTR(_pTree);
|
|
|
|
if( !bStatus )
|
|
{
|
|
delete _pTree;
|
|
_pTree = NULL;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Set some special property value to us, so the
|
|
// worker thread could recognize us
|
|
//
|
|
bStatus DBGCHK = SetProp( _hDlg, _strPropertyName, static_cast<HANDLE>(_pLocData) );
|
|
|
|
if( bStatus )
|
|
{
|
|
//
|
|
// Hide the help button as requested
|
|
//
|
|
if (!(_UIFlags & kLocationShowHelp))
|
|
{
|
|
ShowWindow (GetDlgItem(_hDlg, IDC_LOCATION_HELP), SW_HIDE);
|
|
}
|
|
|
|
//
|
|
// Let the user know we're busy
|
|
//
|
|
EnableWindow (GetDlgItem (_hDlg, IDOK), FALSE);
|
|
|
|
vStartAnim();
|
|
|
|
//
|
|
// Just verify if the data is ready
|
|
//
|
|
_pLocData->vNotifyUIDataIsReady();
|
|
}
|
|
}
|
|
|
|
return bStatus;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TFindLocDlg::bOnTreeNotify
|
|
|
|
Description:
|
|
|
|
When the selection is changed on the tree control, update
|
|
the static control that displays the currently selected location
|
|
|
|
|
|
Arguments:
|
|
|
|
pTreeNotify - pointer to NMTREEVIEW struct
|
|
|
|
Return Value:
|
|
|
|
TRUE - if message is handled
|
|
FALSE - otherwise
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
TFindLocDlg::
|
|
bOnTreeNotify(
|
|
IN LPNMTREEVIEW pTreeNotify
|
|
)
|
|
{
|
|
TStatusB bStatus = TRUE;
|
|
TString strSel;
|
|
|
|
switch (pTreeNotify->hdr.code)
|
|
{
|
|
case TVN_SELCHANGED:
|
|
{
|
|
bStatus DBGCHK = _pTree->bGetSelectedLocation (strSel);
|
|
|
|
if (strSel.bEmpty())
|
|
{
|
|
strSel.bLoadString (ghInst,IDS_NO_LOCATION);
|
|
}
|
|
|
|
bStatus DBGCHK = bSetEditText (_hDlg, IDC_CHOSEN_LOCATION, strSel);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
bStatus DBGNOCHK = FALSE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return bStatus;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TFindLocDlg::vStartAnim
|
|
|
|
Description:
|
|
|
|
Show the animation window
|
|
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
VOID
|
|
TFindLocDlg::
|
|
vStartAnim(
|
|
VOID
|
|
)
|
|
{
|
|
HWND hwndAni = GetDlgItem (_hDlg, IDC_BROWSELOC_ANIM);
|
|
|
|
SetWindowPos (hwndAni,
|
|
HWND_TOP,
|
|
0,0,0,0,
|
|
SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW);
|
|
|
|
Animate_Open(hwndAni, MAKEINTRESOURCE (IDA_SEARCH));
|
|
Animate_Play(hwndAni, 0, -1, -1);
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TFindLocDlg::vStopAnim
|
|
|
|
Description:
|
|
|
|
Hide the animation window
|
|
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
VOID
|
|
TFindLocDlg::
|
|
vStopAnim(
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// Call LockWindowUpdate() to prevent default drawing of the
|
|
// animation control after stop playing - which is gray rect
|
|
//
|
|
LockWindowUpdate( _hDlg );
|
|
|
|
HWND hwndAni = GetDlgItem (_hDlg, IDC_BROWSELOC_ANIM);
|
|
|
|
SetWindowPos (hwndAni,
|
|
HWND_BOTTOM,
|
|
0,0,0,0,
|
|
SWP_NOMOVE|SWP_NOSIZE|SWP_HIDEWINDOW);
|
|
|
|
|
|
Animate_Stop(hwndAni);
|
|
|
|
//
|
|
// Unlock window update - tree control will
|
|
// repaint its content
|
|
//
|
|
LockWindowUpdate( NULL );
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
TFindLocDlg::bOnCtlColorStatic
|
|
|
|
Description:
|
|
Used to set background color of the animation window
|
|
to the same color as the treeview window
|
|
|
|
|
|
Arguments:
|
|
hdc - DC to set background color
|
|
|
|
Return Value:
|
|
color value used to draw background
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
TFindLocDlg::
|
|
bOnCtlColorStatic(
|
|
IN HDC hdc,
|
|
IN HWND hStatic
|
|
)
|
|
{
|
|
//
|
|
// Assume default processing of this message
|
|
//
|
|
BOOL bResult = FALSE;
|
|
|
|
if (hStatic == GetDlgItem (_hDlg, IDC_BROWSELOC_ANIM))
|
|
{
|
|
//
|
|
// We process this message only to have
|
|
// opportunity to patch the animation control
|
|
// dc just before paint.
|
|
//
|
|
// We do not return a brush here!
|
|
// (which means that we return a NULL brush)
|
|
//
|
|
// We should just return TRUE here to prevent the
|
|
// default message processing of this msg, which will
|
|
// revert the backgound color to gray.
|
|
//
|
|
SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
|
|
|
|
//
|
|
// Message is processed. Do not perform default
|
|
// processing!
|
|
//
|
|
bResult = TRUE;
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TFindLocDlg::bStartTheBackgroundThread
|
|
|
|
Description:
|
|
|
|
Starts the background thread for reading the subnet locations
|
|
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
TRUE - on success
|
|
FALSE - on failure
|
|
|
|
Notes:
|
|
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
TFindLocDlg::
|
|
bStartTheBackgroundThread(
|
|
VOID
|
|
)
|
|
{
|
|
TStatusB bStatus;
|
|
|
|
DWORD dwThreadID;
|
|
HANDLE hThread;
|
|
|
|
//
|
|
// You want to make sure the data is protected for the worker thread.
|
|
//
|
|
_pLocData->vIncRef();
|
|
|
|
//
|
|
// Spin the background thread here
|
|
//
|
|
hThread = TSafeThread::Create ( NULL,
|
|
0,
|
|
(LPTHREAD_START_ROUTINE)TLocData::FindLocationsThread,
|
|
_pLocData,
|
|
0,
|
|
&dwThreadID );
|
|
if( hThread )
|
|
{
|
|
//
|
|
// We don't need this handle any more.
|
|
// Just leave the thread running untill
|
|
// it stops
|
|
//
|
|
CloseHandle( hThread );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Ensure the data is release if the thread creation fails.
|
|
//
|
|
_pLocData->cDecRef();
|
|
}
|
|
|
|
bStatus DBGCHK = !!hThread;
|
|
|
|
return bStatus;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TFindLocDlg::bOnCommand
|
|
|
|
Description:
|
|
|
|
Handles WM_COMMAND messages
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
TRUE - on success
|
|
FALSE - on failure
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
TFindLocDlg::
|
|
bOnCommand(
|
|
IN UINT uCmdID
|
|
)
|
|
{
|
|
//
|
|
// Assume message is handled
|
|
//
|
|
BOOL bHandled = TRUE;
|
|
|
|
switch (uCmdID)
|
|
{
|
|
case IDOK:
|
|
vOnOK ();
|
|
break;
|
|
|
|
case IDCANCEL:
|
|
EndDialog (_hDlg, 0);
|
|
break;
|
|
|
|
case IDC_LOCATION_HELP:
|
|
PrintUIHtmlHelp (_hDlg,
|
|
gszHtmlPrintingHlp,
|
|
HH_DISPLAY_TOPIC,
|
|
reinterpret_cast<ULONG_PTR>(gszLocationHtmFile));
|
|
break;
|
|
|
|
default:
|
|
{
|
|
bHandled = FALSE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return bHandled;
|
|
}
|
|
|