//+---------------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1997-2001.
//
//  File:       cmponent.cpp
//
//  Contents:   Implementation of CCertTmplComponent
//
//----------------------------------------------------------------------------

#include "stdafx.h"

#include "dbg.h"
#include "compdata.h" // CCertTmplComponentData
#include "dataobj.h"
#include "cmponent.h" // CCertTmplComponent
#include "utils.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

DECLARE_INFOLEVEL(CertTmplSnapin)

USE_HANDLE_MACROS ("CERTTMPL (cmponent.cpp)")

#pragma warning(push,3)
#include "stdcmpnt.cpp" // CComponent
#pragma warning(pop)

UINT m_aColumnsSnapinSelected[CERT_TEMPLATES_NUM_COLS+1] =
	{IDS_COLUMN_CERT_TEMPLATE_OBJECT,
        IDS_COLUMN_CERT_TEMPLATE_TYPE,
        IDS_COLUMN_CERT_TEMPLATE_VERSION,
        IDS_COLUMN_CERT_TEMPLATE_AUTOENROLLMENT,
		0};

UINT* m_Columns[CERTTMPL_NUMTYPES] =
	{	
		m_aColumnsSnapinSelected,   // CERTTMPL_SNAPIN (displays certificate templates in the result pane)
        0
	};



UINT** g_aColumns = 0;	// for framework
int** g_aColumnWidths = 0;  // for framework
const int SINGLE_COL_WIDTH = 300;

CCertTmplComponent::CCertTmplComponent ()
	: m_pViewedCookie (NULL),
	m_currResultNodeType (CERTTMPL_INVALID)
{
	_TRACE (1, L"Entering CCertTmplComponent::CCertTmplComponent\n");
    AFX_MANAGE_STATE (AfxGetStaticModuleState ( ));

    ::ZeroMemory (m_ColumnWidths, (sizeof (UINT*) * CERTTMPL_NUMTYPES));

	m_ColumnWidths[CERTTMPL_SNAPIN] = new UINT[CERT_TEMPLATES_NUM_COLS];
	if ( m_ColumnWidths[CERTTMPL_SNAPIN] )
	{
		m_ColumnWidths[CERTTMPL_SNAPIN][COLNUM_CERT_TEMPLATE_OBJECT] = 250;
        m_ColumnWidths[CERTTMPL_SNAPIN][COLNUM_CERT_TEMPLATE_TYPE] = 150;
        m_ColumnWidths[CERTTMPL_SNAPIN][COLNUM_CERT_TEMPLATE_VERSION] = 50;
        m_ColumnWidths[CERTTMPL_SNAPIN][COLNUM_CERT_TEMPLATE_AUTOENROLL_STATUS] = 100;
	}

	_TRACE (-1, L"Leaving CCertTmplComponent::CCertTmplComponent\n");
}

CCertTmplComponent::~CCertTmplComponent ()
{
	_TRACE (1, L"Entering CCertTmplComponent::~CCertTmplComponent\n");
	VERIFY ( SUCCEEDED (ReleaseAll ()) );

	for (int i = 0; i < CERTTMPL_NUMTYPES; i++)
	{
        if ( m_ColumnWidths[i] )
		    delete [] m_ColumnWidths[i];
	}
	_TRACE (-1, L"Leaving CCertTmplComponent::~CCertTmplComponent\n");
}

HRESULT CCertTmplComponent::ReleaseAll ()
{
	return CComponent::ReleaseAll ();
}


/////////////////////////////////////////////////////////////////////////////
// IComponent Implementation

HRESULT CCertTmplComponent::LoadStrings ()
{
	return S_OK;
}

HRESULT CCertTmplComponent::LoadColumns ( CCertTmplCookie* pcookie )
{
    AFX_MANAGE_STATE (AfxGetStaticModuleState ());
	_TRACE (1, L"Entering CCertTmplComponent::LoadColumns\n");
	HRESULT	hr = S_OK;


	hr = LoadColumnsFromArrays (pcookie->m_objecttype);

	_TRACE (-1, L"Leaving CCertTmplComponent::LoadColumns\n");
	return hr;
}


/* This is generated by UpdateAllViews () */
HRESULT CCertTmplComponent::OnViewChange (LPDATAOBJECT pDataObject, LPARAM /*data*/, LPARAM hint)
{
	_TRACE (1, L"Entering CCertTmplComponent::OnViewChange\n");
	ASSERT (pDataObject);
	if ( !pDataObject )
		return E_POINTER;

	CCertTmplComponentData&	compData = QueryComponentDataRef ();
	HRESULT					hr = S_OK;

	if ( hint & UPDATE_HINT_ENUM_CERT_TEMPLATES )
	{
		hr = RefreshResultPane (false);
		return hr;
	}
    
	hr = RefreshResultPane (false);


	CCertTmplCookie* pCookie = compData.ConvertCookie (pDataObject);
	if ( pCookie )
	{
		switch (pCookie->m_objecttype)
		{
        case CERTTMPL_CERT_TEMPLATE:
            break;

		case CERTTMPL_SNAPIN:
			break;

		default:
			{
				IConsole2*	pConsole2 = 0;
				hr = m_pConsole->QueryInterface (
						IID_PPV_ARG(IConsole2, &pConsole2));
				if (SUCCEEDED (hr))
				{
					hr = pConsole2->SetStatusText (L"");
					if ( !SUCCEEDED (hr) )
					{
						_TRACE (0, L"IConsole2::SetStatusText () failed: %x", hr);
					}
					pConsole2->Release ();
				}
			}
			break;
		}
	}

	_TRACE (-1, L"Leaving CCertTmplComponent::OnViewChange\n");
	return hr;
}

HRESULT CCertTmplComponent::Show (
        CCookie* pcookie, 
        LPARAM arg, 
        HSCOPEITEM /*hScopeItem*/, 
        LPDATAOBJECT /*pDataObject*/)
{
    AFX_MANAGE_STATE (AfxGetStaticModuleState ());
	HRESULT	hr = S_OK;

	if ( !arg )
	{
		if ( !m_pResultData )
		{
			ASSERT ( FALSE );
			return E_UNEXPECTED;
		}

		m_pViewedCookie = dynamic_cast <CCertTmplCookie*> (pcookie);
		ASSERT (m_pViewedCookie);
		if ( m_pViewedCookie )
			hr = SaveWidths (m_pViewedCookie);
		m_pViewedCookie = 0;
		return S_OK;
	}

	m_pViewedCookie = dynamic_cast <CCertTmplCookie*> (pcookie);
	ASSERT (m_pViewedCookie);
	if ( m_pViewedCookie )
	{
		// Load default columns and widths
		LoadColumns (m_pViewedCookie);

		// Restore persisted column widths
		switch (m_pViewedCookie->m_objecttype)
		{
		case CERTTMPL_SNAPIN:
			break;

        case CERTTMPL_CERT_TEMPLATE:  // not a scope pane item
            ASSERT (0);
            break;

		default:
			ASSERT (0);
			break;
		}

		hr = PopulateListbox (m_pViewedCookie);
		if ( FAILED (hr) )
		{
            CString caption;
            CString text;

            VERIFY (caption.LoadString (IDS_CERTTMPL));

            text.FormatMessage (IDS_CANNOT_ENUM_CERT_TEMPLATES, GetSystemMessage (hr));

		    int		iRetVal = 0;
		    VERIFY (SUCCEEDED (m_pConsole->MessageBox (text, caption,
			    MB_ICONWARNING | MB_OK, &iRetVal)));
		}
	}

	return hr;
}

HRESULT CCertTmplComponent::Show ( CCookie* pcookie, LPARAM arg, HSCOPEITEM hScopeItem)
{
	ASSERT (0);
	return Show (pcookie, arg, hScopeItem, 0);
}


HRESULT CCertTmplComponent::OnNotifyAddImages (LPDATAOBJECT /*pDataObject*/,
	                                             LPIMAGELIST lpImageList,
	                                             HSCOPEITEM /*hSelectedItem*/)
{
	long	lViewMode = 0;

	ASSERT (m_pResultData);
	QueryComponentDataRef ().SetResultData (m_pResultData);

	HRESULT	hr = m_pResultData->GetViewMode (&lViewMode);	
	ASSERT (SUCCEEDED (hr));
	BOOL	bLoadLargeIcons = (LVS_ICON == lViewMode);

	return QueryComponentDataRef ().LoadIcons (lpImageList, bLoadLargeIcons);
}


HRESULT CCertTmplComponent::PopulateListbox (CCertTmplCookie* pCookie)
{
	_TRACE (1, L"Entering CCertTmplComponent::PopulateListbox\n");
	HRESULT		hr = S_OK;

	
	switch ( pCookie->m_objecttype )
	{
	case CERTTMPL_SNAPIN:
		hr = AddEnterpriseTemplates ();
		if ( SUCCEEDED (hr) )
		{
        	m_currResultNodeType = CERTTMPL_CERT_TEMPLATE;
        }
        break;

    case CERTTMPL_CERT_TEMPLATE:
        ASSERT (0);
        break;

	default:
        ASSERT (0);
		break;
	}

	_TRACE (-1, L"Leaving CCertTmplComponent::PopulateListbox\n");
	return hr;
}

HRESULT CCertTmplComponent::RefreshResultPane (const bool bSilent)
{
	_TRACE (1, L"Entering CCertTmplComponent::RefreshResultPane\n");
	HRESULT hr = S_OK;

	ASSERT (NULL != m_pResultData);
	if ( m_pResultData )
	{
		m_pResultData->DeleteAllRsltItems ();
	}
	else
		hr = E_UNEXPECTED;

	if ( m_pViewedCookie )
	{
		hr = PopulateListbox (m_pViewedCookie);
		if ( FAILED (hr) && !bSilent )
		{
            CString caption;
            CString text;

            VERIFY (caption.LoadString (IDS_CERTTMPL));

            text.FormatMessage (IDS_CANNOT_ENUM_CERT_TEMPLATES, GetSystemMessage (hr));

		    int		iRetVal = 0;
		    VERIFY (SUCCEEDED (m_pConsole->MessageBox (text, caption,
			    MB_ICONWARNING | MB_OK, &iRetVal)));
		}
	}

	_TRACE (-1, L"Leaving CCertTmplComponent::RefreshResultPane\n");
	return hr;
}

STDMETHODIMP CCertTmplComponent::GetDisplayInfo (RESULTDATAITEM * pResult)
{	
	AFX_MANAGE_STATE (AfxGetStaticModuleState ());
	ASSERT (pResult);
	HRESULT hr = S_OK;


	if ( pResult && !pResult->bScopeItem ) //&& (pResult->mask & RDI_PARAM) )
	{
		CCookie* pResultCookie = reinterpret_cast<CCookie*> (pResult->lParam);
		ASSERT (pResultCookie);
		if ( !pResultCookie || IsBadWritePtr ((LPVOID) pResultCookie, sizeof (CCookie)) )
			return E_UNEXPECTED;

		CCookie* pActiveCookie = ActiveBaseCookie (pResultCookie);
		ASSERT (pActiveCookie);
		if ( !pActiveCookie || IsBadWritePtr ((LPVOID) pActiveCookie, sizeof (CCookie)) )
			return E_UNEXPECTED;

		CCertTmplCookie* pCookie = dynamic_cast <CCertTmplCookie*>(pActiveCookie);
		ASSERT (pCookie);
		switch (pCookie->m_objecttype)
		{
        case CERTTMPL_CERT_TEMPLATE:
			{
				CCertTemplate* pCertTemplate = reinterpret_cast <CCertTemplate*> (pCookie);
				ASSERT (pCertTemplate);
				if ( pCertTemplate )
				{
					if (pResult->mask & RDI_STR)
					{
						// Note:  text is first stored in class variable so that the buffer is
						// somewhat persistent.  Copying the buffer pointer directly to the
						// pResult->str would result in the buffer being freed before the pointer
						// is used.
						switch (pResult->nCol)
						{
						case COLNUM_CERT_TEMPLATE_OBJECT:
							m_szDisplayInfoResult = pCertTemplate->GetDisplayName ();
							break;

                        case COLNUM_CERT_TEMPLATE_TYPE:
                            {
                                DWORD   dwVersion = pCertTemplate->GetType ();
                                switch (dwVersion)
                                {
                                case 1:
                                    VERIFY (m_szDisplayInfoResult.LoadString (IDS_WINDOWS_2000_AND_LATER));
                                    break;

                                case 2:
                                    VERIFY (m_szDisplayInfoResult.LoadString (IDS_WINDOWS_2002_AND_LATER));
                                    break;

                                default:
                                    break;
                                }
                            }
                            break;

                        case COLNUM_CERT_TEMPLATE_VERSION:
                            {
                                DWORD   dwMajorVersion = 0;
                                DWORD   dwMinorVersion = 0;

                                hr = pCertTemplate->GetMajorVersion (dwMajorVersion);
                                if ( SUCCEEDED (hr) )
                                {
                                    hr = pCertTemplate->GetMinorVersion (dwMinorVersion);
                                    if ( SUCCEEDED (hr) )
                                    {
                                        WCHAR   str[32];
                                        m_szDisplayInfoResult = _ultow (dwMajorVersion, str, 10);
                                        m_szDisplayInfoResult += L".";
                                        m_szDisplayInfoResult += _ultow (dwMinorVersion, str, 10);
                                    }
                                }
                            }
                            break;

                        case COLNUM_CERT_TEMPLATE_AUTOENROLL_STATUS:
                            if ( pCertTemplate->GoodForAutoEnrollment () )
                                VERIFY (m_szDisplayInfoResult.LoadString (IDS_VALID_FOR_AUTOENROLLMENT));
                            else
                                VERIFY (m_szDisplayInfoResult.LoadString (IDS_INVALID_FOR_AUTOENROLLMENT));
                            break;

                        default:
							ASSERT (0);
							break;
						}

						pResult->str = const_cast<LPWSTR> ( (LPCWSTR) m_szDisplayInfoResult);
					}
					if (pResult->mask & RDI_IMAGE)
                    {
                        if ( 1 == pCertTemplate->GetType () )
                            pResult->nImage = iIconCertTemplateV1;
                        else
                            pResult->nImage = iIconCertTemplateV2;
                    }
				}
			}
			break;

        default:
            ASSERT (0);
            break;
		}
    }
	else
		hr = CComponent::GetDisplayInfo (pResult);

	return hr;
}


///////////////////////////////////////////////////////////////////////////////
// IExtendContextMenu implementation
//
STDMETHODIMP CCertTmplComponent::AddMenuItems (LPDATAOBJECT pDataObject,
                                            LPCONTEXTMENUCALLBACK pContextMenuCallback,
                                            long *pInsertionAllowed)
{
	return QueryComponentDataRef ().AddMenuItems (pDataObject,
			pContextMenuCallback, pInsertionAllowed);
}


STDMETHODIMP CCertTmplComponent::Command (long nCommandID, LPDATAOBJECT pDataObject)
{
	HRESULT	hr = S_OK;

	hr = QueryComponentDataRef ().Command (nCommandID, pDataObject);

	return hr;
}


HRESULT CCertTmplComponent::OnNotifyDblClick (LPDATAOBJECT pDataObject)
{
	_TRACE (1, L"Entering CCertTmplComponent::OnNotifyDblClick\n");
	HRESULT	hr = S_OK;
	ASSERT (pDataObject);

	CCertTmplCookie* pParentCookie =
			QueryComponentDataRef ().ConvertCookie (pDataObject);
	if ( pParentCookie )
	{
		switch ( pParentCookie->m_objecttype )
		{
			case CERTTMPL_SNAPIN:
				hr = S_FALSE;
				break;

            case CERTTMPL_CERT_TEMPLATE:
                hr = S_FALSE;
                break;

			default:
				_TRACE (0, L"CCertTmplComponentData::OnNotifyDblClick bad parent type\n");
				ASSERT (FALSE);
				hr = S_OK;
				break;
		}
	}
	else
		hr =  E_UNEXPECTED;


	_TRACE (-1, L"Leaving CCertTmplComponent::OnNotifyDblClick\n");
	return hr;
}


HRESULT CCertTmplComponent::OnNotifySelect (LPDATAOBJECT pDataObject, BOOL /*fSelected*/)
{
	ASSERT (m_pConsoleVerb && 0xdddddddd != (UINT_PTR) m_pConsoleVerb);
	if ( !m_pConsoleVerb || 0xdddddddd == (UINT_PTR) m_pConsoleVerb )
		return E_FAIL;


	HRESULT	hr = S_OK;
	CCertTmplComponentData& compData = QueryComponentDataRef ();


	switch (compData.GetObjectType (pDataObject))
	{
	case CERTTMPL_SNAPIN:
   		m_pConsoleVerb->SetVerbState (MMC_VERB_REFRESH, ENABLED, TRUE);
        m_pConsoleVerb->SetDefaultVerb (MMC_VERB_OPEN);
        DisplayRootNodeStatusBarText (m_pConsole);
		break;

    case CERTTMPL_CERT_TEMPLATE:
        {
			CCertTmplCookie* pCookie = ConvertCookie (pDataObject);
			if ( pCookie )
			{
				CCertTemplate* pCertTemplate = dynamic_cast <CCertTemplate*> (pCookie);
				if ( pCertTemplate )
				{
                    if ( !pCertTemplate->IsDefault () )
                        m_pConsoleVerb->SetVerbState (MMC_VERB_DELETE, ENABLED, TRUE);

                    // #NTRAID 360650: Cert Server: Cannot rename cert templates
                    //if ( 1 != pCertTemplate->GetType () && !pCertTemplate->IsDefault () )
                	//	m_pConsoleVerb->SetVerbState (MMC_VERB_RENAME, ENABLED, TRUE);
                }
            }
        }
	    m_pConsoleVerb->SetVerbState (MMC_VERB_PROPERTIES, ENABLED, TRUE);
		m_pConsoleVerb->SetDefaultVerb (MMC_VERB_PROPERTIES);
		m_currResultNodeType = CERTTMPL_CERT_TEMPLATE;
	    DisplayObjectCountInStatusBar (m_pConsole, 
			    QueryComponentDataRef ().m_dwNumCertTemplates);
        break;

	case CERTTMPL_MULTISEL:
    	m_pConsoleVerb->SetVerbState (MMC_VERB_DELETE, ENABLED, TRUE);
		m_currResultNodeType = CERTTMPL_MULTISEL;
	    DisplayObjectCountInStatusBar (m_pConsole, 
			    QueryComponentDataRef ().m_dwNumCertTemplates);
		break;

	default:
		m_currResultNodeType = CERTTMPL_INVALID;
		hr = E_UNEXPECTED;
		break;
	}

	return hr;
}

STDMETHODIMP CCertTmplComponent::CreatePropertyPages (
	LPPROPERTYSHEETCALLBACK pCallBack,
    LONG_PTR handle,		// This handle must be saved in the property page object to notify the parent when modified
	LPDATAOBJECT pDataObject)
{
	return QueryComponentDataRef ().CreatePropertyPages (pCallBack, handle, pDataObject);
}

STDMETHODIMP CCertTmplComponent::QueryPagesFor (LPDATAOBJECT pDataObject)
{
	return QueryComponentDataRef ().QueryPagesFor (pDataObject);
}


HRESULT CCertTmplComponent::OnNotifyRefresh (LPDATAOBJECT pDataObject)
{
	_TRACE (1, L"Entering CCertTmplComponent::OnNotifyRefresh\n");
	ASSERT (pDataObject);
	if ( !pDataObject )
		return E_POINTER;

	HRESULT	    hr = S_OK;
    CWaitCursor	waitCursor;

	CCertTmplCookie* pCookie = ConvertCookie (pDataObject);
	if ( !pCookie )
		return E_UNEXPECTED;

	CCertTmplComponentData&	dataRef = QueryComponentDataRef ();

	switch (pCookie->m_objecttype)
	{
	case CERTTMPL_SNAPIN:
		{
			// Delete all the scope items and force a reexpansion
			hr = dataRef.DeleteScopeItems ();
	        hr = PopulateListbox (m_pViewedCookie);
	        if ( FAILED (hr) )
	        {
                CString caption;
                CString text;

                VERIFY (caption.LoadString (IDS_CERTTMPL));

                text.FormatMessage (IDS_CANNOT_ENUM_CERT_TEMPLATES, GetSystemMessage (hr));

		        int		iRetVal = 0;
		        VERIFY (SUCCEEDED (m_pConsole->MessageBox (text, caption,
			        MB_ICONWARNING | MB_OK, &iRetVal)));
	        }
		}
		break;

    case CERTTMPL_CERT_TEMPLATE:
        ASSERT (0);
        break;

	default:
		ASSERT (0);
		hr = E_UNEXPECTED;
		break;
	}

	_TRACE (-1, L"Leaving CCertTmplComponent::OnNotifyRefresh\n");
	return hr;
}

void CCertTmplComponent::SetTextNotAvailable ()
{
	AFX_MANAGE_STATE (AfxGetStaticModuleState ());
	m_szDisplayInfoResult.LoadString (IDS_NOT_AVAILABLE);
}


HRESULT	CCertTmplComponent::DeleteCookie (CCertTmplCookie* pCookie, LPDATAOBJECT pDataObject, bool bRequestConfirmation, bool bIsMultipleSelect)
{
	_TRACE (1, L"Entering CCertTmplComponent::DeleteCookie\n");
	HRESULT			hr = S_OK;
	CString			text;
	CString			caption;
	int				iRetVal = IDYES;
	CWaitCursor		waitCursor;

	switch (pCookie->m_objecttype)
	{
    case CERTTMPL_CERT_TEMPLATE:
		{
			CCertTemplate* pCertTemplate = dynamic_cast <CCertTemplate*> (pCookie);
			ASSERT (pCertTemplate);
			if ( pCertTemplate )
			{
				if ( bRequestConfirmation )
				{
					if ( bIsMultipleSelect )
					{
						VERIFY (text.LoadString (IDS_CONFIRM_DELETE_CERT_TEMPLATE_MULTI));
					}
					else
						VERIFY (text.LoadString (IDS_CONFIRM_DELETE_CERT_TEMPLATE));
					VERIFY (caption.LoadString (IDS_CERTTMPL));
					hr = m_pConsole->MessageBox (text, caption, MB_ICONWARNING | MB_YESNO, &iRetVal);
					ASSERT (SUCCEEDED (hr));
				}

				if ( IDYES == iRetVal )
				{
					hr = DeleteCertTemplateFromResultPane (pCertTemplate, pDataObject);
				}
				else
					hr = E_FAIL;
			}
		}
        break;

	default:
		ASSERT (0);
		hr = E_UNEXPECTED;
		break;
	}

	_TRACE (-1, L"Leaving CCertTmplComponent::DeleteCookie\n");
	return hr;
}



HRESULT CCertTmplComponent::DeleteCertTemplateFromResultPane (CCertTemplate* pCertTemplate, LPDATAOBJECT /*pDataObject*/)
{
	_TRACE (1, L"Entering CCertTmplComponent::DeleteCertTemplateFromResultPane\n");
	HRESULT			hr = S_OK;
    hr = pCertTemplate->Delete ();

    if ( SUCCEEDED (hr) )
    {
        CCertTmplComponentData& dataref = QueryComponentDataRef ();

        POSITION    prevPos = 0;
        POSITION pos = 0;
        for (pos = dataref.m_globalFriendlyNameList.GetHeadPosition (); pos;)
        {
            prevPos = pos;
            if ( pCertTemplate->GetDisplayName () == 
                    dataref.m_globalFriendlyNameList.GetNext (pos) )
            {
                dataref.m_globalFriendlyNameList.RemoveAt (prevPos);
                break;
            }
        }

        for (pos = dataref.m_globalTemplateNameList.GetHeadPosition (); pos;)
        {
            prevPos = pos;
            if ( pCertTemplate->GetTemplateName () == 
                    dataref.m_globalTemplateNameList.GetNext (pos) )
            {
                dataref.m_globalTemplateNameList.RemoveAt (prevPos);
                break;
            }
        }

    }
    else
    {
        CString caption;
        CString text;

        VERIFY (caption.LoadString (IDS_CERTTMPL));
        text.FormatMessage (IDS_CANNOT_DELETE_CERT_TEMPLATE, GetSystemMessage (hr));

		int		iRetVal = 0;
		VERIFY (SUCCEEDED (m_pConsole->MessageBox (text, caption,
			MB_ICONWARNING | MB_OK, &iRetVal)));
    }
	_TRACE (-1, L"Leaving CCertTmplComponent::DeleteCertTemplateFromResultPane\n");
	return hr;
}


HRESULT CCertTmplComponent::OnNotifyDelete (LPDATAOBJECT pDataObject)
{
	ASSERT (pDataObject);
	if ( !pDataObject )
		return E_POINTER;

	HRESULT			hr = S_OK;
	long			hint = 0;
	CWaitCursor		waitCursor;

	CCertTmplCookie* pCookie =
			QueryComponentDataRef ().ConvertCookie (pDataObject);
	if ( pCookie )
	{
		if ( ((CCertTmplCookie*) MMC_MULTI_SELECT_COOKIE) == pCookie )
		{

			// Is multiple select, get all selected items and paste each one
			CCertTemplatesDataObject* pDO = dynamic_cast <CCertTemplatesDataObject*>(pDataObject);
			ASSERT (pDO);
			if ( pDO )
			{
				// Is multiple select, get all selected items and delete - confirm
				// first deletion only.
				bool	bRequestConfirmation = true;
				pDO->Reset();
				while (pDO->Next(1, reinterpret_cast<MMC_COOKIE*>(&pCookie), NULL) != S_FALSE &&
						SUCCEEDED (hr) )
				{
					hr = DeleteCookie (pCookie, pDataObject, bRequestConfirmation, true);
					bRequestConfirmation = false;
				}

                hr = m_pConsole->UpdateAllViews (pDataObject, 0, hint);
			}

		}
		else
		{
			// In that event, we don't want a confirmation message.
			hr = DeleteCookie (pCookie, pDataObject, true, false);
			if ( SUCCEEDED (hr) )
				hr = m_pConsole->UpdateAllViews (pDataObject, 0, hint);
		}
	}

	return hr;
}



// This compare is used to sort the items in the listview
//
// Parameters:
//
// lUserParam - user param passed in when IResultData::Sort () was called
// cookieA - first item to compare
// cookieB - second item to compare
// pnResult [in, out]- contains the col on entry,
//          -1, 0, 1 based on comparison for return value.
//
// Note: Assume sort is ascending when comparing.

STDMETHODIMP CCertTmplComponent::Compare (RDCOMPARE* prdc, int* pnResult)
{
//	_TRACE (1, L"Entering CCertTmplComponent::Compare\n");
	if ( !prdc || !pnResult )
		return E_POINTER;

	HRESULT						hr = S_OK;

	if ( RDCI_ScopeItem & prdc->prdch1->dwFlags )
	{
	}
	else
	{
        CCertTmplCookie* pCookie = reinterpret_cast <CCertTmplCookie*> (prdc->prdch1->cookie);
        ASSERT (pCookie);
        if ( !pCookie )
            return E_UNEXPECTED;

        switch (pCookie->m_objecttype)
        {
        case CERTTMPL_CERT_TEMPLATE:
            {
	            CCertTemplate* pCertTemplateA = reinterpret_cast <CCertTemplate*> (prdc->prdch1->cookie);
	            CCertTemplate* pCertTemplateB = reinterpret_cast <CCertTemplate*> (prdc->prdch2->cookie);
	            switch ( prdc->nColumn )
	            {
	            case COLNUM_CERT_TEMPLATE_OBJECT:
		            *pnResult = LocaleStrCmp (pCertTemplateA->GetDisplayName (), pCertTemplateB->GetDisplayName ());
		            break;

	            case COLNUM_CERT_TEMPLATE_TYPE:
		            if ( pCertTemplateA->GetType () == pCertTemplateB->GetType () )
                        *pnResult = 0;
                    else if ( pCertTemplateA->GetType () > pCertTemplateB->GetType () )
                        *pnResult = 1;
                    else
                        *pnResult = -1;
		            break;

	            case COLNUM_CERT_TEMPLATE_VERSION:
                    {
                        // Sort first on major version, then on minor version
                        *pnResult = 0;
                        DWORD dwMajorVersionA = 0;
                        hr = pCertTemplateA->GetMajorVersion (dwMajorVersionA);
                        if ( SUCCEEDED (hr) )
                        {
                            DWORD dwMajorVersionB = 0;
                            hr = pCertTemplateB->GetMajorVersion (dwMajorVersionB);
                            if ( SUCCEEDED (hr) )
                            {
                                if ( dwMajorVersionA == dwMajorVersionB )
                                {
                                    DWORD dwMinorVersionA = 0;
                                    hr = pCertTemplateA->GetMinorVersion (dwMinorVersionA);
                                    if ( SUCCEEDED (hr) )
                                    {
                                        DWORD dwMinorVersionB = 0;
                                        hr = pCertTemplateB->GetMinorVersion (dwMinorVersionB);
                                        if ( SUCCEEDED (hr) )
                                        {
                                            if ( dwMinorVersionA == dwMinorVersionB )
                                                *pnResult = 0;
                                            else if ( dwMinorVersionA > dwMinorVersionB )
                                                *pnResult = 1;
                                            else
                                                *pnResult = -1;
                                        }
                                    }
                                }
                                else if ( dwMajorVersionA > dwMajorVersionB )
                                    *pnResult = 1;
                                else
                                    *pnResult = -1;
                            }
                        }
                    }
                    break;

                case COLNUM_CERT_TEMPLATE_AUTOENROLL_STATUS:
                    if ( pCertTemplateA->GoodForAutoEnrollment () && 
                            pCertTemplateB->GoodForAutoEnrollment () )
                    {
                        *pnResult = 0;
                    }
                    else if ( pCertTemplateA->GoodForAutoEnrollment () && 
                            !pCertTemplateB->GoodForAutoEnrollment () )
                    {
                        *pnResult = 1;
                    }
                    else
                        *pnResult = 0;
                    break;

                default:
                    ASSERT (0);
                    break;
	            }
            }
            break;

		default:
			ASSERT (0);
			break;
		}
	}

//	_TRACE (-1, L"Leaving CCertTmplComponent::Compare\n");
	return hr;
}


/////////////////////////////////////////////////////////////////////
// Virtual function called by CComponent::IComponent::Notify (MMCN_COLUMN_CLICK)
HRESULT CCertTmplComponent::OnNotifyColumnClick (LPDATAOBJECT /*pDataObject*/, LPARAM iColumn, LPARAM uFlags)
{
	_TRACE (1, L"Entering CCertTmplComponent::OnNotifyColumnClick\n");

	IResultData*	pResultData = 0;
	HRESULT			hr = m_pConsole->QueryInterface (
			IID_PPV_ARG (IResultData, &pResultData));
	if ( SUCCEEDED (hr) )
	{
		hr = pResultData->Sort ((DWORD)iColumn, (DWORD)uFlags, 0);
        _TRACE (0, L"IResultData::Sort () returned: 0x%x\n", hr);

		pResultData->Release ();
	}

	_TRACE (-1, L"Leaving CCertTmplComponent::OnNotifyColumnClick\n");
	return hr;
}


STDMETHODIMP CCertTmplComponent::Notify (LPDATAOBJECT pDataObject, MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param)
{
    HRESULT hr = S_OK;

    switch (event)
    {
		case MMCN_CUTORMOVE:
			hr = OnNotifyCutOrMove (arg);
			break;

		case MMCN_QUERY_PASTE:
			hr = OnNotifyQueryPaste (pDataObject, arg, param);
			break;

		case MMCN_PASTE:
			hr = OnNotifyPaste (pDataObject, arg, param);
			break;

	    case MMCN_SHOW:
			{
				CCookie* pCookie = NULL;
				hr = ::ExtractData (pDataObject,
								  CDataObject::m_CFRawCookie,
								  &pCookie,
								  sizeof(pCookie));
				if ( SUCCEEDED (hr) )
				{
					hr = Show (ActiveBaseCookie (pCookie), arg,
							(HSCOPEITEM) param, pDataObject);
				}
			}
			break;

        case MMCN_RENAME:
            hr = OnNotifyRename (pDataObject, arg, param);
            break;

        default:
			hr = CComponent::Notify (pDataObject, event, arg, param);
			break;
	}

	return hr;
}


HRESULT CCertTmplComponent::OnNotifySnapinHelp (LPDATAOBJECT pDataObject)
{
	_TRACE (1, L"Entering CCertTmplComponent::OnNotifySnapinHelp\n");
	AFX_MANAGE_STATE (AfxGetStaticModuleState ( ));

	CComQIPtr<IDisplayHelp,&IID_IDisplayHelp>	spDisplayHelp = m_pConsole;
	if ( !spDisplayHelp )
	{
		ASSERT(FALSE);
		return E_UNEXPECTED;
	}

	CString strHelpTopic;

    UINT nLen = ::GetSystemWindowsDirectory (strHelpTopic.GetBufferSetLength(2 * MAX_PATH), 2 * MAX_PATH);
    strHelpTopic.ReleaseBuffer();
    if (0 == nLen)
    {
        ASSERT(FALSE);
        return E_FAIL;
    }

    strHelpTopic += CERTTMPL_HELP_PATH;
    strHelpTopic += CERTTMPL_HTML_HELP_FILE;
    strHelpTopic += L"::/";

    CCertTmplComponentData&	compData = QueryComponentDataRef ();
	CCertTmplCookie* pCookie = compData.ConvertCookie (pDataObject);
	if ( pCookie )
	{
		switch (pCookie->m_objecttype)
		{
        case CERTTMPL_SNAPIN:
        case CERTTMPL_CERT_TEMPLATE:
        default:
            strHelpTopic += CERTTMPL_HTML_TOP_NODE;
            break;
        }
    }

 	HRESULT hr = spDisplayHelp->ShowTopic (T2OLE ((PWSTR)(PCWSTR) strHelpTopic));
	if ( FAILED (hr) )
	{
        CString caption;
        CString text;

        VERIFY (caption.LoadString (IDS_CERTTMPL));

        text.FormatMessage (IDS_CANT_DISPLAY_SNAPIN_HELP_TOPIC, strHelpTopic, 
				GetSystemMessage (hr));

		int		iRetVal = 0;
		VERIFY (SUCCEEDED (m_pConsole->MessageBox (text, caption,
			MB_ICONWARNING | MB_OK, &iRetVal)));
	}


	_TRACE (-1, L"Leaving CCertTmplComponent::OnNotifySnapinHelp\n");
	return hr;
}

void CCertTmplComponent::DisplayAccessDenied ()
{
	DWORD	dwErr = GetLastError ();
	ASSERT (E_ACCESSDENIED == dwErr);
	if ( E_ACCESSDENIED == dwErr )
	{
		LPVOID lpMsgBuf;
			
		FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
				NULL,
				GetLastError (),
				MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
				 (PWSTR) &lpMsgBuf,    0,    NULL );
			
		// Display the string.
		CString	caption;
		VERIFY (caption.LoadString (IDS_CERTTMPL));
		int		iRetVal = 0;
		VERIFY (SUCCEEDED (m_pConsole->MessageBox ( (PWSTR) lpMsgBuf, caption,
			MB_ICONWARNING | MB_OK, &iRetVal)));

		// Free the buffer.
		LocalFree (lpMsgBuf);
	}
}

HRESULT CCertTmplComponent::OnNotifyPaste (LPDATAOBJECT /*pDataObject*/, LPARAM /*arg*/, LPARAM /*param*/)
{
	return E_NOTIMPL;
}


HRESULT CCertTmplComponent::OnNotifyQueryPaste(LPDATAOBJECT /*pDataObject*/, LPARAM /*arg*/, LPARAM /*param*/)
{
	return E_NOTIMPL;
}


STDMETHODIMP CCertTmplComponent::GetResultViewType(MMC_COOKIE cookie,
		BSTR* ppViewType,
		long* pViewOptions) 
{
	CCertTmplCookie* pScopeCookie = reinterpret_cast <CCertTmplCookie*> (cookie);
	if ( pScopeCookie )
	{
		switch (pScopeCookie->m_objecttype)
		{
        case CERTTMPL_SNAPIN:
			*pViewOptions |= MMC_VIEW_OPTIONS_MULTISELECT;
			break;

        case CERTTMPL_CERT_TEMPLATE:
		default:
			break;
		}
	}
    else
        *pViewOptions |= MMC_VIEW_OPTIONS_MULTISELECT;

    *ppViewType = NULL;
    return S_FALSE;
}


STDMETHODIMP CCertTmplComponent::Initialize(LPCONSOLE lpConsole)
{
	_TRACE (1, L"Entering CCertTmplComponent::Initialize\n");
	HRESULT	 hr = CComponent::Initialize (lpConsole);
	if ( SUCCEEDED (hr) )
	{
		ASSERT (m_pHeader);
		QueryComponentDataRef ().m_pHeader = m_pHeader;

		if ( lpConsole )
		{
			if ( QueryComponentDataRef ().m_pComponentConsole )
				SAFE_RELEASE (QueryComponentDataRef ().m_pComponentConsole);
			QueryComponentDataRef ().m_pComponentConsole = m_pConsole;
			QueryComponentDataRef ().m_pComponentConsole->AddRef ();
		}
	}

	_TRACE (-1, L"Leaving CCertTmplComponent::Initialize\n");
	return hr;
}


HRESULT CCertTmplComponent::LoadColumnsFromArrays (CertTmplObjectType objecttype )
{
	_TRACE (1, L"Entering CCertTmplComponent::LoadColumnsFromArrays\n");
    ASSERT (m_pHeader);

	CString str;
	for ( INT i = 0; 0 != m_Columns[objecttype][i]; i++)
	{
		VERIFY(str.LoadString (m_Columns[objecttype][i]));
		m_pHeader->InsertColumn(i, const_cast<PWSTR>((PCWSTR)str), LVCFMT_LEFT,
			m_ColumnWidths[objecttype][i]);
	}

	_TRACE (-1, L"Leaving CCertTmplComponent::LoadColumnsFromArrays\n");
	return S_OK;
}

HRESULT CCertTmplComponent::SaveWidths(CCertTmplCookie * pCookie)
{
	_TRACE (1, L"Entering CCertTmplComponent::SaveWidths\n");
	HRESULT	hr = S_OK;

	m_fDirty = TRUE;

	ASSERT (pCookie);
	if ( pCookie )
	{
		switch (m_pViewedCookie->m_objecttype)
		{
		case CERTTMPL_SNAPIN:
			{
				const UINT* pColumns = m_Columns[m_pViewedCookie->m_objecttype];
				ASSERT(pColumns);
				int    nWidth = 0;

				for (UINT iIndex = 0; iIndex < pColumns[iIndex]; iIndex++)
				{
					hr = m_pHeader->GetColumnWidth ((int) iIndex, &nWidth);
					if ( SUCCEEDED (hr) )
					{
						m_ColumnWidths[m_pViewedCookie->m_objecttype][iIndex] =
								(UINT) nWidth;
					}
					else
						break;
				}
			}
			break;

		default:
			ASSERT (0);
			break;
		}
	}
	else
		hr = E_POINTER;

	_TRACE (-1, L"Leaving CCertTmplComponent::SaveWidths\n");
	return hr;
}


///////////////////////////////////////////////////////////////////////////////
#define _dwMagicword	10000  // Internal version number
STDMETHODIMP CCertTmplComponent::Load(IStream __RPC_FAR *pIStream)
{
	_TRACE (1, L"Entering CCertTmplComponent::Load\n");
	HRESULT hr = S_OK;

#ifndef DONT_PERSIST
	ASSERT (pIStream);
	XSafeInterfacePtr<IStream> pIStreamSafePtr( pIStream );

	// Read the magic word from the stream
	DWORD dwMagicword = 0;
	hr = pIStream->Read (&dwMagicword, sizeof(dwMagicword), NULL);
	if ( FAILED(hr) )
	{
		ASSERT( FALSE );
		return hr;
	}
	if (dwMagicword != _dwMagicword)
	{
		// We have a version mismatch
		_TRACE(0, L"INFO: CCertTmplComponentData::Load() - Wrong Magicword.  You need to re-save your .msc file.\n");
		return E_FAIL;
	}

	int	numCols = 0;

	for (int iIndex = 0; iIndex < CERTTMPL_NUMTYPES && SUCCEEDED (hr); iIndex++)
	{
		switch (iIndex)
		{
		case CERTTMPL_SNAPIN:
            numCols = CERT_TEMPLATES_NUM_COLS;
			break;;

        case CERTTMPL_CERT_TEMPLATE:
            continue;

		default:
			ASSERT (0);
			break;
		}

		for (int colNum = 0; colNum < numCols; colNum++)
		{
			hr = pIStream->Read (&(m_ColumnWidths[iIndex][colNum]),
					sizeof (UINT), NULL);
			ASSERT (SUCCEEDED (hr));
			if ( FAILED(hr) )
			{
				break;
			}
		}
	}
#endif
	_TRACE (-1, L"Leaving CCertTmplComponent::Load\n");
	return S_OK;
}


///////////////////////////////////////////////////////////////////////////////

STDMETHODIMP CCertTmplComponent::Save(IStream __RPC_FAR *pIStream, BOOL /*fSameAsLoad*/)
{
	_TRACE (1, L"Entering CCertTmplComponent::Save\n");
	HRESULT hr = S_OK;


#ifndef DONT_PERSIST
	ASSERT (pIStream);
	XSafeInterfacePtr<IStream> pIStreamSafePtr (pIStream);

	// Store the magic word to the stream
	DWORD dwMagicword = _dwMagicword;
	hr = pIStream->Write (&dwMagicword, sizeof(dwMagicword), NULL);
	ASSERT (SUCCEEDED (hr));
	if ( FAILED (hr) )
		return hr;


	int	numCols = 0;

	for (int iIndex = 0; iIndex < CERTTMPL_NUMTYPES && SUCCEEDED (hr); iIndex++)
	{
		switch (iIndex)
		{
		case CERTTMPL_SNAPIN:
            numCols = CERT_TEMPLATES_NUM_COLS;
			break;;

        case CERTTMPL_CERT_TEMPLATE:
            continue;

		default:
			ASSERT (0);
			break;
		}

		for (int colNum = 0; colNum < numCols; colNum++)
		{
			hr = pIStream->Write (&(m_ColumnWidths[iIndex][colNum]),
					sizeof (UINT), NULL);
			ASSERT (SUCCEEDED (hr));
			if ( FAILED(hr) )
			{
				ASSERT (FALSE);
				break;
			}
		}
	}
#endif

	_TRACE (-1, L"Leaving CCertTmplComponent::Save\n");
	return S_OK;
}

HRESULT CCertTmplComponent::OnNotifyCutOrMove(LPARAM arg)
{
	_TRACE (1, L"Entering CCertTmplComponent::OnNotifyCutOrMove\n");
	if ( !arg )
		return E_POINTER;

	LPDATAOBJECT pDataObject = reinterpret_cast <IDataObject*> (arg);
	ASSERT (pDataObject);
	if ( !pDataObject )
		return E_UNEXPECTED;


	HRESULT			hr = S_OK;

	CCertTmplCookie* pCookie =
			QueryComponentDataRef ().ConvertCookie (pDataObject);
	if ( pCookie )
	{
		if ( ((CCertTmplCookie*) MMC_MULTI_SELECT_COOKIE) == pCookie )
		{
			CCertTemplatesDataObject* pDO = dynamic_cast <CCertTemplatesDataObject*>(pDataObject);
			ASSERT (pDO);
			if ( pDO )
			{
				pDO->Reset();
				while (pDO->Next(1, reinterpret_cast<MMC_COOKIE*>(&pCookie), NULL) != S_FALSE)
				{
					hr = DeleteCookie (pCookie, pDataObject, false, true);
				}
			}
			else
				hr = E_FAIL;
		}
		else
		{
			hr = DeleteCookie (pCookie, pDataObject, false, false);
		}
		if ( SUCCEEDED (hr) )
			RefreshResultPane (false);
	}

	_TRACE (-1, L"Leaving CCertTmplComponent::OnNotifyCutOrMove\n");
	return hr;
}



CCertTmplCookie* CCertTmplComponent::ConvertCookie(LPDATAOBJECT pDataObject)
{
	return QueryComponentDataRef ().ConvertCookie (pDataObject);
}



HRESULT CCertTmplComponent::RefreshResultItem (CCertTmplCookie* pCookie)
{
	_TRACE (1, L"Entering CCertTmplComponent::RefreshResultItem\n");
	ASSERT (pCookie);
	if ( !pCookie )
		return E_POINTER;

	HRESULT	hr = S_OK;
	HRESULTITEM	itemID = 0;

	ASSERT (m_pResultData);
	if ( m_pResultData )
	{
		pCookie->Refresh ();
		hr = m_pResultData->FindItemByLParam ( (LPARAM) pCookie, &itemID);
		ASSERT (SUCCEEDED (hr));
		if ( SUCCEEDED (hr) )
		{
			hr = m_pResultData->UpdateItem (itemID);
			ASSERT (SUCCEEDED (hr));
		}
	}
	else
		hr = E_FAIL;

	_TRACE (-1, L"Leaving CCertTmplComponent::RefreshResultItem\n");
	return hr;
}


/////////////////////////////////////////////////////////////////////
// Virtual function called by CComponent::IComponent::Notify(MMCN_PROPERTY_CHANGE)
// OnPropertyChange() is generated by MMCPropertyChangeNotify( param )
HRESULT CCertTmplComponent::OnPropertyChange (LPARAM param)
{
	return  QueryComponentDataRef ().OnPropertyChange (param);
}

HRESULT CCertTmplComponent::AddEnterpriseTemplates ()
{
	_TRACE (1, L"Entering CCertTmplComponent::AddEnterpriseTemplates\n");
    AFX_MANAGE_STATE(AfxGetStaticModuleState());	
    HRESULT	                hr = S_OK;
    CWaitCursor	            cursor;
	CComPtr<IADsPathname>   spPathname;

	//
	// Constructing the directory paths
	//
	hr = CoCreateInstance(
				CLSID_Pathname,
				NULL,
				CLSCTX_ALL,
				IID_PPV_ARG (IADsPathname, &spPathname));
	if ( SUCCEEDED (hr) )
	{
        ASSERT (!!spPathname);
		hr = spPathname->Set(const_cast <PWSTR> (CERTTMPL_LDAP),
							ADS_SETTYPE_PROVIDER);
		if ( SUCCEEDED (hr) )
		{
			//
			// Open the root DSE object
			//
			hr = spPathname->AddLeafElement(const_cast <PWSTR> (CERTTMPL_ROOTDSE));
			if ( SUCCEEDED (hr) )
			{
				BSTR bstrFullPath = 0;
				hr = spPathname->Retrieve(ADS_FORMAT_X500, &bstrFullPath);
				if ( SUCCEEDED (hr) )
				{
					CComPtr<IADs> spRootDSEObject;
					VARIANT varNamingContext;


					hr = ADsGetObject (
			              bstrFullPath,
						  IID_PPV_ARG (IADs, &spRootDSEObject));
					if ( SUCCEEDED (hr) )
					{
                        ASSERT (!!spRootDSEObject);
						//
						// Get the configuration naming context from the root DSE
						//
						hr = spRootDSEObject->Get(const_cast <PWSTR> (CERTTMPL_CONFIG_NAMING_CONTEXT),
											 &varNamingContext);
						if ( SUCCEEDED (hr) )
						{
							hr = spPathname->Set(V_BSTR(&varNamingContext),
												ADS_SETTYPE_DN);
							if ( SUCCEEDED (hr) )
							{
                                hr = spPathname->AddLeafElement (L"CN=Services");
                                if ( SUCCEEDED (hr) )
                                {
                                    hr = spPathname->AddLeafElement (L"CN=Public Key Services");
                                    if ( SUCCEEDED (hr) )
                                    {
                                        hr = spPathname->AddLeafElement (L"CN=Certificate Templates");
                                        if ( SUCCEEDED (hr) )
                                        {
				                            BSTR bstrCertTemplatePath = 0;
				                            hr = spPathname->Retrieve(ADS_FORMAT_X500, &bstrCertTemplatePath);
				                            if ( SUCCEEDED (hr) )
				                            {
					                            CComPtr<IDirectoryObject> spTemplateContObj;

					                            hr = ADsGetObject (
			                                          bstrCertTemplatePath,
						                              IID_PPV_ARG (IDirectoryObject, &spTemplateContObj));
					                            if ( SUCCEEDED (hr) )
					                            {
                                                    hr = EnumerateTemplates (spTemplateContObj, bstrCertTemplatePath);
                                                    if ( SUCCEEDED (hr) )
                                                    {
					                                    m_currResultNodeType = CERTTMPL_CERT_TEMPLATE;
					                                    hr = m_pResultData->Sort (COLNUM_CERT_TEMPLATE_OBJECT, 0, 0);
                                                    }
                                                }
                                                else
                                                {
                                                    _TRACE (0, L"ADsGetObject (%s) failed: 0x%x\n", bstrCertTemplatePath, hr);
                                                }

                                                SysFreeString (bstrCertTemplatePath);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        else
                        {
                            _TRACE (0, L"IADs::Get (%s) failed: 0x%x\n", CERTTMPL_CONFIG_NAMING_CONTEXT, hr);
                        }
                    }
                    else
                    {
                        _TRACE (0, L"ADsGetObject (%s) failed: 0x%x\n", bstrFullPath, hr);
                    }
                }
            }
        }
    }
    else
        hr = E_POINTER;

	_TRACE (-1, L"Leaving CCertTmplComponent::AddEnterpriseTemplates\n");
	return hr;
}


HRESULT CCertTmplComponent::EnumerateTemplates (
        IDirectoryObject* pTemplateContObj, 
        const BSTR bszTemplateContainerPath)
{
    _TRACE (1, L"Entering CCertTmplComponent::EnumerateTemplates\n");
    CCertTmplComponentData& dataRef = QueryComponentDataRef ();
	CWaitCursor	            cursor;

    dataRef.m_fUseCache = false;

    // Bug 243609	CertServer: Wrong count of templates displayed in the MMC
    dataRef.m_dwNumCertTemplates = 0;
    dataRef.m_globalTemplateNameList.RemoveAll ();
    dataRef.m_globalFriendlyNameList.RemoveAll ();
	CComPtr<IDirectorySearch>   spDsSearch;
	HRESULT hr = pTemplateContObj->QueryInterface (IID_PPV_ARG(IDirectorySearch, &spDsSearch));
	if ( SUCCEEDED (hr) )
	{
        ASSERT (!!spDsSearch);
		ADS_SEARCHPREF_INFO pSearchPref[1];
		DWORD dwNumPref = 1;

		pSearchPref[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
		pSearchPref[0].vValue.dwType = ADSTYPE_INTEGER;
		pSearchPref[0].vValue.Integer = ADS_SCOPE_ONELEVEL;

		hr = spDsSearch->SetSearchPreference(
				 pSearchPref,
				 dwNumPref
				 );
		if ( SUCCEEDED (hr) )
		{
			static const DWORD	cAttrs = 2;
            static PWSTR	    rgszAttrList[cAttrs] = {L"displayName", L"cn"};
			ADS_SEARCH_HANDLE	hSearchHandle = 0;
            wstring             strQuery;
            ADS_SEARCH_COLUMN   Column;

            Column.pszAttrName = 0;
            strQuery = L"objectClass=pKICertificateTemplate";

			hr = spDsSearch->ExecuteSearch(
								 const_cast <PWSTR>(strQuery.c_str ()),
								 rgszAttrList,
								 cAttrs,
								 &hSearchHandle
								 );
			if ( SUCCEEDED (hr) )
			{
                CCookie&	rootCookie = dataRef.QueryBaseRootCookie ();

				while ((hr = spDsSearch->GetNextRow (hSearchHandle)) != S_ADS_NOMORE_ROWS )
				{
                    if (FAILED(hr))
                        continue;

					//
					// Getting current row's information
					//
					hr = spDsSearch->GetColumn(
							 hSearchHandle,
							 rgszAttrList[0],
							 &Column
							 );
					if ( SUCCEEDED (hr) )
					{
                        CString strDisplayName = Column.pADsValues->CaseIgnoreString;

						spDsSearch->FreeColumn (&Column);
						Column.pszAttrName = NULL;

					    hr = spDsSearch->GetColumn(
							     hSearchHandle,
							     rgszAttrList[1],
							     &Column
							     );
					    if ( SUCCEEDED (hr) )
					    {
                            CString strTemplateName = Column.pADsValues->CaseIgnoreString;

						    spDsSearch->FreeColumn (&Column);
						    Column.pszAttrName = NULL;


	                        CComPtr<IADsPathname> spPathname;
	                        //
	                        // Constructing the directory paths
	                        //
	                        hr = CoCreateInstance(
				                        CLSID_Pathname,
				                        NULL,
				                        CLSCTX_ALL,
				                        IID_PPV_ARG (IADsPathname, &spPathname));
	                        if ( SUCCEEDED (hr) )
	                        {
                                ASSERT (!!spPathname);
		                        hr = spPathname->Set(const_cast <PWSTR> (bszTemplateContainerPath),
							                        ADS_SETTYPE_FULL);
		                        if ( SUCCEEDED (hr) )
		                        {
			                        //
			                        // Open the root DSE object
			                        //
			                        hr = spPathname->AddLeafElement(const_cast <PWSTR> ((PCWSTR) strTemplateName));
			                        if ( SUCCEEDED (hr) )
			                        {
				                        BSTR bstrFullPath = 0;
				                        hr = spPathname->Retrieve(ADS_FORMAT_X500, &bstrFullPath);
				                        if ( SUCCEEDED (hr) )
				                        {
						                    CCertTemplate* pCertTemplate = 
								                    new CCertTemplate (strDisplayName, strTemplateName,
                                                            bstrFullPath, false,
                                                            dataRef.m_fUseCache);
						                    if ( pCertTemplate )
						                    {
                                                dataRef.m_fUseCache = true;                                    

							                    rootCookie.m_listResultCookieBlocks.AddHead (pCertTemplate);

							                    RESULTDATAITEM			rdItem;
							                    ::ZeroMemory (&rdItem, sizeof (rdItem));
							                    rdItem.mask = RDI_STR | RDI_IMAGE | RDI_PARAM;
							                    rdItem.nCol = 0;
							                    rdItem.str = MMC_CALLBACK;
                                                if ( 1 == pCertTemplate->GetType () )
							                        rdItem.nImage = iIconCertTemplateV1;
                                                else
							                        rdItem.nImage = iIconCertTemplateV2;
							                    rdItem.lParam = (LPARAM) pCertTemplate;
							                    pCertTemplate->m_resultDataID = m_pResultData;
							                    hr = m_pResultData->InsertItem (&rdItem);
							                    if ( FAILED (hr) )
							                    {
								                    _TRACE (0, L"IResultData::InsertItem failed: 0x%x\n", hr);
								                    hr = S_OK;
								                    break;
							                    }
							                    else
                                                {
                                                    dataRef.m_dwNumCertTemplates++;
                                                    dataRef.m_globalTemplateNameList.AddTail (strTemplateName);
                                                    dataRef.m_globalFriendlyNameList.AddHead (
                                                        pCertTemplate->GetDisplayName ());    
                                                }
						                    }
						                    else
						                    {
							                    hr = E_OUTOFMEMORY;
							                    break;
						                    }

                                            SysFreeString (bstrFullPath);
                                        }
                                    }
                                }
                            }

                        }
					}
					else if ( hr != E_ADS_COLUMN_NOT_SET )
					{
						break;
					}
                    else
                    {
                        _TRACE (0, L"IDirectorySearch::GetColumn () failed: 0x%x\n", hr);
                    }
                }
			}
            else
            {
                _TRACE (0, L"IDirectorySearch::ExecuteSearch () failed: 0x%x\n", hr);
            }

            spDsSearch->CloseSearchHandle(hSearchHandle);
		}
        else
        {
            _TRACE (0, L"IDirectorySearch::SetSearchPreference () failed: 0x%x\n", hr);
        }
    }
    else
    {
        _TRACE (0, L"IDirectoryObject::QueryInterface (IDirectorySearch) failed: 0x%x\n", hr);
    }

    _TRACE (-1, L"Leaving CCertTmplComponent::EnumerateTemplates: 0x%x\n", hr);
    dataRef.m_fUseCache = false;

    return hr;
}


HRESULT CCertTmplComponent::OnNotifyRename(LPDATAOBJECT pDataObject, LPARAM /*arg*/, LPARAM param)
{
    _TRACE (1, L"Entering CCertTmplComponent::OnNotifyRename\n");
    AFX_MANAGE_STATE (AfxGetStaticModuleState ());
    HRESULT hr = S_FALSE;

    CCertTmplCookie* pCookie = ConvertCookie (pDataObject);
    if ( pCookie )
    {
        switch (pCookie->m_objecttype)
        {
        case CERTTMPL_CERT_TEMPLATE:
            {
                CString newName = (LPOLESTR) param;

                newName.TrimLeft ();
                newName.TrimRight ();

                if ( !newName.IsEmpty () )
                {
                    CCertTmplComponentData& dataref = QueryComponentDataRef ();
                    POSITION                pos = 0;
                    bool                    bFound = false;
                    for (pos = dataref.m_globalFriendlyNameList.GetHeadPosition (); pos;)
                    {
                        if ( !_wcsicmp (newName, dataref.m_globalFriendlyNameList.GetNext (pos)) )
                        {
                            CString caption;
                            CString text;

                            VERIFY (caption.LoadString (IDS_CERTTMPL));
                            text.FormatMessage (IDS_FRIENDLY_NAME_ALREADY_USED, newName);

                            int     iRetVal = 0;
                            VERIFY (SUCCEEDED (m_pConsole->MessageBox (text, caption,
                                    MB_OK, &iRetVal)));
                            bFound = true;
                            break;
                        }
                    }

                    if ( !bFound )
                    {
                        CCertTemplate* pCertTemplate = dynamic_cast<CCertTemplate*> (pCookie);
                        if ( pCertTemplate )
                        {
                            hr = pCertTemplate->SetDisplayName (newName);
                            if ( SUCCEEDED (hr) )
                            {
                                hr = pCertTemplate->SaveChanges ();
                                if ( FAILED (hr) )
                                {
                                    CString caption;
                                    CString text;

                                    VERIFY (caption.LoadString (IDS_CERTTMPL));
                                    text.FormatMessage (IDS_UNABLE_TO_SAVE_CERT_TEMPLATE_CHANGES, GetSystemMessage (hr));

                                    int     iRetVal = 0;
                                    VERIFY (SUCCEEDED (m_pConsole->MessageBox (text, caption,
                                            MB_ICONWARNING | MB_OK, &iRetVal)));
                                }
                            }
                            else
                            {
                                CString caption;
                                CString text;

                                VERIFY (caption.LoadString (IDS_CERTTMPL));
                                text.FormatMessage (IDS_CANNOT_CHANGE_DISPLAY_NAME, hr);

                                int     iRetVal = 0;
                                VERIFY (SUCCEEDED (m_pConsole->MessageBox (text, caption,
                                        MB_ICONWARNING | MB_OK, &iRetVal)));
                            }
                        }
                    }
                }
                else
                {
                    CString caption;
                    CString text;

                    VERIFY (caption.LoadString (IDS_CERTTMPL));
                    VERIFY (text.LoadString (IDS_MUST_TYPE_TEMPLATE_DISPLAY_NAME));
                    int     iRetVal = 0;
                    VERIFY (SUCCEEDED (m_pConsole->MessageBox (text, caption,
                            MB_ICONWARNING | MB_OK, &iRetVal)));
                    hr = S_FALSE;
                }
            }
            break;

        default:
            break;
        }
    }

	if ( !SUCCEEDED (hr) )
		hr = S_FALSE;

    _TRACE(-1, L"Leaving CCertTmplComponent::OnNotifyRename: 0x%x\n", hr);
    return hr;
}

