/*++ Copyright (c) 1994-1998 Microsoft Corporation Module Name : events.cpp Abstract: Handle snapin event notifications Author: Ronald Meijer (ronaldm) Project: Internet Services Manager Revision History: --*/ // // Include Files // #include "stdafx.h" #include "inetmgr.h" #include "cinetmgr.h" // // Event handlers // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< HRESULT CSnapin::OnFolder( IN MMC_COOKIE cookie, IN LPARAM arg, IN LPARAM param ) /*++ Routine Description: 'Folder change' notification handler Arguments: MMC_COOKIE cookie : Selected item LPARAM arg : Notification Argument LPARAM param : Notification Parameter Return Value: HRESULT --*/ { ASSERT(FALSE); return S_OK; } HRESULT CSnapin::OnAddImages( IN MMC_COOKIE cookie, IN LPARAM arg, IN LPARAM param ) /*++ Routine Description: 'Add Image' handler Arguments: MMC_COOKIE cookie : Selected item LPARAM arg : Notification Argument LPARAM param : Notification Parameter Return Value: HRESULT --*/ { // // if cookie is from a different snapin // if (IsMyCookie(cookie) == FALSE) // if (0) { // // add the images for the scope tree only // CBitmap bmp16x16; CBitmap bmp32x32; LPIMAGELIST lpImageList = reinterpret_cast(arg); // // Load the bitmaps from the dll // { AFX_MANAGE_STATE(AfxGetStaticModuleState()); bmp16x16.LoadBitmap(IDB_16x16); bmp32x32.LoadBitmap(IDB_32x32); } // // Set the images // lpImageList->ImageListSetStrip( reinterpret_cast(static_cast(bmp16x16)), reinterpret_cast(static_cast(bmp32x32)), 0, RGB(255, 0, 255) ); lpImageList->Release(); } else { InitializeBitmaps(cookie); } return S_OK; } HRESULT CSnapin::OnShow( IN MMC_COOKIE cookie, IN LPARAM arg, IN LPARAM param ) /*++ Routine Description: 'Show' notification handler Arguments: MMC_COOKIE cookie : Selected item LPARAM arg : Notification Argument LPARAM param : Notification Parameter Return Value: HRESULT --*/ { // // Note - arg is TRUE when it is time to enumerate // if (arg) { // // Show the headers for this nodetype // InitializeHeaders(cookie); Enumerate(cookie, param); if (m_pControlbar) { SetToolbarStates(cookie); } } else { // // Free data associated with the result pane items, because // the node is no longer being displayed. // Note: The console will remove the items from the result pane // m_oblResultItems.RemoveAll(); } return S_OK; } HRESULT CSnapin::OnActivate( IN MMC_COOKIE cookie, IN LPARAM arg, IN LPARAM param ) /*++ Routine Description: 'Activiation' notification handler Arguments: MMC_COOKIE cookie : Selected item LPARAM arg : Notification Argument LPARAM param : Notification Parameter Return Value: HRESULT --*/ { return S_OK; } HRESULT CSnapin::OnResultItemClkOrDblClk( IN MMC_COOKIE cookie, IN BOOL fDblClick ) /*++ Routine Description: Result item click/double click notification handler Arguments: MMC_COOKIE cookie : Selected item BOOL fDblClick : TRUE if double click, FALSE for single click Return Value: HRESULT --*/ { CIISObject * pObject = (CIISObject *)cookie; if (pObject && !pObject->IsMMCConfigurable() && pObject->IsLeafNode()) { // // Special case: Down-level object -- not mmc configurable, but // configuration is the default verb, so fake it. // if (fDblClick) { ((CComponentDataImpl *)m_pComponentData)->DoConfigure(pObject); return S_OK; } } // // Use the default verb // return S_FALSE; } HRESULT CSnapin::OnMinimize( IN MMC_COOKIE cookie, IN LPARAM arg, IN LPARAM param ) /*++ Routine Description: 'Minimize' handler Arguments: MMC_COOKIE cookie : Selected item LPARAM arg : Notification Argument LPARAM param : Notification Parameter Return Value: HRESULT --*/ { return S_OK; } HRESULT CSnapin::OnPropertyChange( IN LPDATAOBJECT lpDataObject ) /*++ Routine Description: 'Property change' notification handler Arguments: LPDATAOBJECT lpDataObject : Selected data object Return Value: HRESULT --*/ { CIISObject * pObject = NULL; if (lpDataObject != NULL) { INTERNAL * pInternal = ExtractInternalFormat(lpDataObject); if (pInternal != NULL) { pObject = (CIISObject *)pInternal->m_cookie; SetToolbarStates((MMC_COOKIE)pObject); FREE_DATA(pInternal); } } return S_OK; } HRESULT CSnapin::OnUpdateView( IN LPDATAOBJECT lpDataObject ) /*++ Routine Description: 'Update View' notification handler Arguments: LPDATAOBJECT lpDataObject : Selected data object Return Value: HRESULT --*/ { return OnPropertyChange(lpDataObject); } void CSnapin::Enumerate( IN MMC_COOKIE cookie, IN HSCOPEITEM hParent ) /*++ Routine Description: Scope item enumeration notification handler Arguments: MMC_COOKIE cookie : Selected cookie (i.e. IISObject *) HSCOPEITEM hParent : Scope item to be enumerated Return Value: None --*/ { // // Add result view items // EnumerateResultPane(cookie); } void CSnapin::AddFileSystem( IN HSCOPEITEM hParent, IN LPCTSTR lpstrRoot, IN LPCTSTR lpstrMetaRoot, IN CIISInstance * pInstance, IN BOOL fGetDirs ) /*++ Routine Description: Add file system to result view. Arguments: HSCOPEITEM hParent Parent scope item LPCTSTR lpstrRoot Physical path LPCTSTR lpstrMetaRoot Meta root CIISInstance * pInstance Owning instance BOOL fGetDirs TRUE for directories, FALSE for files Return Value: None --*/ { // // Save state - needed for CWaitCursor // AFX_MANAGE_STATE(AfxGetStaticModuleState()); DWORD dwBufferSize = 0L; int cChildren = 0; CError err; do { CWaitCursor(); LPCTSTR lpstrOwner = pInstance->GetMachineName(); ASSERT(lpstrOwner); CString strDir; if (::IsServerLocal(lpstrOwner) || ::IsUNCName(lpstrRoot)) { // // Local directory, or already a unc path // strDir = lpstrRoot; } else { ::MakeUNCPath(strDir, lpstrOwner, lpstrRoot); } strDir.TrimLeft(); strDir.TrimRight(); if (strDir.IsEmpty()) { // // Invalid path // break; } strDir += _T("\\*"); WIN32_FIND_DATA w32data; HANDLE hFind = ::FindFirstFile(strDir, &w32data); if (hFind == INVALID_HANDLE_VALUE) { err.GetLastWinError(); break; } // // Find metabase information to match up with // this entry // CWaitCursor wait; CString strRedirect; CString strBase; pInstance->BuildFullPath(strBase, TRUE); LPCTSTR lpPath = lpstrMetaRoot; while (lpPath && *lpPath && *lpPath != _T('/')) ++lpPath; if (lpPath && *lpPath) { strBase += lpPath; } TRACEEOLID("Opening: " << strBase); TRACEEOLID(lpstrMetaRoot); BOOL fCheckMetabase = TRUE; CMetaKey mk( lpstrOwner, METADATA_PERMISSION_READ, METADATA_MASTER_ROOT_HANDLE, strBase ); CError errMB(mk.QueryResult()); if (errMB.Win32Error() == ERROR_PATH_NOT_FOUND) { // // Metabase path not found, not a problem. // TRACEEOLID("Parent node not in metabase"); fCheckMetabase = FALSE; errMB.Reset(); } else if (!errMB.MessageBoxOnFailure()) { // // Opened successfully, read redirect string. // DWORD dwAttr; errMB = mk.QueryValue( MD_HTTP_REDIRECT, strRedirect, NULL, // Inheritance override NULL, // Path &dwAttr ); if (errMB.Succeeded()) { if (IS_FLAG_SET(dwAttr, METADATA_INHERIT)) { int nComma = strRedirect.Find(_T(',')); if (nComma >= 0) { strRedirect.ReleaseBuffer(nComma); } } else { // // Yes, there's a redirect on the parent, but it's // not marked as inheritable, so it won't affect // the children. // strRedirect.Empty(); } } } // // Loop through the file system // do { // // Check to see if this is a file or directory as desired. // Ignore anything starting with a dot. // TRACEEOLID(w32data.cFileName); BOOL fIsDir = ((w32data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0); if (fIsDir == fGetDirs && *w32data.cFileName != _T('.')) { CIISFileNode * pNode = new CIISFileNode( w32data.cFileName, w32data.dwFileAttributes, pInstance, strRedirect, fIsDir ); if (pNode == NULL) { err = ERROR_NOT_ENOUGH_MEMORY; break; } // // For the result view -- only files, directories // get added automatically // ASSERT(!fIsDir); if (fCheckMetabase) { errMB = mk.DoesPathExist(w32data.cFileName); if (errMB.Succeeded()) { // // Match up with metabase properties. If the item // is found in the metabase with a non-inherited vrpath, // than a virtual root with this name exists, and this // file/directory should not be shown. // BOOL fVirtualDirectory; CString strMetaRoot(lpstrMetaRoot); errMB = pNode->FetchMetaInformation( strMetaRoot, &fVirtualDirectory ); if (errMB.Succeeded() && fVirtualDirectory) { TRACEEOLID("file/directory exists as vroot -- tossing" << w32data.cFileName); delete pNode; continue; } } } // // This better be unassigned -- one scope item per IISobject! // Note that the scope handle we're setting is actually the // _parent_'s scope handle. // ASSERT(pNode->GetScopeHandle() == NULL); pNode->SetScopeHandle(hParent, TRUE); // // Add the item // RESULTDATAITEM ri; ::ZeroMemory(&ri, sizeof(ri)); ri.mask = RDI_STR | RDI_IMAGE | RDI_PARAM; ri.str = MMC_CALLBACK; ri.nImage = pNode->QueryBitmapIndex(); ri.lParam = (LPARAM)pNode; m_pResult->InsertItem(&ri); // // Store // m_oblResultItems.AddTail(pNode); } } while(err.Succeeded() && FindNextFile(hFind, &w32data)); ::FindClose(hFind); } while(FALSE); if (err.Failed()) { // // Behaviour change: Display the errors always on the result // enumerator, and stop displaying them on the scope side // (this way we avoid double error messages) // err.MessageBoxFormat( IDS_ERR_ENUMERATE_FILES, MB_OK, NO_HELP_CONTEXT ); } } void CSnapin::DestroyItem( IN LPDATAOBJECT lpDataObject ) /*++ Routine Description: Delete the contents of the given data object Arguments: LPDATAOBJECT lpDataObject : Data object to be destroyed Return Value: None --*/ { CIISObject * pObject = NULL; if (lpDataObject) { INTERNAL * pInternal = ExtractInternalFormat(lpDataObject); if (pInternal) { pObject = (CIISObject *)pInternal->m_cookie; delete pObject; FREE_DATA(pInternal); } } } void CSnapin::EnumerateResultPane( IN MMC_COOKIE cookie ) /*++ Routine Description: Enumerate the result pane Arguments: MMC_COOKIE cookie : Parent CIISObject (scope side) Return Value: None --*/ { // // Make sure we QI'ed for the interface // ASSERT(m_pResult != NULL); ASSERT(m_pComponentData != NULL); CIISObject * pObject = (CIISObject *)cookie; if (pObject == NULL) { // // Static root node -- owns no leaf nodes // return; } if (pObject->SupportsFileSystem()) { CString strPhysicalPath, strMetaPath; pObject->BuildPhysicalPath(strPhysicalPath); pObject->BuildFullPath(strMetaPath, FALSE); AddFileSystem( pObject->GetScopeHandle(), strPhysicalPath, strMetaPath, pObject->FindOwnerInstance(), GET_FILES ); } //m_pResult->Sort(0, 0, -1); } HSCOPEITEM CComponentDataImpl::AddIISObject( IN HSCOPEITEM hParent, IN CIISObject * pObject, IN HSCOPEITEM hSibling, OPTIONAL IN BOOL fNext OPTIONAL ) /*++ Routine Description: Insert IIS object to the scope view Arguments: HSCOPEITEM hParent : Parent scope handle CIISObject * pObject : Object to be added HSCOPEITEM hSibling : NULL, or otherwise next sibling item BOOL fNext : If hSibling != NULL, this is used to indicate : Next (TRUE), or Previous (FALSE). Return Value: Handle to scope item of the newly added item --*/ { ASSERT(m_pScope != NULL); ASSERT(pObject != NULL); SCOPEDATAITEM item; ::ZeroMemory(&item, sizeof(SCOPEDATAITEM)); item.mask = SDI_STR | SDI_IMAGE | SDI_OPENIMAGE | SDI_PARAM | SDI_CHILDREN; if (hSibling != NULL) { item.mask |= (fNext ? SDI_NEXT : SDI_PREVIOUS); item.relativeID = hSibling; } else { item.mask |= SDI_PARENT; item.relativeID = hParent; } // // No '+' sign if no child objects could possibly exist. // e.g. downlevel web services, etc. // item.cChildren = (pObject->SupportsFileSystem() || pObject->SupportsChildren()) ? 1 : 0; item.displayname = MMC_CALLBACK; item.nOpenImage = item.nImage = pObject->QueryBitmapIndex(); item.lParam = (LPARAM)pObject; m_pScope->InsertItem(&item); // // This better be unassigned -- one scope item per IISobject! // ASSERT(pObject->GetScopeHandle() == NULL); pObject->SetScopeHandle(item.ID); return item.ID; } BOOL CComponentDataImpl::KillChildren( IN HSCOPEITEM hParent, IN UINT nOpenErrorMsg, IN BOOL fFileNodesOnly, IN BOOL fContinueOnOpenSheet ) /*++ Routine Description: Kill all children of a given parent node. Arguments: HSCOPEITEM hParent : The infanticidal parent handle UINT nOpenErrorMsg : Error indicating open prop sheet BOOL fFileNodesOnly : TRUE to delete only file nodes BOOL fContinueOnOpenSheet : TRUE to continue on open sheet error Return Value: TRUE if the nodes were deleted successfully -- FALSE if an open property sheet prevents deletions. --*/ { ASSERT(m_pScope != NULL); ASSERT(nOpenErrorMsg > 0); AFX_MANAGE_STATE(AfxGetStaticModuleState()); HSCOPEITEM hChildItem; MMC_COOKIE cookie; // // If a property sheet is open for this item, don't // allow deletion. // LPPROPERTYSHEETPROVIDER piPropertySheetProvider = NULL; CError err(m_pConsole->QueryInterface( IID_IPropertySheetProvider, (void **)&piPropertySheetProvider )); if (err.MessageBoxOnFailure()) { return FALSE; } CWaitCursor wait; if (!fFileNodesOnly) { // // Loop through and find open property sheets on the // nodes. // err = m_pScope->GetChildItem(hParent, &hChildItem, &cookie); while (err.Succeeded() && hChildItem != NULL) { CIISObject * pObject = (CIISObject *)cookie; HSCOPEITEM hTarget = NULL; if (FindOpenPropSheetOnNodeAndDescendants( piPropertySheetProvider, cookie )) { ::AfxMessageBox(nOpenErrorMsg); if (!fContinueOnOpenSheet) { return FALSE; } } // // Advance to next child of the same parent. // err = m_pScope->GetNextItem(hChildItem, &hChildItem, &cookie); } } // // Having ensured that no relevant property sheets remain open, // we can start committing infanticide. // err = m_pScope->GetChildItem(hParent, &hChildItem, &cookie); while (err.Succeeded() && hChildItem != NULL) { CIISObject * pObject = (CIISObject *)cookie; TRACEEOLID("Deleting: " << pObject->GetNodeName()); HSCOPEITEM hTarget = NULL; if (!fFileNodesOnly || pObject->IsFileSystemNode()) { if (FindOpenPropSheetOnNodeAndDescendants( piPropertySheetProvider, cookie )) { // // Can't kill this one then, display error, but continue // TRACEEOLID("Unable to kill child -- sheet open shouldn't happen!"); ASSERT(FALSE && "Should have been closed in the first pass"); // // Message for retail. How did he do it? // ::AfxMessageBox(nOpenErrorMsg); if (!fContinueOnOpenSheet) { return FALSE; } } else { // // Remember that this one is to be deleted. // hTarget = hChildItem; } } // // Advance to next child of the same parent. // err = m_pScope->GetNextItem(hChildItem, &hChildItem, &cookie); if (hTarget) { // // Delete the item we remembered earlier. This has to be done // after the GetNextItem() otherwise the hChildItem would be // bogus // HRESULT hr2 = m_pScope->DeleteItem(pObject->GetScopeHandle(), TRUE); delete pObject; } } piPropertySheetProvider->Release(); return TRUE; } HSCOPEITEM CComponentDataImpl::FindNextInstanceSibling( IN HSCOPEITEM hParent, IN CIISObject * pObject, OUT BOOL * pfNext ) /*++ Routine Descritpion: Find the 'next' or 'previous' instance sibling of the given object. That is, the instance we want to be inserted just in front of, or right after. Arguments: HSCOPEITEM hParent : Parent scope item CIISObject * pObject : IISObject to be placed BOOL * pfNext : Returns TRUE if sibling returned is Next, FALSE if sibling is previous, undetermined if sibling returned is NULL. Return Value: The 'next' or 'previous' sibling item (scope item handle) that the pObject is to be inserted in front of, or right after (check *pfNext), or else NULL. --*/ { // // Want to group by service type. Find an appropriate // sibling. Second key is instance ID. // MMC_COOKIE cookie; int nResult; HSCOPEITEM hItem; HSCOPEITEM hSibling = NULL; LPCTSTR lpSvcName = pObject->GetServiceName(); DWORD dwID = pObject->QueryInstanceID(); *pfNext = TRUE; TRACEEOLID("Service name: " << lpSvcName); TRACEEOLID("Instance ID#: " << dwID); BOOL fFoundSvc = FALSE; HRESULT hr = m_pScope->GetChildItem(hParent, &hItem, &cookie); while (hr == S_OK && hItem != NULL) { CIISObject * p = (CIISObject *)cookie; ASSERT(p != NULL); TRACEEOLID("Comparing against service: " << p->GetServiceName()); nResult = lstrcmpi(lpSvcName, p->GetServiceName()); if (nResult == 0) { // // Found same service type, now sort on instance ID // fFoundSvc = TRUE; hSibling = hItem; *pfNext = FALSE; DWORD dw = p->QueryInstanceID(); TRACEEOLID("Comparing against instance ID#: " << dw); if (dwID <= dw) { *pfNext = TRUE; break; } } else if (nResult < 0) { // // Needs to be inserted before this one. // if (!fFoundSvc) { hSibling = hItem; *pfNext = TRUE; } break; } hr = m_pScope->GetNextItem(hItem, &hItem, &cookie); } return hSibling; } HSCOPEITEM CComponentDataImpl::FindNextVDirSibling( IN HSCOPEITEM hParent, IN CIISObject * pObject ) /*++ Routine Descritpion: Find the 'next' virtual directory sibling of the given object. That is, the vdir we want to be inserted just in front of. Arguments: HSCOPEITEM hParent : Parent scope item CIISObject * pObject : IISObject to be placed Return Value: The 'next' sibling item (scope item handle) that the pObject is to be inserted in front of, or else NULL --*/ { // // Since VDIRs always are at the top of their list, the first // item with a different GUID is our 'next' sibling // HSCOPEITEM hItem; MMC_COOKIE cookie; GUID guid1 = pObject->QueryGUID(); HRESULT hr = m_pScope->GetChildItem(hParent, &hItem, &cookie); while (hr == S_OK && hItem != NULL) { CIISObject * p = (CIISObject *)cookie; ASSERT(p != NULL); GUID guid2 = p->QueryGUID(); if (guid1 != guid2) { // // Want to insert before this one // return hItem; } hr = m_pScope->GetNextItem(hItem, &hItem, &cookie); } // // Nothing found // return NULL; } HSCOPEITEM CComponentDataImpl::FindServerInfoParent( IN HSCOPEITEM hParent, IN CServerInfo * pServerInfo ) /*++ Routine Description: Find server info parent object for this object. The server info parent depends on the type of view, and can be a machine node, or a service collector node. Arguments: HSCOPEITEM hParent : Parent scope CServerInfo * pServerInfo Return Value: The scope item handle of the appropriate parent object, or NULL if not found. --*/ { ASSERT(m_pScope != NULL); // // Notes: The server info object parent is always a machine // node. Find the one that maches the computer name. // HSCOPEITEM hItem; MMC_COOKIE cookie; HRESULT hr = m_pScope->GetChildItem(hParent, &hItem, &cookie); while (hr == S_OK && hItem != NULL) { CIISObject * pObject = (CIISObject *)cookie; // // Skip objects that we don't own // if (pObject != NULL) { ASSERT(pObject->QueryGUID() == cMachineNode); // // Compare computer names // CIISMachine * pMachine = (CIISMachine *)pObject; if (::lstrcmpi(pServerInfo->QueryServerName(), pMachine->GetMachineName()) == 0) { // // Found the item // return hItem; } } // // Advance to next child of the same parent. // hr = m_pScope->GetNextItem(hItem, &hItem, &cookie); } // // Not found // return NULL; } HSCOPEITEM CComponentDataImpl::ForceAddServerInfoParent( IN HSCOPEITEM hParent, IN CServerInfo * pServerInfo ) /*++ Routine Description: Add a serverinfo object to the scope view Arguments: HSCOPEITEM hParent : Handle to parent scope item CServerInfo * pServerInfo : Server info object Return Value: Handle to the scope item of the newly inserted object --*/ { // // Server info parents are always machine nodes now. // CIISMachine * pMachine = new CIISMachine(pServerInfo->QueryServerName()); pMachine->m_fIsExtension = m_fIsExtension; return AddIISObject(hParent, pMachine); } HSCOPEITEM CComponentDataImpl::AddServerInfoParent( IN HSCOPEITEM hRootNode, IN CServerInfo * pServerInfo ) /*++ Routine Description: Add server info parent object appropriate for the given object. Look to see if one exists, otherwise add one. Return the handle to the parent object. Arguments: HSCOPEITEM hRootNode : Root of the scope view CServerInfo * pServerInfo : Server info object, whose parent we add Return Value: Scope view handle to a suitable server info parent object --*/ { HSCOPEITEM hParent = FindServerInfoParent(hRootNode, pServerInfo); if (hParent == NULL) { // // Parent doesn't exist, add it // hParent = ForceAddServerInfoParent(hRootNode, pServerInfo); } return hParent; } HSCOPEITEM CComponentDataImpl::AddServerInfo( IN HSCOPEITEM hRootNode, IN CServerInfo * pServerInfo, IN BOOL fAddParent ) /*++ Routine Description: Add a serverinfo object to the scope view. Find suitable parent object, and attach to it. Arguments: HSCOPEITEM hRootNode : Parent scope item handle CServerInfo * pServerInfo : Server info object to be added. BOOL fAddParent : TRUE to add parent item, FALSE to add to the given parent scope item Return Value: Handle to the newly added object. --*/ { HSCOPEITEM hItem = NULL; HSCOPEITEM hParent = fAddParent ? AddServerInfoParent(hRootNode, pServerInfo) : hRootNode; CError err; ASSERT(hParent != NULL); try { // // Add it underneath the parent // if (!pServerInfo->SupportsInstances()) { // // No instance support for this service // type. Add a single down-level instance // CIISInstance * pInstance = new CIISInstance(pServerInfo); BOOL fNext; HSCOPEITEM hSibling = FindNextInstanceSibling( hParent, pInstance, &fNext ); hItem = AddIISObject(hParent, pInstance, hSibling, fNext); } else { // // Add all virtual hosts (instances) at the same level // as a single instance item. Temporarily wrap this // in a down-level instance. // CIISInstance inst(pServerInfo); hItem = AddInstances(hParent, &inst); } } catch(CMemoryException * e) { hItem = NULL; err = ERROR_NOT_ENOUGH_MEMORY; e->Delete(); } if (err.Failed()) { AFX_MANAGE_STATE(::AfxGetStaticModuleState()); err.MessageBox(); } return hItem; } // // CODEWORK: Mess, should merge with AddFileSystem in results // HSCOPEITEM CComponentDataImpl::AddFileSystem( IN HSCOPEITEM hParent, IN LPCTSTR lpstrRoot, IN LPCTSTR lpstrMetaRoot, IN CIISInstance * pInstance, IN BOOL fGetDirs, IN BOOL fDeleteCurrentFileSystem ) /*++ Routine Description: Add file system objects on the scope side Arguments: HSCOPEITEM hParent : Parent scope item LPCTSTR lpstrRoot : Phsysical root path LPCTSTR lpstrMetaRoot : Meta root path CIISInstance * pInstance : Owner instance BOOL fGetDirs : TRUE to get directories, FALSE for files BOOL fDeleteCurrentFileSystem : TRUE to remove the current file/dir tree first Return Value: Handle to the last scope item added. --*/ { AFX_MANAGE_STATE(::AfxGetStaticModuleState()); ASSERT(hParent != NULL); CError err; HSCOPEITEM hItem = NULL; DWORD dwBufferSize = 0L; int cChildren = 0; do { if (fDeleteCurrentFileSystem) { TRACEEOLID("Deleting current file enumeration"); if (!KillChildren( hParent, IDS_PROP_OPEN_CONTINUE, DELETE_FILES_ONLY, CONTINUE_ON_OPEN_SHEET )) { // // Failed to remove the file system that was already enumerated // here. An error message will already have been displayed, so // quit gracefully here. // break; } } LPCTSTR lpstrOwner = pInstance->GetMachineName(); ASSERT(lpstrOwner); // // Turn the path into a UNC path // CString strDir; if (::IsServerLocal(lpstrOwner) || ::IsUNCName(lpstrRoot)) { // // Local directory, or already a unc path // strDir = lpstrRoot; } else { ::MakeUNCPath(strDir, lpstrOwner, lpstrRoot); } strDir.TrimLeft(); strDir.TrimRight(); if (strDir.IsEmpty()) { // // Invalid path // break; } strDir += _T("\\*"); WIN32_FIND_DATA w32data; HANDLE hFind = ::FindFirstFile(strDir, &w32data); if (hFind == INVALID_HANDLE_VALUE) { err.GetLastWinError(); break; } // // See if the parent has a redirect on it // CWaitCursor wait; CString strRedirect; CString strBase; pInstance->BuildFullPath(strBase, TRUE); LPCTSTR lpPath = lpstrMetaRoot; while (lpPath && *lpPath && *lpPath != _T('/')) ++lpPath; if (lpPath && *lpPath) { strBase += lpPath; } TRACEEOLID("Opening: " << strBase); TRACEEOLID(lpstrMetaRoot); BOOL fCheckMetabase = TRUE; CMetaKey mk( lpstrOwner, METADATA_PERMISSION_READ, METADATA_MASTER_ROOT_HANDLE, strBase ); CError errMB(mk.QueryResult()); if (errMB.Win32Error() == ERROR_PATH_NOT_FOUND) { // // Metabase path not found, not a problem. // TRACEEOLID("Parent node not in metabase"); fCheckMetabase = FALSE; errMB.Reset(); } else if (!errMB.MessageBoxOnFailure()) { // // Opened successfully, read redirect string. // DWORD dwAttr; errMB = mk.QueryValue( MD_HTTP_REDIRECT, strRedirect, NULL, // Inheritance override NULL, // Path &dwAttr ); if (errMB.Succeeded()) { if (IS_FLAG_SET(dwAttr, METADATA_INHERIT)) { int nComma = strRedirect.Find(_T(',')); if (nComma >= 0) { strRedirect.ReleaseBuffer(nComma); } } else { // // Yes, there's a redirect on the parent, but it's // not marked as inheritable, so it won't affect // the children. // strRedirect.Empty(); } } } // // Loop through the file system // do { // // Check to see if this is a file or directory/ // Ignore anything starting with a dot. // TRACEEOLID(w32data.cFileName); BOOL fIsDir = ((w32data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0); if (fIsDir == fGetDirs && *w32data.cFileName != _T('.')) { CIISFileNode * pNode = new CIISFileNode( w32data.cFileName, w32data.dwFileAttributes, pInstance, strRedirect, fIsDir ); if (pNode == NULL) { err = ERROR_NOT_ENOUGH_MEMORY; break; } if (fCheckMetabase) { errMB = mk.DoesPathExist(w32data.cFileName); ASSERT(errMB.Succeeded() || errMB.Win32Error() == ERROR_PATH_NOT_FOUND); if (errMB.Succeeded()) { // // Match up with metabase properties. If the item // is found in the metabase with a non-inherited vrpath, // than a virtual root with this name exists, and this // file/directory should not be shown. // BOOL fVirtualDirectory; CString strMetaRoot(lpstrMetaRoot); if (pNode->FetchMetaInformation( strMetaRoot, &fVirtualDirectory ) == ERROR_SUCCESS && fVirtualDirectory) { TRACEEOLID( "file/directory exists as vroot -- tossing" << w32data.cFileName ); delete pNode; continue; } } } // // Always added on at the end // hItem = AddIISObject(hParent, pNode); } } while(err.Succeeded() && FindNextFile(hFind, &w32data)); ::FindClose(hFind); } while(FALSE); if (err.Failed()) { // // Don't display file system errors -- leave those to result side // enumeration. // TRACEEOLID("Ate error message: " << err); } return hItem; } HSCOPEITEM CComponentDataImpl::AddVirtualRoots( IN HSCOPEITEM hParent, IN LPCTSTR lpstrParentPath, IN CIISInstance * pInstance ) /*++ Routine Description: Add virtual roots to the scope view Arguments: HSCOPEITEM hParent : Handle to parent scope item LPCTSTR lpstrParentPath : Parent metabase path CIISInstance * pInstance : Owner instance Return Value: Handle to the newly added scope item --*/ { ASSERT(hParent != NULL); CServerInfo * pServerInfo = pInstance->GetServerInfo(); ASSERT(pServerInfo != NULL); ISMCHILDINFO ii; HSCOPEITEM hItem = NULL; DWORD dwIndex = 0L; CError err; ZeroMemory(&ii, sizeof(ii)); ii.dwSize = sizeof(ii); HANDLE hEnum = NULL; FOREVER { DWORD dwID = pInstance->QueryID(); err = pServerInfo->ISMEnumerateChildren( &ii, &hEnum, dwID, lpstrParentPath ); if (err.Failed()) { break; } TRACEEOLID("Alias: " << ii.szAlias); TRACEEOLID("Path : " << ii.szPath); TRACEEOLID("Redir: " << ii.szRedirPath); if (*ii.szPath) { CIISChildNode * pChild = new CIISChildNode(&ii, pInstance); if (pChild == NULL) { err = ERROR_NOT_ENOUGH_MEMORY; break; } // // Always added on at the end // hItem = AddIISObject(hParent, pChild); } else { TRACEEOLID("Tossing child without vrpath"); } } if (err.Win32Error() == ERROR_NO_MORE_ITEMS) { // // This is the normal way to end this // err.Reset(); } if (err.Failed()) { // // Display error // AFX_MANAGE_STATE(::AfxGetStaticModuleState()); err.MessageBoxFormat( IDS_ERR_ENUMERATE_CHILD, MB_OK, NO_HELP_CONTEXT, (LPCTSTR)pServerInfo->GetServiceInfo()->GetShortName() ); } return hItem; } HSCOPEITEM CComponentDataImpl::AddInstances( IN HSCOPEITEM hParent, IN CIISObject * pObject ) /*++ Routine Description: Add instances to the treeview Arguments: HSCOPEITEM hParent : Parent scope item handle CIISObject * pObject : Owning object Return Value: Handle to the last instance added --*/ { ASSERT(hParent != NULL); CServerInfo * pServerInfo = pObject->GetServerInfo(); ASSERT(pServerInfo != NULL); ISMINSTANCEINFO ii; HSCOPEITEM hItem = NULL; DWORD dwIndex = 0L; CError err; ZeroMemory(&ii, sizeof(ii)); ii.dwSize = sizeof(ii); HANDLE hEnum = NULL; HSCOPEITEM hSibling = NULL; FOREVER { // // Loop through... // err = pServerInfo->ISMEnumerateInstances(&ii, &hEnum); if (err.Failed()) { break; } if (ii.dwError == ERROR_ACCESS_DENIED) { // // No point in listing this one // continue; } CIISInstance * pInstance = new CIISInstance(&ii, pServerInfo); if (pInstance == NULL) { err = ERROR_NOT_ENOUGH_MEMORY; break; } // // Add grouped by service type // BOOL fNext; if (hSibling == NULL) { hSibling = FindNextInstanceSibling( hParent, pInstance, &fNext ); } else { // // Keep appending // fNext = FALSE; } hSibling = hItem = AddIISObject( hParent, pInstance, hSibling, fNext ); } if (err.Win32Error() == ERROR_NO_MORE_ITEMS) { // // This is the normal way to end this // err.Reset(); } if (err.Failed()) { // // Display error message // AFX_MANAGE_STATE(::AfxGetStaticModuleState()); switch(err.Win32Error()) { // // Non-fatal errors // case ERROR_PATH_NOT_FOUND: case ERROR_NOT_ENOUGH_MEMORY: case ERROR_FILE_NOT_FOUND: ::AfxMessageBox(IDS_NON_FATAL_ERROR_INSTANCES); err.Reset(); break; default: err.MessageBoxFormat( IDS_ERR_ENUMERATE_INST, MB_OK, NO_HELP_CONTEXT, (LPCTSTR)pServerInfo->GetServiceInfo()->GetShortName() ); } } return hItem; }