windows-nt/Source/XPSP1/NT/admin/activec/samples/benefits/bennodes.cpp
2020-09-26 16:20:57 +08:00

713 lines
18 KiB
C++

//+-------------------------------------------------------------------------
//
// 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<IConsole> 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<CHealthNode> ( 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<IConsole> 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<IConsole> 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<MMC_TASK> > > 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<CKeyNode>( 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<IHeaderCtrl> 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<IConsole> 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<CBuildingNode*>( 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 );
}