////////////////////////////////////////////////////////////////////////////// /*++ Copyright (C) Microsoft Corporation, 1997 - 1999 Module Name: LoggingMethodsNode.cpp Abstract: Implementation file for the CLoggingMethodsNode class. Author: Michael A. Maguire 12/15/97 Revision History: mmaguire 12/15/97 - created --*/ ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // BEGIN INCLUDES // // standard includes: // #include "Precompiled.h" // // where we can find declaration for main class in this file: // #include "LoggingMethodsNode.h" // // // where we can find declarations needed in this file: // #include "LocalFileLoggingNode.h" #include "LogCompD.h" // this must be included before NodeWithResultChildrenList.cpp #include "LogComp.h" // this must be included before NodeWithResultChildrenList.cpp #include "NodeWithResultChildrenList.cpp" // Implementation of template class. #include "LogMacNd.h" // // END INCLUDES ////////////////////////////////////////////////////////////////////////////// #define COLUMN_WIDTH__LOGGING_METHOD 150 #define COLUMN_WIDTH__DESCRIPTION 300 ////////////////////////////////////////////////////////////////////////////// /*++ CLoggingMethodsNode::CLoggingMethodsNode Constructor --*/ ////////////////////////////////////////////////////////////////////////////// CLoggingMethodsNode::CLoggingMethodsNode( CSnapInItem* pParentNode, bool extendRasNode ) :CNodeWithResultChildrenList, CLoggingComponentData, CLoggingComponent>(pParentNode, extendRasNode?RAS_HELP_INDEX:0), m_ExtendRas(extendRasNode) { ATLTRACE(_T("# +++ CLoggingMethodsNode::CLoggingMethodsNode\n")); // Check for preconditions: // None. // Set the display name for this object TCHAR lpszName[IAS_MAX_STRING]; int nLoadStringResult = LoadString( _Module.GetResourceInstance(), IDS_LOGGING_METHODS_NODE__NAME, lpszName, IAS_MAX_STRING ); _ASSERT( nLoadStringResult > 0 ); m_bstrDisplayName = lpszName; // In IComponentData::Initialize, we are asked to inform MMC of // the icons we would like to use for the scope pane. // Here we store an index to which of these images we // want to be used to display this node m_scopeDataItem.nImage = IDBI_NODE_LOGGING_METHODS_CLOSED; m_scopeDataItem.nOpenImage = IDBI_NODE_LOGGING_METHODS_OPEN; m_pLocalFileLoggingNode = NULL; // We create the LocalFileLoggingNode now. // Usually we don't create objects until they have become // visible (when this LoggingMethodsNode receives the MMCN_SHOW // notification). // But because of the main IAS taskpad's Configure Logging // option, we need to make sure that this node has been // created and is available in case the user clicks on // configure logging before they ever saw or clicked on this node. // It should not already exist at this point. _ASSERTE( NULL == m_pLocalFileLoggingNode ); m_pLocalFileLoggingNode = new CLocalFileLoggingNode( this ); _ASSERTE( NULL != m_pLocalFileLoggingNode ); // ATTENTION: We did something a little unusual in // this class to solve a problem. // We want to be able to have a fixed pointer which other // parts of the snapin (e.g. the taskpad's Configure Logging command) // can use to get at the local file logging node. // So we have a member variable m_pLocalFileLoggingNode which // points to that node object. However, we wanted to re-use // the features of CResultNodeWithChildrenList, // so we added this node to the children list above. // The children list will automatically take care of deleting // any nodes added to the list, so we must be careful that if the // list of children ever deletes these nodes, // we don't still try to use m_pLocalFileLoggingNode. // The practical solution is to never allow the children // list to try to repopulate itself, which in this case // means to not enable the MMC_VERB_REFRESH for the // CLoggingMethodsNode. This is what we do. AddChildToList(m_pLocalFileLoggingNode); } ////////////////////////////////////////////////////////////////////////////// /*++ CLoggingMethodsNode::InitSdoPointers Call as soon as you have constructed this class and pass in it's SDO pointer. --*/ ////////////////////////////////////////////////////////////////////////////// HRESULT CLoggingMethodsNode::InitSdoPointers( ISdo *pSdo ) { ATLTRACE(_T("# CLoggingMethodsNode::InitSdoPointers\n")); // Check for preconditions: _ASSERTE( pSdo != NULL ); HRESULT hr = S_OK; // Release the old pointer if we had one. if( m_spSdo != NULL ) { m_spSdo.Release(); } // Save our client sdo pointer. m_spSdo = pSdo; // Give the node its Sdo -- in this case it's just our Sdo, which is the SdoServer. m_pLocalFileLoggingNode->InitSdoPointers( m_spSdo ); return hr; } ////////////////////////////////////////////////////////////////////////////// /*++ CLoggingMethodsNode::~CLoggingMethodsNode Destructor --*/ ////////////////////////////////////////////////////////////////////////////// CLoggingMethodsNode::~CLoggingMethodsNode() { ATLTRACE(_T("# --- CLoggingMethodsNode::~CLoggingMethodsNode\n")); // Check for preconditions: // None. // ATTENTION: We did something a little unusual in // this class to solve a problem. // We want to be able to have a fixed pointer which other // parts of the snapin (e.g. the taskpad's Configure Logging command) // can use to get at the local file logging node. // So we have a member variable m_pLocalFileLoggingNode which // points to that node object. However, we wanted to re-use // the features of CResultNodeWithChildrenList, // so we added this node to the list of children. // The children list will automatically take care of deleting // any nodes added to the list, so we must be careful that if the // list of children ever deletes these nodes, // we don't still try to use m_pLocalFileLoggingNode. // The practical solution is to never allow the children // list to try to repopulate itself, which in this case // means to not enable the MMC_VERB_REFRESH for the // CLoggingMethodsNode. This is what we do. // So DON'T "delete m_pLocalFileLoggingNode;" } ////////////////////////////////////////////////////////////////////////////// /*++ CLoggingMethodsNode::GetResultPaneColInfo See CSnapinNode::GetResultPaneColInfo (which this method overrides) for detailed info. --*/ ////////////////////////////////////////////////////////////////////////////// OLECHAR* CLoggingMethodsNode::GetResultPaneColInfo(int nCol) { ATLTRACE(_T("# CLoggingMethodsNode::GetResultPaneColInfo\n")); // Check for preconditions: // None. if (nCol == 0 && m_bstrDisplayName != NULL) return m_bstrDisplayName; return NULL; } // This is no longer needed. We have chosen to handle images on a // per-IComponent basis. See CComponent::OnAddImages. // We keep this here because it demonstrates how IImageList::ImageListSetIcon // can be used. ////////////////////////////////////////////////////////////////////////////// /*++ CLoggingMethodsNode::OnAddImages See CSnapinNode::OnAddImages (which this method overrides) for detailed info. --*/ ////////////////////////////////////////////////////////////////////////////// //HRESULT CLoggingMethodsNode::OnAddImages( LPARAM arg // , LPARAM param // , IComponentData * pComponentData // , IComponent * pComponent // , DATA_OBJECT_TYPES type // ) //{ // ATLTRACE(_T("# CLoggingMethodsNode::OnAddImages\n")); // // // // Check for preconditions: // _ASSERTE( arg != NULL ); // // // HRESULT hr = S_FALSE; // // // Load bitmaps associated with the result pane // // and add them to the image list // // Loads the default bitmaps generated by the wizard // // Change as needed // // // ISSUE: sburns in localsec does a trick where he combines // // scope and result pane ImageLists into one // // is this necessary? // // CComPtr spImageList = reinterpret_cast(arg); // _ASSERTE( spImageList != NULL ); // // HICON icon = LoadIcon(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDI_RESULT_NODE_LOGGING_METHOD)); // if (NULL == icon) // return E_UNEXPECTED; // // // ISSUE: We use nImage = 0 here as that is what the default // // constructor of CSnapinNode does // // hr = spImageList->ImageListSetIcon( reinterpret_cast(icon), 0 ); // // return hr; // //} ////////////////////////////////////////////////////////////////////////////// /*++ CLoggingMethodsNode::SetVerbs See CSnapinNode::SetVerbs (which this method overrides) for detailed info. --*/ ////////////////////////////////////////////////////////////////////////////// HRESULT CLoggingMethodsNode::SetVerbs( IConsoleVerb * pConsoleVerb ) { ATLTRACE(_T("# CLoggingMethodsNode::SetVerbs\n")); // Check for preconditions: // None. HRESULT hr = S_OK; hr = pConsoleVerb->SetVerbState( MMC_VERB_REFRESH, ENABLED, TRUE ); // CLoggingMethodsNode has no properties // hr = pConsoleVerb->SetVerbState( MMC_VERB_PROPERTIES, ENABLED, FALSE ); // We don't want the user deleting or renaming this node, so we // don't set the MMC_VERB_RENAME or MMC_VERB_DELETE verbs. // By default, when a node becomes selected, these are disabled. // We want double-clicking on a collection node to show its children. // hr = pConsoleVerb->SetVerbState( MMC_VERB_OPEN, ENABLED, TRUE ); // hr = pConsoleVerb->SetDefaultVerb( MMC_VERB_OPEN ); return hr; } //+--------------------------------------------------------------------------- // // Function: DataRefresh -- to support // // Class: CPoliciesNode // // Synopsis: Initialize the CPoliciesNode using the SDO pointers // // Arguments: ISdo* pMachineSdo - Server SDO // ISdoDictionaryOld* pDictionarySdo - Sdo Dictionary // Returns: HRESULT - how the initialization goes // // History: Created byao 2/6/98 8:03:12 PM // //+--------------------------------------------------------------------------- HRESULT CLoggingMethodsNode::DataRefresh( ISdo* pSdo ) { HRESULT hr = S_OK; _ASSERTE( pSdo != NULL ); // Save away the interface pointers. m_spSdo.Release(); m_spSdo = pSdo; hr = m_pLocalFileLoggingNode->DataRefresh(pSdo); return hr; } ////////////////////////////////////////////////////////////////////////////// /*++ CPoliciesNode::OnRefresh See CSnapinNode::OnRefresh (which this method overrides) for detailed info. --*/ ////////////////////////////////////////////////////////////////////////////// HRESULT CLoggingMethodsNode::OnRefresh( LPARAM arg , LPARAM param , IComponentData * pComponentData , IComponent * pComponent , DATA_OBJECT_TYPES type ) { HRESULT hr = S_OK; CWaitCursor WC; CComPtr spConsole; // We need IConsole if( pComponentData != NULL ) { spConsole = ((CLoggingComponentData*)pComponentData)->m_spConsole; } else { spConsole = ((CLoggingComponent*)pComponent)->m_spConsole; } _ASSERTE( spConsole != NULL ); hr = BringUpPropertySheetForNode( m_pLocalFileLoggingNode , pComponentData , pComponent , spConsole ); if( S_OK == hr ) { // We found a property sheet already up for this node. ShowErrorDialog( NULL, IDS_ERROR_CLOSE_PROPERTY_SHEET, NULL, hr, 0, spConsole ); return hr; } // reload SDO from hr = ((CLoggingMachineNode *) m_pParentNode)->DataRefresh(); m_pLocalFileLoggingNode->OnPropertyChange(arg, param, pComponentData, pComponent, type); // refresh the node // hr = CNodeWithResultChildrenList< CLoggingMethodsNode, CLocalFileLoggingNode, CSimpleArray, CLoggingComponentData, CLoggingComponent >::OnRefresh( arg, param, pComponentData, pComponent, type); return hr; } ////////////////////////////////////////////////////////////////////////////// /*++ CLoggingMethodsNode::InsertColumns See CNodeWithResultChildrenList::InsertColumns (which this method overrides) for detailed info. --*/ ////////////////////////////////////////////////////////////////////////////// HRESULT CLoggingMethodsNode::InsertColumns( IHeaderCtrl* pHeaderCtrl ) { ATLTRACE(_T("# CLoggingMethodsNode::InsertColumns\n")); // Check for preconditions: _ASSERTE( pHeaderCtrl != NULL ); HRESULT hr; int nLoadStringResult; TCHAR szLoggingMethod[IAS_MAX_STRING]; TCHAR szDescription[IAS_MAX_STRING]; nLoadStringResult = LoadString( _Module.GetResourceInstance(), IDS_LOGGING_METHODS_NODE__LOGGING_METHOD, szLoggingMethod, IAS_MAX_STRING ); _ASSERT( nLoadStringResult > 0 ); nLoadStringResult = LoadString( _Module.GetResourceInstance(), IDS_LOGGING_METHODS_NODE__DESCRIPTION, szDescription, IAS_MAX_STRING ); _ASSERT( nLoadStringResult > 0 ); hr = pHeaderCtrl->InsertColumn( 0, szLoggingMethod, LVCFMT_LEFT, COLUMN_WIDTH__LOGGING_METHOD ); _ASSERT( S_OK == hr ); hr = pHeaderCtrl->InsertColumn( 1, szDescription, LVCFMT_LEFT, COLUMN_WIDTH__DESCRIPTION ); _ASSERT( S_OK == hr ); return hr; } ////////////////////////////////////////////////////////////////////////////// /*++ CLoggingMethodsNode::PopulateResultChildrenList See CNodeWithResultChildrenList::PopulateResultChildrenList (which this method overrides) for detailed info. --*/ ////////////////////////////////////////////////////////////////////////////// HRESULT CLoggingMethodsNode::PopulateResultChildrenList( void ) { ATLTRACE(_T("# CLoggingMethodsNode::PopulateResultChildrenList\n")); // Check for preconditions: // None. HRESULT hr = S_OK; // ISSUE: in the future, when we have more than one kind of logging // method, we should make an abstract class called // CLoggingMethodNode which CLocalFileLoggingNode derives from. // Then we can pass CLoggingMethodNode as the child class for the // template to enable us to use different types of logging method // nodes here polymorphically. // This node should already have been created in our Constructor. // See notes there for reason why we didn't leave creating // it until now. _ASSERTE( NULL != m_pLocalFileLoggingNode ); return hr; } ////////////////////////////////////////////////////////////////////////////// /*++ CLoggingMethodsNode::GetComponentData This method returns our unique CComponentData object representing the scope pane of this snapin. It relies upon the fact that each node has a pointer to its parent, except for the root node, which instead has a member variable pointing to CComponentData. This would be a useful function to use if, for example, you need a reference to some IConsole but you weren't passed one. You can use GetComponentData and then use the IConsole pointer which is a member variable of our CComponentData object. --*/ ////////////////////////////////////////////////////////////////////////////// CLoggingComponentData * CLoggingMethodsNode::GetComponentData( void ) { ATLTRACE(_T("# CLoggingMethodsNode::GetComponentData\n")); // Check for preconditions: _ASSERTE( m_pParentNode ); return ((CLoggingMachineNode *) m_pParentNode)->GetComponentData(); } ////////////////////////////////////////////////////////////////////////////// /*++ CLoggingMethodsNode::GetServerRoot This method returns the Server node under which this node can be found. It relies upon the fact that each node has a pointer to its parent, all the way up to the server node. This would be a useful function to use if, for example, you need a reference to some data specific to a server. --*/ ////////////////////////////////////////////////////////////////////////////// CLoggingMachineNode * CLoggingMethodsNode::GetServerRoot( void ) { ATLTRACE(_T("# CLoggingMethodsNode::GetServerRoot\n")); // Check for preconditions: _ASSERTE( m_pParentNode != NULL ); return (CLoggingMachineNode *) m_pParentNode; } ////////////////////////////////////////////////////////////////////////////// /*++ CLoggingMethodsNode::OnPropertyChange This is our own custom response to the MMCN_PROPERTY_CHANGE notification. MMC never actually sends this notification to our snapin with a specific lpDataObject, so it would never normally get routed to a particular node but we have arranged it so that our property pages can pass the appropriate CSnapInItem pointer as the param argument. In our CComponent::Notify override, we map the notification message to the appropriate node using the param argument. --*/ ////////////////////////////////////////////////////////////////////////////// HRESULT CLoggingMethodsNode::OnPropertyChange( LPARAM arg , LPARAM param , IComponentData * pComponentData , IComponent * pComponent , DATA_OBJECT_TYPES type ) { ATLTRACE(_T("# CLoggingMethodsNode::OnPropertyChange\n")); // Check for preconditions: // None. return LoadCachedInfoFromSdo(); } ////////////////////////////////////////////////////////////////////////////// /*++ CLoggingMethodsNode::LoadCachedInfoFromSdo Causes this node and its children to re-read all their cached info from the SDO's. Call if you change something and you want to make sure that the display reflects this change. --*/ ////////////////////////////////////////////////////////////////////////////// HRESULT CLoggingMethodsNode::LoadCachedInfoFromSdo( void ) { ATLTRACE(_T("# CLoggingMethodsNode::LoadCachedInfoFromSdo\n")); // Check for preconditions: HRESULT hr; // Do it to each of its children. // At the moment, there should only ever be one child // to do this to. CLocalFileLoggingNode* pChildNode; int iSize = m_ResultChildrenList.GetSize(); for (int i = 0; i < iSize; i++) { pChildNode = m_ResultChildrenList[i]; _ASSERTE( pChildNode != NULL ); hr = pChildNode->LoadCachedInfoFromSdo(); // Ignore failed HRESULT. } return S_OK; } ////////////////////////////////////////////////////////////////////////////// /*++ CPoliciesNode::FillData The server node need to override CSnapInItem's implementation of this so that we can also support a clipformat for exchanging machine names with any snapins extending us. --*/ ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CLoggingMethodsNode::FillData(CLIPFORMAT cf, LPSTREAM pStream) { ATLTRACE(_T("# CClientsNode::FillData\n")); // Check for preconditions: // None. HRESULT hr = DV_E_CLIPFORMAT; ULONG uWritten = 0; if (cf == CF_MMC_NodeID) { ::CString SZNodeID = (LPCTSTR)GetSZNodeType(); if (INTERNET_AUTHENTICATION_SERVICE_SNAPIN == GetServerRoot()->m_enumExtendedSnapin) SZNodeID += L":Ext_IAS:"; SZNodeID += GetServerRoot()->m_bstrServerAddress; DWORD dwIdSize = 0; SNodeID2* NodeId = NULL; BYTE *id = NULL; DWORD textSize = (SZNodeID.GetLength()+ 1) * sizeof(TCHAR); dwIdSize = textSize + sizeof(SNodeID2); try{ NodeId = (SNodeID2 *)_alloca(dwIdSize); } catch(...) { hr = E_OUTOFMEMORY; return hr; } NodeId->dwFlags = 0; NodeId->cBytes = textSize; memcpy(NodeId->id,(BYTE*)(LPCTSTR)SZNodeID, textSize); hr = pStream->Write(NodeId, dwIdSize, &uWritten); return hr; } // Call the method which we're overriding to let it handle the // rest of the possible cases as usual. return CNodeWithResultChildrenList< CLoggingMethodsNode, CLocalFileLoggingNode, CSimpleArray, CLoggingComponentData, CLoggingComponent >::FillData( cf, pStream ); }