Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

2417 lines
43 KiB

/*++
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;
}