//+--------------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1994 - 2001.
//
//  File:       scopane.cpp
//
//  Contents:   Functions for handling the scope pane folder structure
//
//  History:    12-12-1997   RobCap   Split out from snapmgr.cpp
//
//---------------------------------------------------------------------------


#include "stdafx.h"
#include "cookie.h"
#include "snapmgr.h"
#include "resource.h"
#include "wrapper.h"
#include "util.h"
#include <sceattch.h>
#include <io.h>

#ifdef INITGUID
#undef INITGUID
#include <gpedit.h>
#define INITGUID
#include "userenv.h"
#endif


//
// Array of folders to list in the scope pane
// The order of this array is important:
//   All folders which appear at the same level must be adjacent
//   to each other and the array and #defines need to be kept in
//   sync
//
//
#define USE_KERBEROS    1

//
// Top level folders
//
#define ANALYSIS_FOLDER 0
#define CONFIGURATION_FOLDER (ANALYSIS_FOLDER +1)

//
// Profile level folders
//
#define PROFILE_ACCOUNT_FOLDER (CONFIGURATION_FOLDER +1)
#define PROFILE_LOCAL_FOLDER (PROFILE_ACCOUNT_FOLDER +1)
#define PROFILE_EVENTLOG_FOLDER (PROFILE_LOCAL_FOLDER +1)
#define PROFILE_GROUPS_FOLDER (PROFILE_EVENTLOG_FOLDER +1)
#define PROFILE_SERVICE_FOLDER (PROFILE_GROUPS_FOLDER +1)
#define PROFILE_REGISTRY_FOLDER (PROFILE_SERVICE_FOLDER +1)
#define PROFILE_FILESTORE_FOLDER (PROFILE_REGISTRY_FOLDER +1)

//
// Profile/Account level folders
//
#define ACCOUNT_PASSWORD_FOLDER (PROFILE_FILESTORE_FOLDER +1)
#define ACCOUNT_LOCKOUT_FOLDER (ACCOUNT_PASSWORD_FOLDER +1)
#define ACCOUNT_KERBEROS_FOLDER (ACCOUNT_LOCKOUT_FOLDER +1)

//
// Profile/Local level folders
//
#define LOCAL_AUDIT_FOLDER (ACCOUNT_KERBEROS_FOLDER +1)
#define LOCAL_PRIVILEGE_FOLDER (LOCAL_AUDIT_FOLDER +1)
#define LOCAL_OTHER_FOLDER (LOCAL_PRIVILEGE_FOLDER +1)

//
// Profile/Eventlog level folders
//
#define EVENTLOG_LOG_FOLDER (LOCAL_OTHER_FOLDER +1)


#define NUM_FOLDERS (LOCAL_OTHER_FOLDER +1)
//#define NUM_FOLDERS (EVENTLOG_LOG_FOLDER +1)

//
// #defines to identify which folders belong in which sections
//
#define FIRST_STATIC_FOLDER ANALYSIS_FOLDER
#define LAST_STATIC_FOLDER CONFIGURATION_FOLDER
#define FIRST_PROFILE_FOLDER PROFILE_ACCOUNT_FOLDER
#define LAST_PROFILE_FOLDER PROFILE_DSOBJECT_FOLDER
#define LAST_PROFILE_NODS_FOLDER PROFILE_FILESTORE_FOLDER
#define LAST_LOCALPOL_FOLDER PROFILE_LOCAL_FOLDER
#define FIRST_ACCOUNT_FOLDER ACCOUNT_PASSWORD_FOLDER
#define LAST_ACCOUNT_NODS_FOLDER ACCOUNT_LOCKOUT_FOLDER
//
// remove kerberos section from NT5 for now
//
#if defined(_NT4BACK_PORT) || !defined(USE_KERBEROS)
#define LAST_ACCOUNT_FOLDER ACCOUNT_LOCKOUT_FOLDER
#else
#define LAST_ACCOUNT_FOLDER ACCOUNT_KERBEROS_FOLDER
#endif
#define FIRST_LOCAL_FOLDER LOCAL_AUDIT_FOLDER
#define LAST_LOCAL_FOLDER LOCAL_OTHER_FOLDER
#define FIRST_EVENTLOG_FOLDER EVENTLOG_LOG_FOLDER
#define LAST_EVENTLOG_FOLDER EVENTLOG_LOG_FOLDER

//
// The actual folder data
// This must be kept in sync with the above #defines
//         should be initialized based on the #defines rather than
//         independantly on them.  Let the compiler keep things
//         accurate for us
//
FOLDER_DATA SecmgrFolders[NUM_FOLDERS] =
{
   { IDS_ANALYZE, IDS_ANALYZE_DESC, ANALYSIS},
   { IDS_CONFIGURE, IDS_CONFIGURE_DESC, CONFIGURATION},
   { IDS_ACCOUNT_POLICY, IDS_ACCOUNT_DESC, POLICY_ACCOUNT},
   { IDS_LOCAL_POLICY, IDS_LOCAL_DESC, POLICY_LOCAL},
   { IDS_EVENT_LOG, IDS_EVENT_LOG, POLICY_LOG},
   { IDS_GROUPS, IDS_GROUPS_DESC, AREA_GROUPS},
   { IDS_SERVICE, IDS_SERVICE_DESC, AREA_SERVICE},
   { IDS_REGISTRY, IDS_REGISTRY_DESC, AREA_REGISTRY},
   { IDS_FILESTORE, IDS_FILESTORE_DESC, AREA_FILESTORE},
   { IDS_PASSWORD_CATEGORY, IDS_PASSWORD_CATEGORY, POLICY_PASSWORD},
   { IDS_LOCKOUT_CATEGORY,  IDS_LOCKOUT_CATEGORY, POLICY_LOCKOUT},
   { IDS_KERBEROS_CATEGORY,  IDS_KERBEROS_CATEGORY, POLICY_KERBEROS},
   { IDS_EVENT_AUDIT, IDS_EVENT_AUDIT, POLICY_AUDIT},
   { IDS_PRIVILEGE, IDS_PRIVILEGE_DESC, AREA_PRIVILEGE},
   { IDS_OTHER_CATEGORY, IDS_OTHER_CATEGORY, POLICY_OTHER},
};

#define ARRAYLEN(x) (sizeof(x) / sizeof((x)[0]))


//+--------------------------------------------------------------------------
//
//  Function:   AddLocationsToFolderList
//
//  Synopsis:   Adds the locations from a given registry key to the
//              folder list.  Returns the number of locations added.
//              Helper function for CreateFolderList
//
//  Arguments:  [hKey]           - the key holding the locations
//              [dwMode]         - the mode SCAT is running in
//              [bCheckForDupes] - TRUE to check for duplicates before adding
//              [pPos]           - output only
//
//  Returns:    *[pPos]  - the position in m_pScopeItemList of the first
//                         folder created
//              the number of child folders created
//
//  Modifies:   CComponentDataImpl::m_pScopeItemList
//
//  History:    7-26-l999  RobCap  broken out from CreateFolderList
//
//---------------------------------------------------------------------------
INT
CComponentDataImpl::AddLocationsToFolderList(HKEY hKey,
                                             DWORD dwMode,
                                             BOOL bCheckForDupes,
                                             POSITION *pPos) {
   LPTSTR  tmpstr=NULL;
   WCHAR   pBuf[MAX_PATH];
   DWORD   BufSize = MAX_PATH;
   WCHAR   pExpanded[MAX_PATH];
   FILETIME    LastWriteTime;
   PWSTR       Desc=NULL;
   CFolder *folder =NULL;
   INT nCount = 0;
   DWORD status = 0;
   HRESULT hr = S_OK;
   //
   // enumerate all subkeys of the key
   //
   int iTotal = 0;
   do {
      memset(pBuf, '\0', MAX_PATH*sizeof(WCHAR));
      BufSize = MAX_PATH;

      status = RegEnumKeyEx(hKey,
                            nCount,
                            pBuf,
                            &BufSize,
                            NULL,
                            NULL,
                            NULL,
                            &LastWriteTime);

      if ( NO_ERROR == status ) {
         //
         // get description of this location (subkey)
         //
         MyRegQueryValue( hKey,
                          pBuf,
                          L"Description",  // Value name (not localized)
                          (PVOID*)&Desc,
                          &BufSize );

         //
         // replace '/' with '\' because Registry does not
         // take '\' in a single key
         //
         tmpstr = wcschr(pBuf, L'/');
         while (tmpstr) {
            *tmpstr = L'\\';
            tmpstr = wcschr(tmpstr, L'/');
         }

         if (!ExpandEnvironmentStrings(pBuf,pExpanded,MAX_PATH)) {
            wcsncpy(pExpanded,pBuf,BufSize);
         }

         if (bCheckForDupes) {
            //
            // Make sure we haven't already added this directory
            //
            POSITION pos;
            BOOL bDuplicate = FALSE;
            pos = m_scopeItemList.GetHeadPosition();
            for (int i=0;i < m_scopeItemList.GetCount(); i++) {
               folder = m_scopeItemList.GetAt(pos);
               if (folder && (0 == lstrcmp(folder->GetName(),pExpanded))) {
                  bDuplicate = TRUE;
                  break;
               }
            }

            if (bDuplicate) {
               if ( Desc )
                   LocalFree(Desc);
               Desc = NULL;
               continue;
            }
         }

         folder = new CFolder();

         if (folder) {
            if( _wchdir( pExpanded ) ){
               folder->SetState( CFolder::state_InvalidTemplate );
            }
            //
            // Create the folder objects with static data
            //
            hr = folder->Create(pExpanded,                   // Name
                                Desc,                   // Description
                                NULL,                   // inf file name
                                CONFIG_FOLDER_IDX,      // closed icon index
                                CONFIG_FOLDER_IDX,      // open icon index
                                LOCATIONS,              // folder type
                                TRUE,                   // has children
                                dwMode,                 // SCE mode
                                NULL);                  // Extra Data
            if (SUCCEEDED(hr)) {
               m_scopeItemList.AddTail(folder);

               if ( iTotal == 0 && NULL != pPos && !bCheckForDupes) {
                  *pPos = m_scopeItemList.GetTailPosition();
               }
            } else {    // if can't create, then quit doing it anymore, no more reason to continue
               delete folder;
               if ( Desc )
                   LocalFree(Desc);
               Desc = NULL;
               break;
            }

         } else {
            hr = E_OUTOFMEMORY;
            if ( Desc )
               LocalFree(Desc);
            Desc = NULL;
            break;
         }

         if ( Desc ) {
            LocalFree(Desc);
         }
         Desc = NULL;

         nCount++;
         iTotal++;
      }
   } while ( status != ERROR_NO_MORE_ITEMS );

   return nCount;
}

//+--------------------------------------------------------------------------
//
//  Function:   CreateFolderList
//
//  Synopsis:   Adds the children folders of pFolder to m_pScopeItemList
//              and returns the location of the first such folder and the
//              number added
//
//  Arguments:  [pFolder] - the folder whose children we want to find
//              [type]    - the type of that folder
//              [pPos]    - output only
//              [Count]   - output only
//
//  Returns:    *[pPos]  - the position in m_pScopeItemList of the first
//                         folder created
//              *[Count] - the number of child folders created
//
//  Modifies:   CComponentDataImpl::m_pScopeItemList
//
//  History:    12-15-1997  RobCap  made dynamic based on mode
//
//---------------------------------------------------------------------------
HRESULT
CComponentDataImpl::CreateFolderList(CFolder *pFolder,   // Optional, In
                                     FOLDER_TYPES type,  // In
                                     POSITION *pPos,     // Optional, Out
                                     INT *Count)         // Optional, Out,
{
   CFolder* folder = 0;

   INT     nStart = 0;
   INT     nCount = 0;
   BOOL    bHasChildren = FALSE;
   struct _wfinddata_t findData;
   intptr_t hFile = 0;
   WCHAR   pBuf[MAX_PATH];
   HKEY    hKey = 0;
   DWORD       BufSize = 0;
   DWORD       status = 0;
   PWSTR       Desc=NULL;
   LPTSTR      tmpstr=NULL;
   HRESULT     hr = S_OK;
   DWORD   dwErr = 0;

   SCESTATUS            rc = 0;
   PSCE_OBJECT_CHILDREN ObjectList=NULL;
   PSCE_OBJECT_LIST     pObject = 0;
   PSCE_ERROR_LOG_INFO  ErrBuf=NULL;
   CString              StrErr;
   PSCE_PROFILE_INFO    pProfileInfo=NULL;
   FOLDER_TYPES         newType;
   PEDITTEMPLATE        pet = 0;

   //
   // initialize dwMode and ModeBits
   //

   DWORD dwMode=0;
   DWORD ModeBits=0;

   AFX_MANAGE_STATE(AfxGetStaticModuleState());

   if (Count)
      *Count = 0;

   if (pFolder) 
   {
      dwMode = pFolder->GetMode();
      ModeBits = pFolder->GetModeBits();
   }

   //
   // This could take some time, so create a wait curser
   //
   CWaitCursor wc;

   switch ( type ) 
   {
   case ROOT:
         //
         // Initial standalone mode root mode
         //

         folder = new CFolder();

         if (!folder)
            return E_OUTOFMEMORY;
         
         if ( GetImplType() == SCE_IMPL_TYPE_SAV ) 
         {
             dwMode = SCE_MODE_VIEWER;
             newType = ANALYSIS;
         } 
         else if ( GetImplType() == SCE_IMPL_TYPE_SCE ) 
         {
             dwMode = SCE_MODE_EDITOR;
             newType = CONFIGURATION;
         } 
         else if ( GetImplType() == SCE_IMPL_TYPE_LS) 
         {
            dwMode = SCE_MODE_LOCALSEC;
            newType = LOCALPOL;
         } 
         else 
         {
             dwMode = 0;
             newType = CONFIGURATION;
         }
         //
         // Create the folder objects with static data
         // MMC pulls in the name from the data object
         //
         hr = folder->Create(L"",              // Name
                             L"",              // Description
                             NULL,             // inf file name
                             SCE_IMAGE_IDX,    // closed icon index
                             SCE_IMAGE_IDX,    // open icon index
                             newType,          // folder type
                             TRUE,             // has children
                             dwMode,           // SCE Mode
                             NULL);            // Extra Data
         if (SUCCEEDED(hr)) 
         {
            folder->SetCookie(NULL);
            switch (m_Mode)
            {
               case SCE_MODE_DOMAIN_COMPUTER:
               case SCE_MODE_OU_COMPUTER:
               case SCE_MODE_LOCAL_COMPUTER:
               case SCE_MODE_REMOTE_COMPUTER:
                  m_computerModeBits = folder->GetModeBits();
                  break;

               case SCE_MODE_REMOTE_USER:
               case SCE_MODE_LOCAL_USER:
               case SCE_MODE_DOMAIN_USER:
               case SCE_MODE_OU_USER:
                  m_userModeBits = folder->GetModeBits();
                  break;

               default:
                  m_computerModeBits = folder->GetModeBits();
                  break;
            }
            
            m_scopeItemList.AddTail(folder);
            return S_OK;
         } 
         else 
         {
            delete folder;
            return hr;
         }


      case ANALYSIS:
         pFolder->SetInfFile(GT_COMPUTER_TEMPLATE);
         m_AnalFolder = pFolder;
         //
         // Very first time initialization of the sad name.
         // Ask the user to get a sad name if none exists.
         //
         if(!m_AnalFolder && SadName.IsEmpty() )
            OnOpenDataBase();
         //
         // enumerate security areas for analysis
         //
         if ( !SadHandle )
            LoadSadInfo(TRUE);

         //
         // The data under the Analysis node is not valid right now,
         // so don't display any folders
         //
         if (m_bIsLocked)
            return S_OK;

         //
         // We weren't able to load the Analysis data even though we're
         // not in the middle of an action that should be blocking it
         //
         if ( SadErrored != ERROR_SUCCESS || !SadHandle) 
            return E_FAIL;

         nStart = FIRST_PROFILE_FOLDER;

            //
            // Display all but the DS Objects folder
            //
            nCount = LAST_PROFILE_NODS_FOLDER - FIRST_PROFILE_FOLDER +1;
         bHasChildren = FALSE;
         break;

      case AREA_REGISTRY_ANALYSIS:
      case AREA_FILESTORE_ANALYSIS:
         if ( SadHandle == NULL ) 
         {
            //
            // We shouldn't be able to get this far without a SadHandle
            //
            ASSERT(FALSE);
            return E_FAIL;
         }

         if (m_bIsLocked) 
         {
            //
            // We shouldn't be able to get this far if we're locked
            //
            ASSERT(FALSE);
            return E_FAIL;
         }

         switch ( type ) 
         {
            case AREA_REGISTRY_ANALYSIS:
               status = AREA_REGISTRY_SECURITY; // use status temporatorily
               newType = REG_OBJECTS;
               break;

            case AREA_FILESTORE_ANALYSIS:
               status = AREA_FILE_SECURITY;
               newType = FILE_OBJECTS;
               break;

            default:
               break;
         }

         //
         // get the object roots
         //
         pet = GetTemplate(GT_LAST_INSPECTION,status,&dwErr);
         if (!pet) 
         {
            CString strErr;
            strErr.LoadString(dwErr);
            AfxMessageBox(strErr);
            return E_FAIL;
         }
         pProfileInfo = pet->pTemplate;

         if ( pProfileInfo ) 
         {
            //
            // add the object roots
            //
            if ( type == AREA_REGISTRY_ANALYSIS)
               pObject = pProfileInfo->pRegistryKeys.pOneLevel;
            else if ( type == AREA_FILESTORE_ANALYSIS )
               pObject = pProfileInfo->pFiles.pOneLevel;
            else 
               pObject = pProfileInfo->pDsObjects.pOneLevel;

            for (; pObject!=NULL; pObject=pObject->Next) 
            {
               CString strRoot;
               strRoot = (LPCTSTR)pObject->Name;
               if (AREA_FILESTORE_ANALYSIS == type) 
               {
                  //
                  // We want c:\, not c: here.
                  //
                  strRoot += L"\\";
               }
               //
               // These are the roots of the objects.
               // They are always containers
               //

               if (SCE_STATUS_NO_ACL_SUPPORT == pObject->Status) 
               {
                  folder = CreateAndAddOneNode(pFolder,
                                              // pObject->Name,
                                               strRoot,
                                               pBuf,
                                               newType,
                                               FALSE,
                                               GT_COMPUTER_TEMPLATE,
                                               pObject,
                                               pObject->Status);
               } 
               else 
               {
                  folder = CreateAndAddOneNode(
                                              pFolder,       // Parent folder
                                           //   pObject->Name, // Name
                                              strRoot,
                                              pBuf,          // Description
                                              newType,       // Folder Type
                                              TRUE,          // Has Children?
                                              GT_COMPUTER_TEMPLATE, // INF File
                                              pObject,       // Extra Data: the object
                                              pObject->Status); // Status
               }

               if(folder)
                  folder->SetDesc( pObject->Status, pObject->Count );
            }
         }
         return S_OK;

      case REG_OBJECTS:
      case FILE_OBJECTS:
         if ( SadHandle == NULL ) 
         {

            //
            // We shouldn't be able to get this far without a SadHandle
            //
            ASSERT(FALSE);
            return E_FAIL;
         }

         if ( type == REG_OBJECTS)
            status = AREA_REGISTRY_SECURITY;
         else if ( type == FILE_OBJECTS )
            status = AREA_FILE_SECURITY;
         else 
         {
            ASSERT(FALSE);
            return E_FAIL;
         }

         //
         // get the next level objects
         //
         rc = SceGetObjectChildren(SadHandle,                   // hProfile
                                   SCE_ENGINE_SAP,              // Profile type
                                   (AREA_INFORMATION)status,    // Area
                                   (LPTSTR)(pFolder->GetName()),// Object prefix
                                   &ObjectList,                 // Object list [out]
                                   &ErrBuf);                    // Error list [out]
         if ( ErrBuf ) 
         { // rc != SCESTATUS_SUCCESS ) {
            MyFormatResMessage(rc, IDS_ERROR_GETTING_LAST_ANALYSIS, ErrBuf, StrErr);

            SceFreeMemory((PVOID)ErrBuf, SCE_STRUCT_ERROR_LOG_INFO);
            ErrBuf = NULL;
         }
         if ( rc == SCESTATUS_SUCCESS &&
              ObjectList ) 
         {
            BOOL bContainer = FALSE;
            //
            // add the objects
            //
            PSCE_OBJECT_CHILDREN_NODE *pObjNode = &(ObjectList->arrObject);

            for (DWORD i=0; i<ObjectList->nCount;i++) 
            {
               //
               // These are the next level objects
               //
               if ( pObjNode[i] == NULL ||
                    pObjNode[i]->Name == NULL ) 
               {
                   continue;
               }

               if (SCE_STATUS_NO_ACL_SUPPORT == pObjNode[i]->Status) 
               {
                  // No ACL support, so don't add sub objects
                  continue;
               }

               //
               // If there are any mismatched child objects then we know
               // that this is a container, otherwise we have to check the
               // object on the system to find out if it is a container
               //
               if ( pObjNode[i]->Count > 0 ) 
                  bContainer = TRUE;
               else 
               {
                  if (FILE_OBJECTS == type) 
                  {
                     //
                     // Check if a file object is a container
                     //
                     CString strPath;
                     DWORD dwAttr = 0;

                     strPath = pFolder->GetName();
                     if (strPath.Right(1) != L"\\") 
                     {
                        strPath += L"\\";
                     }
                     strPath += pObjNode[i]->Name;

                     dwAttr = GetFileAttributes(strPath);
                     if (0xFFFFFFFF == dwAttr) 
                        bContainer = FALSE;
                     else 
                        bContainer = dwAttr & FILE_ATTRIBUTE_DIRECTORY;
                  } 
                  else 
                  {
                     //
                     // Always treat Registry Keys and DS Objects as containers
                     //
                     bContainer = TRUE;
                  }
               }
               if (bContainer) 
               {
                  StrErr = pFolder->GetName();
                  if (StrErr.Right(1) != L"\\")
                     StrErr += L"\\";
                  
                  StrErr += pObjNode[i]->Name;
                  folder = CreateAndAddOneNode(
                                              pFolder,       // Parent folder
                                              (LPTSTR)((LPCTSTR)StrErr),  // Name
                                              pBuf,          // Description
                                              type,          // Folder Type
                                              TRUE,          // Has Children?
                                              GT_COMPUTER_TEMPLATE, // INF File
                                              NULL,
                                              pObjNode[i]->Status); // Object Status
                  if(folder)
                  {
                     folder->SetDesc( pObjNode[i]->Status,
                                      pObjNode[i]->Count );
                  }
               }
            }
         }

         if ( ObjectList )
            SceFreeMemory((PVOID)ObjectList, SCE_STRUCT_OBJECT_CHILDREN );

         return S_OK;

      case CONFIGURATION: 
         {
         //
         // enumerate profile locations in registry
         //
         CString strLocations;

         m_ConfigFolder = pFolder;
         nCount = 0;

         if (strLocations.LoadString(IDS_TEMPLATE_LOCATION_KEY)) 
         {
            //
            // Bug 375324 - Merge HKCU locations with HKLM locations
            //
            status = RegOpenKeyEx( HKEY_CURRENT_USER,
                                   strLocations,
                                   0, KEY_READ, &hKey);

            if ( NO_ERROR == status ) 
            {
               nCount += AddLocationsToFolderList(hKey,dwMode,FALSE,pPos);
               RegCloseKey(hKey);
            }

            if ( 0 == nCount ) 
            {
               //
               // Empty location list, so add a default
               //
               CString strDefLoc;
               CString strDefLocEx;
               strDefLoc.LoadString(IDS_DEFAULT_LOCATION);
               int iLen = strDefLoc.GetLength()+MAX_PATH;
               LPWSTR pBuffer = strDefLocEx.GetBuffer(iLen);
               if (ExpandEnvironmentStrings(strDefLoc, pBuffer, iLen)) 
               {
                   //
                   // must use pBuffer here since strDefLocEx has not been released
                   //
                   AddTemplateLocation(pFolder,pBuffer,FALSE,TRUE);
               } 
               else
                   AddTemplateLocation(pFolder,strDefLoc,FALSE,TRUE);
               
               strDefLocEx.ReleaseBuffer();
            }
         }

         if ( Count != NULL )
            *Count = nCount;

         return hr;
      }

      case LOCATIONS:
         //
         // enumerate available profiles under the location (*.inf files)
         //

         //
         // pFolder is required in this case
         //
         if (!pFolder)
            return E_INVALIDARG;
         
         swprintf(pBuf, L"%s\\*.inf",
                  (LPTSTR)(pFolder->GetName()));
         bHasChildren = FALSE;

         hFile = _wfindfirst(pBuf, &findData);

         if ( hFile != -1) 
         {
            do {
                //
                // Don't add this item to the node if it is a subdirectory.
                //
                CString strDisplay;
                strDisplay.Format(
                   TEXT("%s\\%s"),
                   (LPCTSTR)(pFolder->GetName()),
                   findData.name);

                if( findData.attrib & _A_SUBDIR )
                   continue;

               //
               // get template's description
               //
               strDisplay = findData.name;
               //
               // GetLength has to be at least 4, since we searched on *.inf
               //
               strDisplay = strDisplay.Left(strDisplay.GetLength() - 4);
               swprintf(pBuf,
                        L"%s\\%s",
                        (LPTSTR)(pFolder->GetName()),
                        findData.name);
               if (! GetProfileDescription(pBuf, &Desc) ) 
                  Desc = NULL;
               else 
               {
                  //
                  // No problem; we just won't display a description
                  //
               }

               nCount++;
               folder = new CFolder();

               if (folder) 
               {
                  //
                  // Create the folder objects
                  // save full file name her
                  //
                  hr = folder->Create((LPCTSTR)strDisplay,         // Name
                                      Desc,                        // Description
                                      pBuf,                        // inf file name
                                      TEMPLATES_IDX,               // closed icon index
                                      TEMPLATES_IDX,               // open icon index
                                      PROFILE,                     // folder type
                                      bHasChildren,                // has children
                                      dwMode,                      // SCE Mode
                                      NULL);                       // Extra Data

                  if (SUCCEEDED(hr)) 
                  {
                     m_scopeItemList.AddTail(folder);

                     if ( nCount == 1 && NULL != pPos ) 
                     {
                        *pPos = m_scopeItemList.GetTailPosition();
                     }
                  } 
                  else 
                  {
                     delete folder;
                     folder = NULL;
                  }
               } 
               else
                  hr = E_OUTOFMEMORY;

               if (Desc) 
               {
                  LocalFree(Desc);
                  Desc = NULL;
               }
            } while ( _wfindnext(hFile, &findData) == 0 );
         }

         _findclose(hFile);

         if ( Count != NULL )
            *Count = nCount;

         return hr;

      case PROFILE: 
         {
         TCHAR pszGPTPath[MAX_PATH*5];
         SCESTATUS scestatus = 0;
         //
         // enumerate security areas for this profile
         //

         if (ModeBits & MB_NO_NATIVE_NODES) 
         {
            //
            //
            //
            nStart = nCount = 0;
            break;
         }

         //
         // Find the path to the SCE template within the GPT template
         //
         if (ModeBits & MB_GROUP_POLICY) 
         {
            //
            // get GPT root path
            //
            hr = m_pGPTInfo->GetFileSysPath(GPO_SECTION_MACHINE,
                                            pszGPTPath,
                                            ARRAYSIZE(pszGPTPath));
            if (SUCCEEDED(hr)) 
            {
               if (NULL == m_szSingleTemplateName) 
               {
                  //
                  // Allocate memory for the pszGPTPath + <backslash> + GPTSCE_TEMPLATE + <trailing nul>
                  //
                  m_szSingleTemplateName = (LPTSTR) LocalAlloc(LPTR,(lstrlen(pszGPTPath)+lstrlen(GPTSCE_TEMPLATE)+2)*sizeof(TCHAR));
               }
               if (NULL != m_szSingleTemplateName) 
               {
                  lstrcpy(m_szSingleTemplateName,pszGPTPath);
                  lstrcat(m_szSingleTemplateName,L"\\" GPTSCE_TEMPLATE);

                      PSCE_PROFILE_INFO spi = NULL;
                      //
                      // Create a new template there if there isn't one already
                      //
                      if (!CreateNewProfile(m_szSingleTemplateName,&spi)) 
                      {
                         hr = E_FAIL;
                      } 
                      else 
                      {
                         if (!GetTemplate(m_szSingleTemplateName) && spi) 
                         {
                            //
                            // bug 265996
                            //
                            // The first time a GPO's Security Settings are opened we create
                            // the file, but if it's on a remote machine it may not have been
                            // created yet when we try to open it
                            //
                            // Since we know what's going to be in it once it's created we
                            // can skip the open step and just shove our template into the
                            // cache

                            //
                            // Allocate space for key.
                            //
                            LPTSTR szKey = new TCHAR[ lstrlen( m_szSingleTemplateName ) + 1];
                            if(!szKey)
                            {
                                return NULL;
                            }
                            lstrcpy(szKey, m_szSingleTemplateName);
                            _wcslwr( szKey );

                            //
                            // Create a new CEditTemplate
                            //

                            CEditTemplate *pTemplateInfo = new CEditTemplate;
                            if (pTemplateInfo) 
                            {
                               pTemplateInfo->SetInfFile(m_szSingleTemplateName);
                               pTemplateInfo->SetNotificationWindow(m_pNotifier);
                               pTemplateInfo->pTemplate = spi;
                               //
                               // This is a brand new template; ergo everything's loaded
                               //
                               pTemplateInfo->AddArea(AREA_ALL);


                               //
                               // Stick it in the cache
                               //
                               m_Templates.SetAt(szKey, pTemplateInfo);

                               //
                               // expand registry value section based on registry values list on local machine
                               //
                               SceRegEnumAllValues(
                                                  &(pTemplateInfo->pTemplate->RegValueCount),
                                                  &(pTemplateInfo->pTemplate->aRegValues));
                            }

                            if (szKey) 
                               delete[] szKey;
                         }
                      }
               } 
               else
                  hr = E_OUTOFMEMORY;
            }
         }

         nStart = FIRST_PROFILE_FOLDER;

            //
            // Display all but the DS Objects folder
            //
            nCount = LAST_PROFILE_NODS_FOLDER - FIRST_PROFILE_FOLDER +1;


         bHasChildren = FALSE;
         tmpstr = pFolder->GetInfFile(); // inf file full path name
         //
         // If this folder is in a write-through mode then set that
         // on the template
         //
         PEDITTEMPLATE pie;
         pie = GetTemplate(tmpstr);
         if ( pie ) 
         {
            if (ModeBits & MB_WRITE_THROUGH) 
            {
               pie->SetWriteThrough(TRUE);
            }
         } 
         else 
         {
            //
            // Mark as bad template.
            //
            pFolder->SetState( CFolder::state_InvalidTemplate );
            nCount = 0;
         }
         break;
      }

      case LOCALPOL: 
         {
         nStart = FIRST_PROFILE_FOLDER;
         nCount = LAST_LOCALPOL_FOLDER - FIRST_PROFILE_FOLDER +1;
         bHasChildren = FALSE;
         pFolder->SetInfFile(GT_LOCAL_POLICY);
         break;
      }

      case POLICY_ACCOUNT:
         if (!pFolder) 
         {
            return E_INVALIDARG;
         } 
         else 
         {
            tmpstr = pFolder->GetInfFile();
         }
         // fall through;
      case LOCALPOL_ACCOUNT:
      case POLICY_ACCOUNT_ANALYSIS:
         nStart = FIRST_ACCOUNT_FOLDER;
         if (ModeBits & MB_DS_OBJECTS_SECTION) 
         {
            //
            // Include the DC Specific folders
            //
            nCount = LAST_ACCOUNT_FOLDER - FIRST_ACCOUNT_FOLDER + 1;
         } 
         else 
         {
            //
            // Display all but the DC Specific folders
            //
            nCount = LAST_ACCOUNT_NODS_FOLDER - FIRST_ACCOUNT_FOLDER +1;
         }
         bHasChildren = FALSE;
         break;

      case POLICY_LOCAL:
         if (!pFolder) 
         {
            return E_INVALIDARG;
         } 
         else 
         {
            tmpstr = pFolder->GetInfFile();
         }
         // fall through;
      case LOCALPOL_LOCAL:
      case POLICY_LOCAL_ANALYSIS:
         nStart = FIRST_LOCAL_FOLDER;
         nCount = LAST_LOCAL_FOLDER - FIRST_LOCAL_FOLDER +1;
         bHasChildren = FALSE;
         break;

      case POLICY_EVENTLOG:
         if (!pFolder)
            return E_INVALIDARG;
         else
            tmpstr = pFolder->GetInfFile();
         // fall through;
      case LOCALPOL_EVENTLOG:
      case POLICY_EVENTLOG_ANALYSIS:
         nStart = FIRST_EVENTLOG_FOLDER;
         nCount = LAST_EVENTLOG_FOLDER - FIRST_EVENTLOG_FOLDER +1;
         bHasChildren = FALSE;
         break;

      default:
         break;
   }


   if ( Count != NULL )
      *Count = nCount;

   CString cStrName;
   CString cStrDesc;


   for (int i=nStart; i < nStart+nCount; i++) 
   {
      folder = new CFolder();

      if (!folder) 
      {
         //
         // What about other folders that we've created?
         //
         return E_OUTOFMEMORY;
      }
      if (!cStrName.LoadString(SecmgrFolders[i].ResID) ||
          !cStrDesc.LoadString(SecmgrFolders[i].DescID)) 
      {
         delete folder;
         return E_FAIL;
      }

      //
      // Create the folder objects with static data
      //
      if (type == ANALYSIS ||
          type == AREA_POLICY_ANALYSIS ||
          type == POLICY_ACCOUNT_ANALYSIS ||
          type == POLICY_LOCAL_ANALYSIS ||
          type == POLICY_EVENTLOG_ANALYSIS ) 
      {
         if (m_bIsLocked) 
         {
            nCount = 0;


            delete folder;
            // Should display an "in use" message in result pane

            //
            // We're not adding anything, but we're not actually failing
            //
            return S_OK;
         }

         switch (SecmgrFolders[i].type) 
         {
            case AREA_POLICY:
               newType = AREA_POLICY_ANALYSIS;
               break;

            case AREA_PRIVILEGE:
               newType = AREA_PRIVILEGE_ANALYSIS;
               break;

            case AREA_GROUPS:
               newType = AREA_GROUPS_ANALYSIS;
               break;

            case AREA_SERVICE:
               newType = AREA_SERVICE_ANALYSIS;
               tmpstr = GT_COMPUTER_TEMPLATE;
               break;

            case AREA_REGISTRY:
               newType = AREA_REGISTRY_ANALYSIS;
               break;

            case AREA_FILESTORE:
               newType = AREA_FILESTORE_ANALYSIS;
               break;

            case POLICY_ACCOUNT:
               newType = POLICY_ACCOUNT_ANALYSIS;
               break;

            case POLICY_LOCAL:
               newType = POLICY_LOCAL_ANALYSIS;
               break;

            case POLICY_EVENTLOG:
               newType = POLICY_EVENTLOG_ANALYSIS;
               break;

            case POLICY_PASSWORD:
               newType = POLICY_PASSWORD_ANALYSIS;
               break;

            case POLICY_KERBEROS:
               newType = POLICY_KERBEROS_ANALYSIS;
               break;

            case POLICY_LOCKOUT:
               newType = POLICY_LOCKOUT_ANALYSIS;
               break;

            case POLICY_AUDIT:
               newType = POLICY_AUDIT_ANALYSIS;
               break;

            case POLICY_OTHER:
               newType = POLICY_OTHER_ANALYSIS;
               break;

            case POLICY_LOG:
               newType = POLICY_LOG_ANALYSIS;
               break;

            default:
               newType = SecmgrFolders[i].type;
               break;
         }

        int nImage = GetScopeImageIndex(newType);

        hr = folder->Create(cStrName.GetBuffer(2),    // Name
                            cStrDesc.GetBuffer(2),    // Description
                            tmpstr,                   // inf file name
                            nImage,                   // closed icon index
                            nImage,                   // open icon index
                            newType,                  // folder type
                            bHasChildren,             // has children
                            dwMode,                   // SCE Mode
                            NULL);                    // Extra Data
      } 
      else if (type == LOCALPOL ||
             type == AREA_LOCALPOL ||
             type == LOCALPOL_ACCOUNT ||
             type == LOCALPOL_LOCAL ||
             type == LOCALPOL_EVENTLOG ) 
      {
            if (m_bIsLocked) 
            {
               nCount = 0;

               delete folder;
               // Should display an "in use" message in result pane

               //
               // We're not adding anything, but we're not actually failing
               //
               return S_OK;
            }

            tmpstr = GT_LOCAL_POLICY;
            switch (SecmgrFolders[i].type) 
            {
               case AREA_POLICY:
                  newType = AREA_LOCALPOL;
                  break;

               case POLICY_ACCOUNT:
                  newType = LOCALPOL_ACCOUNT;
                  break;

               case POLICY_LOCAL:
                  newType = LOCALPOL_LOCAL;
                  break;

               case POLICY_EVENTLOG:
                  newType = LOCALPOL_EVENTLOG;
                  break;

               case POLICY_PASSWORD:
                  newType = LOCALPOL_PASSWORD;
                  break;

               case POLICY_KERBEROS:
                  newType = LOCALPOL_KERBEROS;
                  break;

               case POLICY_LOCKOUT:
                  newType = LOCALPOL_LOCKOUT;
                  break;

               case POLICY_AUDIT:
                  newType = LOCALPOL_AUDIT;
                  break;

               case POLICY_OTHER:
                  newType = LOCALPOL_OTHER;
                  break;

               case POLICY_LOG:
                  newType = LOCALPOL_LOG;
                  break;

               case AREA_PRIVILEGE:
                  newType = LOCALPOL_PRIVILEGE;
                  break;

               default:
                  newType = SecmgrFolders[i].type;
                  break;
            }

         int nImage = GetScopeImageIndex(newType);

         hr = folder->Create(cStrName.GetBuffer(2),    // Name
                             cStrDesc.GetBuffer(2),    // Description
                             tmpstr,                   // inf file name
                             nImage,                   // closed icon index
                             nImage,                   // open icon index
                             newType,                  // folder type
                             bHasChildren,             // has children
                             dwMode,                   // SCE Mode
                             NULL);                    // Extra Data
      } 
      else 
      {
         int nImage = GetScopeImageIndex(SecmgrFolders[i].type);

         hr = folder->Create(cStrName.GetBuffer(2),    // Name
                             cStrDesc.GetBuffer(2),    // Description
                             tmpstr,                   // inf file name
                             nImage,                   // closed icon index
                             nImage,                   // open icon index
                             SecmgrFolders[i].type,    // folder type
                             bHasChildren,             // has children
                             dwMode,                   // SCE Mode
                             NULL);                    // Extra Data

      }
      if (SUCCEEDED(hr)) 
      {
         m_scopeItemList.AddTail(folder);
         if ( i == nStart && NULL != pPos ) 
         {
            *pPos = m_scopeItemList.GetTailPosition();
         }
      } 
      else 
      {
         delete folder;
         return hr;
      }
   }

   return S_OK;
}


//+--------------------------------------------------------------------------
//
//  Method:     EnumerateScopePane
//
//  Synopsis:   Add the child folders of cookie/pParent to MMC's scope pane tree
//
//  Arguments:  [cookie]  - The cookie representing the node's who we
//                          are enumerating
//              [pParent] - The id of the node we are enumerating
//              [dwMode]  - The mode SCE is operating under (only allowed for
//                                                           initial enumeration)
//
//  Returns:    none
//
//  Modifies:   m_ScopeItemList (via CreateFolderList)
//
//  History:    12-15-1997   Robcap
//
//---------------------------------------------------------------------------

void CComponentDataImpl::EnumerateScopePane(MMC_COOKIE cookie, HSCOPEITEM pParent)
{
   int i = 0;
   ASSERT(m_pScope != NULL); // make sure we QI'ed for the interface
   if (NULL == m_pScope)
      return;



   m_bEnumerateScopePaneCalled = true;


   //
   // Enumerate the scope pane
   //

   // Note - Each cookie in the scope pane represents a folder.
   // A released product may have more then one level of children.
   // This sample assumes the parent node is one level deep.

   ASSERT(pParent != 0);
   if (0 == pParent)
      return;

   AFX_MANAGE_STATE(AfxGetStaticModuleState());

   if (m_scopeItemList.GetCount() == 0 ) 
   {
      CreateFolderList(NULL, ROOT, NULL, NULL);
   }

   //
   // Enumerate the scope pane
   // return the folder object that represents the cookie
   // Note - for large list, use dictionary
   //
   CFolder* pThis = FindObject(cookie, NULL);
   if (NULL == pThis) 
      pThis = m_AnalFolder;

   ASSERT(pThis);
   if ( NULL == pThis ) 
      return;

   //
   // Note - Each cookie in the scope pane represents a folder.
   //

   //
   // If we've already enumerated this folder then don't do it again
   //
   if ( pThis->IsEnumerated() )
      return;

   POSITION pos = NULL;
   int nCount = 0;
   CFolder *pFolder = 0;


   //
   // the pParent is the enumerated node's item ID, not its parent ID
   //
   pThis->GetScopeItem()->ID = pParent;
   if (SUCCEEDED(CreateFolderList( pThis,
             pThis->GetType(),
             &pos,
             &nCount )))  
   {
      for (i=0; (i < nCount) && (pos != NULL); i++ ) 
      {
         pFolder = m_scopeItemList.GetNext(pos);

         ASSERT(NULL != pFolder);
         if ( pFolder == NULL ) 
         {
            continue;
         }
         LPSCOPEDATAITEM pScope;
         pScope = pFolder->GetScopeItem();

         ASSERT(NULL != pScope);

         //
         // Set the parent
         //
         pScope->relativeID = pParent;

         //
         // Set the folder as the cookie
         //
         pScope->mask |= SDI_PARAM;
         pScope->lParam = reinterpret_cast<LPARAM>(pFolder);
         pFolder->SetCookie(reinterpret_cast<MMC_COOKIE>(pFolder));
         m_pScope->InsertItem(pScope);

         //
         // Note - On return, the ID member of 'm_pScopeItem'
         // contains the handle to the newly inserted item!
         //
         ASSERT(pScope->ID != NULL);
      }

      // This was commented out, but is needed to fix
      // 249158: SCE UI: Every time analysis is performed, another set of node appears
      // This flag will prevent the nodes from being re-enumerated.
      // If this doesn't work, then all the child nodes should be deleted before
      // reenumeration
      pThis->Set(TRUE);     // folder has been enumerated
   }
   else
   {
      //
      // Error creating folder list.  Make sure the folder isn't
      // marked as opened so that we can try to expand it again later
      //
      SCOPEDATAITEM item;

      ZeroMemory (&item, sizeof (item));
      item.mask = SDI_STATE;
      item.nState = 0;
      item.ID = pThis->GetScopeItem()->ID;
      //
      // Nothing else we can do if this returns a failure, so
      // don't worry about it
      //
      (void)m_pScope->SetItem (&item);
   }

}


/*------------------------------------------------------------------------------------------
CComponentDataImpl::GetColumnInfo

Synopsis:   Returns the column info for a folder type.

Arguments: [fType]  - The type of the CFolder item.

Returns:    a pointer to an int * where int[0] = the resource descritption into g_columnInfo.
                                        int[1] = the number of columns this array describes.
            NULL   - If there is no matching key.
------------------------------------------------------------------------------------------*/
PSCE_COLINFOARRAY CComponentDataImpl::GetColumnInfo( FOLDER_TYPES fType )
{
    PSCE_COLINFOARRAY pRet = NULL;
    if( m_mapColumns.Lookup(fType, pRet) )
    {
        return pRet;
    }
    return NULL;
}

/*------------------------------------------------------------------------------------------
CComponentDataImpl::SetColumnInfo

Synopsis:   Sets the column info for a certain type of folder.

Arguments: [fType]  - The type of the CFolder item.
           [pInfo]  - The new column info.
------------------------------------------------------------------------------------------*/
void CComponentDataImpl::SetColumnInfo( FOLDER_TYPES fType, PSCE_COLINFOARRAY pInfo)
{
    PSCE_COLINFOARRAY pCur = GetColumnInfo(fType);

    if(pCur)
    {
        LocalFree(pCur);
    }
    m_mapColumns.SetAt(fType, pInfo);
}

/*------------------------------------------------------------------------------------------
CComponentDataImpl::UpdateObjectStatus

Synopsis:   Updates the status of all objects under the child and parents if bUpdateThis
            is TRUE.

Arguments: [pParent]       - The Object to set status on
           [bUpdateThis]   - Weather to update the object or not.
------------------------------------------------------------------------------------------*/
DWORD CComponentDataImpl::UpdateObjectStatus(
   CFolder *pParent,
   BOOL bUpdateThis)
{
   if(!pParent)
      return ERROR_INVALID_PARAMETER;

   DWORD status = 0;
   TCHAR szBuf[50];

   switch(pParent->GetType())
   {
   case REG_OBJECTS:
      status = AREA_REGISTRY_SECURITY;
      break;

   case FILE_OBJECTS:
      status = AREA_FILE_SECURITY;
      break;

   default:
      return ERROR_INVALID_PARAMETER;
   }

   PSCE_OBJECT_CHILDREN     ObjectList  = NULL;
   PSCE_ERROR_LOG_INFO  ErrBuf      = NULL;
   SCESTATUS rc = 0;
   CString StrErr;
   SCOPEDATAITEM sci;

   HSCOPEITEM hItem = NULL;
   LONG_PTR pCookie = NULL;

   ZeroMemory(&sci, sizeof(SCOPEDATAITEM));
   sci.mask = SDI_STR | SDI_PARAM;

#define UPDATE_STATUS( X, O ) X->SetDesc( O->Status, O->Count );\
                           X->GetScopeItem()->nImage = GetScopeImageIndex( X->GetType(), O->Status);\
                           X->GetScopeItem()->nOpenImage = X->GetScopeItem()->nImage;

   LPCTSTR pszParent = NULL;
   if (bUpdateThis) 
   {
      CFolder *pCurrent = pParent;

      pParent->RemoveAllResultItems();
      m_pConsole->UpdateAllViews(NULL, (MMC_COOKIE)pParent, UAV_RESULTITEM_UPDATEALL);
      hItem = pCurrent->GetScopeItem()->ID;
      do {

         //
         // Walk up the items parent and update the items status.
         //
         if( m_pScope->GetParentItem( hItem, &hItem, &pCookie) == S_OK)
         {
            pszParent = (LPCTSTR)((CFolder *)pCookie)->GetName();
         } 
         else
            break;

         if(!pCookie)
            break;
         
         //
         // We are finished going up the parent.
         //

         switch( ((CFolder *)pCookie)->GetType() ) 
         {
            case AREA_REGISTRY_ANALYSIS:
            case AREA_FILESTORE_ANALYSIS:
               pszParent = NULL;
               break;

            default:
               break;
         }

         //
         // We have to get object information from the parent to the count parameter.
         //
         rc = SceGetObjectChildren(SadHandle,                   // hProfile
                                   SCE_ENGINE_SAP,              // Profile type
                                   (AREA_INFORMATION)status,    // Area
                                   (LPTSTR)pszParent,           // Object prefix
                                   &ObjectList,                 // Object list [out]
                                   &ErrBuf);
         if(ErrBuf)
         {
            SceFreeMemory((PVOID)ErrBuf, SCE_STRUCT_ERROR_LOG_INFO);
            ErrBuf = NULL;
         }

         if(SCESTATUS_SUCCESS != rc)
            break;

         //
         // Find object in link list.
         //
         DWORD i=0;

         sci.lParam = (LONG_PTR)pCurrent;
         GetDisplayInfo( &sci );

         PSCE_OBJECT_CHILDREN_NODE *pObjNode = &(ObjectList->arrObject);

         while(ObjectList && i<ObjectList->nCount)
         {
            if( pObjNode[i] &&
                pObjNode[i]->Name &&
                !lstrcmpi(sci.displayname, pObjNode[i]->Name) )
            {
               UPDATE_STATUS(pCurrent, pObjNode[i]);
               //
               // Update scopeItem.
               //
               m_pScope->SetItem(pCurrent->GetScopeItem());
               break;
            }
            i++;
         }

         if ( ObjectList ) 
         {
            SceFreeMemory((PVOID)ObjectList, SCE_STRUCT_OBJECT_CHILDREN );
            ObjectList = NULL;
         }

         pCurrent = (CFolder *)pCookie;
      } while( pszParent && hItem );
   }


   ObjectList = NULL;
   ErrBuf = NULL;

   //
   // Get Object children.
   //
   pszParent = pParent->GetName();
   rc = SceGetObjectChildren(SadHandle,                   // hProfile
                             SCE_ENGINE_SAP,              // Profile type
                             (AREA_INFORMATION)status,    // Area
                             (LPTSTR)pszParent,           // Object prefix
                             &ObjectList,                 // Object list [out]
                             &ErrBuf);
   //
   // Error list [out]
   //
   if ( ErrBuf ) 
   {
      MyFormatResMessage(rc, IDS_ERROR_GETTING_LAST_ANALYSIS, ErrBuf, StrErr);

      SceFreeMemory((PVOID)ErrBuf, SCE_STRUCT_ERROR_LOG_INFO);
      ErrBuf = NULL;
   }

   if ( SCESTATUS_SUCCESS == rc) 
   {
      //
      // Update all the children.
      //
      if( m_pScope->GetChildItem(pParent->GetScopeItem()->ID, &hItem, &pCookie) == S_OK && pCookie)
      {
         sci.lParam = (LONG_PTR)pCookie;

         GetDisplayInfo(&sci);
         while(hItem)
         {
            pParent = reinterpret_cast<CFolder *>(pCookie);
            //
            // Find object in object list.
            //
            DWORD i=0;
            while( ObjectList && i<ObjectList->nCount )
            {
               if( (&(ObjectList->arrObject))[i] &&
                   (&(ObjectList->arrObject))[i]->Name &&
                   !lstrcmpi((&(ObjectList->arrObject))[i]->Name, (LPCTSTR)sci.displayname) )
               {
                  UPDATE_STATUS(pParent, (&(ObjectList->arrObject))[i]);
                  //
                  // Update this objects children.
                  //
                  UpdateObjectStatus( pParent, FALSE );

                  //
                  // Update the name space
                  //
                  pParent->RemoveAllResultItems();
                  m_pConsole->UpdateAllViews(NULL, (MMC_COOKIE)pParent, UAV_RESULTITEM_UPDATEALL);
                  m_pScope->SetItem(pParent->GetScopeItem());
                  break;
               }
               i++;
            }

            if(ObjectList == NULL || i >= ObjectList->nCount)
            {
               //
               // Couldn't find the item, so just stop.
               //
               break;
            }

            //
            // Next Scope item
            //
            if( m_pScope->GetNextItem(hItem, &hItem, &pCookie) != S_OK)
            {
               break;
            }
         }
      }
   }

   if ( ObjectList )
      SceFreeMemory((PVOID)ObjectList, SCE_STRUCT_OBJECT_CHILDREN );

   return ERROR_SUCCESS;
}