//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1999 - 1999 // // File: bennodes.cpp // //-------------------------------------------------------------------------- // BenefitsNodes.cpp // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "resource.h" #include "BenNodes.h" #include "Dialogs.h" static const GUID CBuildingNodeGUID_NODETYPE = { 0xec362ef4, 0xd94d, 0x11d1, { 0x84, 0x74, 0x0, 0x10, 0x4b, 0x21, 0x1b, 0xe5 } }; const GUID* CBuildingNode::m_NODETYPE = &CBuildingNodeGUID_NODETYPE; const TCHAR* CBuildingNode::m_SZNODETYPE = _T("EC362EF4-D94D-11D1-8474-00104B211BE5"); const TCHAR* CBuildingNode::m_SZDISPLAY_NAME = _T("Building"); const CLSID* CBuildingNode::m_SNAPIN_CLASSID = &CLSID_Benefits; // // The following constructor initialiazes its base-class members and // initializes the building name, location, etc. // CBuildingNode::CBuildingNode( CKeyNode* pParentNode, BSTR strName, BSTR bstrLocation ) : CBenefitsData< CBuildingNode >( NULL ) { _ASSERTE( pParentNode != NULL ); m_resultDataItem.nImage = 3; m_bstrDisplayName = strName; m_bstrLocation = bstrLocation; // // Save the parent node for deletion purposes. // m_pParentNode = pParentNode; } // // Copy constructor. // CBuildingNode::CBuildingNode( const CBuildingNode &inNode ) : CBenefitsData< CBuildingNode >( NULL ) { m_resultDataItem.nImage = inNode.m_resultDataItem.nImage; m_bstrDisplayName = inNode.m_bstrDisplayName; m_bstrLocation = inNode.m_bstrLocation; m_pParentNode = inNode.m_pParentNode; } // // Overridden to provide strings for various columns. // LPOLESTR CBuildingNode::GetResultPaneColInfo(int nCol) { CComBSTR szText; // The following switch statement dispatches to the // appropriate column index and loads the necessary // string. switch ( nCol ) { case 0: szText = m_bstrDisplayName; break; case 1: szText = m_bstrLocation; break; default: ATLTRACE( "An invalid column index was passed to GetResultPaneColInfo()\n" ); } return( szText.Copy() ); } static const GUID CRetirementNodeGUID_NODETYPE = { 0xec362ef2, 0xd94d, 0x11d1, { 0x84, 0x74, 0x0, 0x10, 0x4b, 0x21, 0x1b, 0xe5 } }; const GUID* CRetirementNode::m_NODETYPE = &CRetirementNodeGUID_NODETYPE; const TCHAR* CRetirementNode::m_SZNODETYPE = _T("EC362EF2D94D-11D1-8474-00104B211BE5"); const TCHAR* CRetirementNode::m_SZDISPLAY_NAME = _T("401K Plan"); const CLSID* CRetirementNode::m_SNAPIN_CLASSID = &CLSID_Benefits; // // The following constructor initialiazes its base-class members with // hard-coded values for display purposes. Since these are static nodes, // hard-coded values can be used for the following values. // CRetirementNode::CRetirementNode( CEmployee* pCurEmployee ) : CBenefitsData< CRetirementNode > ( pCurEmployee ) { m_scopeDataItem.nOpenImage = m_scopeDataItem.nImage = 0; m_scopeDataItem.cChildren = 0; // Not necessary unless modified. } CRetirementNode::~CRetirementNode() { } // // Specifies that the results should display a web page as its results. In // addition, the view options should be set so that standard lists, which // won't be applicable to this node, should not be available to the user. // STDMETHODIMP CRetirementNode::GetResultViewType( LPOLESTR* ppViewType, long* pViewOptions ) { USES_CONVERSION; // // For this example to work, the sample control must be installed. // TCHAR* pszControl = _T( "{FE148827-3093-11D2-8494-00104B211BE5}" ); // CoTaskMemAlloc(...) must be used since the MMC client frees the space using // CoTaskMemFree(...). Include enough space for NULL. // *ppViewType = (LPOLESTR) CoTaskMemAlloc( ( _tcslen( pszControl ) + 1 ) * sizeof( OLECHAR ) ); _ASSERTE( *ppViewType != NULL ); ocscpy( *ppViewType, T2OLE( pszControl ) ); // // Set the view options so that no lists are displayed. // *pViewOptions = MMC_VIEW_OPTIONS_NOLISTVIEWS; return( S_OK ); } // // Overridden to provide strings for various columns. // LPOLESTR CRetirementNode::GetResultPaneColInfo(int nCol) { CComBSTR szText; // The following switch statement dispatches to the // appropriate column index and loads the necessary // string. switch ( nCol ) { case 0: szText = m_bstrDisplayName; break; case 1: szText.LoadString( _Module.GetResourceInstance(), IDS_RETIREMENT_DESC ); break; default: ATLTRACE( "An invalid column index was passed to GetResultPaneColInfo()\n" ); } return( szText.Copy() ); } // // Command handler for "Enroll" functionality. // STDMETHODIMP CRetirementNode::OnEnroll( bool& bHandled, CSnapInObjectRootBase* pObj ) { UNUSED_ALWAYS( bHandled ); UNUSED_ALWAYS( pObj ); #ifdef _BENEFITS_DIALOGS CRetirementEnrollDialog dlg; dlg.SetEmployee( m_pEmployee ); dlg.DoModal(); #else CComPtr spConsole; int nResult; // // Retrieve the appropriate console. // GetConsole( pObj, &spConsole ); spConsole->MessageBox( L"Enrolled", L"Benefits", MB_ICONINFORMATION | MB_OK, &nResult ); #endif return( S_OK ); } // // Command handler for "Update" functionality. Demonstrates calling a // displayed OCX's method. // STDMETHODIMP CRetirementNode::OnUpdate( bool& bHandled, CSnapInObjectRootBase* pObj ) { UNUSED_ALWAYS( bHandled ); UNUSED_ALWAYS( pObj ); HRESULT hr = E_FAIL; if ( m_spControl ) { // // This should trigger the OCX to refresh its historical information. // hr = m_spControl->Refresh(); } return( hr ); } static const GUID CHealthNodeGUID_NODETYPE = { 0xec362ef1, 0xd94d, 0x11d1, { 0x84, 0x74, 0x0, 0x10, 0x4b, 0x21, 0x1b, 0xe5 } }; const GUID* CHealthNode::m_NODETYPE = &CHealthNodeGUID_NODETYPE; const TCHAR* CHealthNode::m_SZNODETYPE = _T("EC362EF1D94D-11D1-8474-00104B211BE5"); const TCHAR* CHealthNode::m_SZDISPLAY_NAME = _T("Health & Dental Plan"); const CLSID* CHealthNode::m_SNAPIN_CLASSID = &CLSID_Benefits; // // Hard coded tasks to be associated with the health node. // MMC_TASK g_HealthTasks[ 3 ] = { { MMC_TASK_DISPLAY_TYPE_VANILLA_GIF, L"img\\WebPage.gif", L"img\\WebPage.gif", L"Microsoft", L"General Microsoft resources", MMC_ACTION_LINK, (long) L"http://www.microsoft.com" }, { MMC_TASK_DISPLAY_TYPE_VANILLA_GIF, L"img\\WebPage.gif", L"img\\WebPage.gif", L"Microsoft Management Site", L"More MMC oriented resources", MMC_ACTION_LINK, (long) L"http://www.microsoft.com/management" }, { MMC_TASK_DISPLAY_TYPE_VANILLA_GIF, L"img\\Query.gif", L"img\\Query.gif", L"Local Query", L"Start query on local database", MMC_ACTION_ID, TASKPAD_LOCALQUERY }, }; // // The following constructor initialiazes its base-class members with // hard-coded values for display purposes. Since these are static nodes, // hard-coded values can be used for the following values. // CHealthNode::CHealthNode( CEmployee* pCurEmployee ) : CBenefitsData ( pCurEmployee ) { m_scopeDataItem.nOpenImage = m_scopeDataItem.nImage = 1; m_scopeDataItem.cChildren = 0; // Not necessary unless modified. m_fTaskpad = FALSE; } CHealthNode::~CHealthNode() { } // // Specifies that the results should display a web page as its results. In // addition, the view options should be set so that standard lists, which // won't be applicable to this node, should not be available to the user. // STDMETHODIMP CHealthNode::GetResultViewType( LPOLESTR* ppViewType, long* pViewOptions ) { USES_CONVERSION; TCHAR szPath[ _MAX_PATH ]; TCHAR szModulePath[ _MAX_PATH ]; // // Set the view options to no preferences. // *pViewOptions = MMC_VIEW_OPTIONS_NONE; if ( m_fTaskpad ) { // // In the taskpad case, the module path of MMC.EXE should be // obtained. Use the template contained therein. // GetModuleFileName( NULL, szModulePath, _MAX_PATH ); // // Append the necessary decorations for correct access. // _tcscpy( szPath, _T( "res://" ) ); _tcscat( szPath, szModulePath ); _tcscat( szPath, _T( "/default.htm" ) ); } else { // // Use the HTML page that is embedded as a resource of // this module for display purposes. // GetModuleFileName( _Module.GetModuleInstance(), szModulePath, _MAX_PATH ); // // Append the necessary decorations for correct access. // _tcscpy( szPath, _T( "res://" ) ); _tcscat( szPath, szModulePath ); _tcscat( szPath, _T( "/health.htm" ) ); } // // CoTaskMemAlloc(...) must be used since the MMC client frees the space using // CoTaskMemFree(...). Include enough space for NULL. // *ppViewType = (LPOLESTR) CoTaskMemAlloc( ( _tcslen( szPath ) + 1 ) * sizeof( OLECHAR ) ); _ASSERTE( *ppViewType != NULL ); ocscpy( *ppViewType, T2OLE( szPath ) ); return( S_OK ); } // // Overridden to provide strings for various columns. // LPOLESTR CHealthNode::GetResultPaneColInfo(int nCol) { USES_CONVERSION; CComBSTR szText; // The following switch statement dispatches to the // appropriate column index and loads the necessary // string. switch ( nCol ) { case 0: szText = m_bstrDisplayName; break; case 1: szText.LoadString( _Module.GetResourceInstance(), IDS_HEALTH_DESC ); break; default: ATLTRACE( "An invalid column index was passed to GetResultPaneColInfo()\n" ); } return( szText.Copy() ); } // // Command handler for "Enroll" functionality. // STDMETHODIMP CHealthNode::OnEnroll( bool& bHandled, CSnapInObjectRootBase* pObj ) { UNUSED_ALWAYS( bHandled ); UNUSED_ALWAYS( pObj ); #ifdef _BENEFITS_DIALOGS CHealthEnrollDialog dlg; dlg.SetEmployee( m_pEmployee ); dlg.DoModal(); #else CComPtr spConsole; int nResult; // // Retrieve the appropriate console. // GetConsole( pObj, &spConsole ); spConsole->MessageBox( L"Enrolled", L"Benefits", MB_ICONINFORMATION | MB_OK, &nResult ); #endif return( S_OK ); } // // Restores any state, especially in the case of using a // taskpad, when the back and forward buttons are used by // the user for navigation. // STDMETHODIMP CHealthNode::OnRestoreView( MMC_RESTORE_VIEW* pRestoreView, BOOL* pfHandled ) { _ASSERTE( pRestoreView->dwSize == sizeof( MMC_RESTORE_VIEW ) ); *pfHandled = TRUE; return( S_OK ); } // // Called when one of the tasks is clicked. // STDMETHODIMP CHealthNode::TaskNotify( IConsole* pConsole, VARIANT* arg, VARIANT* param ) { UNUSED_ALWAYS( arg ); UNUSED_ALWAYS( param ); HRESULT hr = E_FAIL; // // Determine if the given notification is for the // start query button. // if ( arg->lVal == TASKPAD_LOCALQUERY ) { CComPtr spConsole = pConsole; int nResult; // // Display a message box to demonstrate the // handling of the taskpad notification. // spConsole->MessageBox( L"Local query started", L"Health Taskpad", MB_ICONINFORMATION | MB_OK, &nResult ); hr = S_OK; } return( hr ); } // // Returns an enumerator for all of these tasks. // STDMETHODIMP CHealthNode::EnumTasks( LPOLESTR szTaskGroup, IEnumTASK** ppEnumTASK ) { UNUSED_ALWAYS( szTaskGroup ); MMC_TASK CoTasks[ sizeof( g_HealthTasks ) / sizeof( MMC_TASK ) ]; typedef CComObject< CComEnum< IEnumTASK, &IID_IEnumTASK, MMC_TASK, _Copy > > enumvar; enumvar* p = new enumvar; // // Copy the local tasks to our temporary task structures. This // performs the CoTaskMemAlloc for the strings, etc. It also // maps image type resources to the local module name. // if ( CoTasksDup( CoTasks, g_HealthTasks, sizeof( g_HealthTasks ) / sizeof( MMC_TASK ) ) ) { p->Init( &CoTasks[ 0 ], &CoTasks[ sizeof( g_HealthTasks ) / sizeof( MMC_TASK ) ], NULL, AtlFlagCopy); return( p->QueryInterface( IID_IEnumTASK, (void**) ppEnumTASK ) ); } return( E_FAIL ); } static const GUID CKeyNodeGUID_NODETYPE = { 0xec362ef3, 0xd94d, 0x11d1, { 0x84, 0x74, 0x0, 0x10, 0x4b, 0x21, 0x1b, 0xe5 } }; const GUID* CKeyNode::m_NODETYPE = &CKeyNodeGUID_NODETYPE; const TCHAR* CKeyNode::m_SZNODETYPE = _T("EC362EF3D94D-11D1-8474-00104B211BE5"); const TCHAR* CKeyNode::m_SZDISPLAY_NAME = _T("Card Key Permissions"); const CLSID* CKeyNode::m_SNAPIN_CLASSID = &CLSID_Benefits; // // Used for the key node example. // extern BUILDINGDATA g_Buildings[ 3 ]; // // The following constructor initialiazes its base-class members with // hard-coded values for display purposes. Since these are static nodes, // hard-coded values can be used for the following values. // CKeyNode::CKeyNode( CEmployee* pCurEmployee ) : CChildrenBenefitsData( pCurEmployee ) { USES_CONVERSION; m_scopeDataItem.nOpenImage = m_scopeDataItem.nImage = 2; m_scopeDataItem.cChildren = 0; // Not necessary unless modified. // // Populate building nodes based on this employees permissions. // for ( int i = 0; i < sizeof( g_Buildings ) / sizeof( BUILDINGDATA ); i++ ) { // // Only add an item if the given employee has access to the // building. // if ( g_Buildings[ i ].dwId & pCurEmployee->m_Access.dwAccess ) { CSnapInItem* pItem; pItem = new CBuildingNode( this, W2BSTR( g_Buildings[ i ].pstrName ), W2BSTR( g_Buildings[ i ].pstrLocation ) ); m_Nodes.Add( pItem ); } } } CKeyNode::~CKeyNode() { } // // Overridden to provide strings for various columns. // LPOLESTR CKeyNode::GetResultPaneColInfo(int nCol) { CComBSTR szText; // The following switch statement dispatches to the // appropriate column index and loads the necessary // string. switch ( nCol ) { case 0: szText = m_bstrDisplayName; break; case 1: szText.LoadString( _Module.GetResourceInstance(), IDS_KEY_DESC ); break; default: ATLTRACE( "An invalid column index was passed to GetResultPaneColInfo()\n" ); } return( szText.Copy() ); } // // Overridden to add new columns to the results // display. // STDMETHODIMP CKeyNode::OnShowColumn( IHeaderCtrl* pHeader ) { USES_CONVERSION; HRESULT hr = E_FAIL; CComPtr spHeader( pHeader ); // Add two columns: one with the name of the object and one with // the description of the node. Use the value of 100 pixels as the size. hr = spHeader->InsertColumn( 0, T2OLE( _T( "Building" ) ), LVCFMT_LEFT, 200 ); _ASSERTE( SUCCEEDED( hr ) ); // Add the second column. Use the value of 200 pixels as the size. hr = spHeader->InsertColumn( 1, T2OLE( _T( "Location" ) ), LVCFMT_LEFT, 350 ); _ASSERTE( SUCCEEDED( hr ) ); return( hr ); } // // Command handler for "Grant Access" functionality. // STDMETHODIMP CKeyNode::OnGrantAccess( bool& bHandled, CSnapInObjectRootBase* pObj ) { UNUSED_ALWAYS( bHandled ); UNUSED_ALWAYS( pObj ); #ifdef _BENEFITS_DIALOGS CBuildingAccessDialog dlg; dlg.SetEmployee( m_pEmployee ); dlg.DoModal(); #else CComPtr spConsole; int nResult; // // Retrieve the appropriate console. // GetConsole( pObj, &spConsole ); spConsole->MessageBox( L"Access granted", L"Benefits", MB_ICONINFORMATION | MB_OK, &nResult ); #endif return( S_OK ); } // // Called by the console to determine if we can paste the // specified node. // STDMETHODIMP CKeyNode::OnQueryPaste( LPDATAOBJECT pDataObject ) { HRESULT hr; // // Determine if the type of object being pasted is the right // type. // hr = IsClipboardDataType( pDataObject, CBuildingNodeGUID_NODETYPE ); if ( SUCCEEDED( hr ) ) { CBuildingNode* pItem; DATA_OBJECT_TYPES Type; // // Loop through all of currently contained nodes and // determine if we already contain the specified building // by comparing building names. // hr = CSnapInItem::GetDataClass( pDataObject, (CSnapInItem**) &pItem, &Type ); if ( SUCCEEDED( hr ) ) { for ( int i = 0; i < m_Nodes.GetSize(); i++ ) { CBuildingNode* pTemp; CComBSTR bstrTemp; // // Retrieve the node from our internal list. // pTemp = dynamic_cast( m_Nodes[ i ] ); _ASSERTE( pTemp != NULL ); // // If the names are equal, indicate failure // and break out. // if ( wcscmp( pItem->m_bstrDisplayName, pTemp->m_bstrDisplayName ) == 0 ) { hr = S_FALSE; break; } } } } return( hr ); } // // Called by MMC when the item should be pasted. // STDMETHODIMP CKeyNode::OnPaste( IConsole* pConsole, LPDATAOBJECT pDataObject, LPDATAOBJECT* ppDataObject ) { HRESULT hr; // // Ensure the data is of the correct type. // hr = IsClipboardDataType( pDataObject, CBuildingNodeGUID_NODETYPE ); if ( SUCCEEDED( hr ) ) { try { CBuildingNode* pItem; DATA_OBJECT_TYPES Type; // // Retrieve the passed in item. // hr = CSnapInItem::GetDataClass( pDataObject, (CSnapInItem**) &pItem, &Type ); if ( FAILED( hr ) ) throw; // // Allocate a new building node. The constructor // copies the values from the input node. // CSnapInItem* pNewNode = new CBuildingNode( *pItem ); if ( pNewNode == NULL ) throw; // // Add the node to the end of our internal array. // m_Nodes.Add( pNewNode ); // // Reselect ourselves to cause a refresh. // pConsole->SelectScopeItem( m_scopeDataItem.ID ); // // Put the given data object into the returned dataobject // so that MMC may complete its cut tasks. // *ppDataObject = pDataObject; hr = S_OK; } catch( ... ) { // // Assume all failures are total. // hr = E_FAIL; } } return( hr ); } // // Called by one of our children nodes to inform us that // they should be deleted. This occurs when the user selects // a delete action on the building. This function should not // only delete the building, but also handle the refresh of // the result display. // STDMETHODIMP CKeyNode::OnDeleteBuilding( IConsole* pConsole, CBuildingNode* pChildNode ) { _ASSERTE( pConsole != NULL ); _ASSERTE( pChildNode != NULL ); HRESULT hr = E_FAIL; // // First, loop through all of our contained members and // remove it from the contained list. // for ( int i = 0; i < m_Nodes.GetSize(); i++ ) { if ( m_Nodes[ i ] == pChildNode ) { // // We have found a match. Remove it from the // contained list. // m_Nodes.RemoveAt( i ); // // Reselect ourselves to cause a refresh. // pConsole->SelectScopeItem( m_scopeDataItem.ID ); // // Since there should only be one match, break out // of the find process. Indicate success. // hr = S_OK; break; } } return( hr ); }