/**********************************************************************/
/**                       Microsoft Windows/NT                       **/
/**                Copyright(c) Microsoft Corporation, 1997 - 1999 **/
/**********************************************************************/

/*
	dhcpcomp.cpp
		This file contains the derived implementations from CComponent
		and CComponentData for the DHCP admin snapin.

    FILE HISTORY:
        
*/

#include "stdafx.h"
#include "dhcpcomp.h"
#include "croot.h"
#include "server.h"
#include "servbrow.h"

#include <util.h>       // for InitWatermarkInfo

#include <atlimpl.cpp>

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

#define DHCPSNAP_HELP_FILE_NAME   "dhcpsnap.chm"

LARGE_INTEGER gliDhcpsnapVersion;
CAuthServerList g_AuthServerList;

WATERMARKINFO g_WatermarkInfoServer = {0};
WATERMARKINFO g_WatermarkInfoScope = {0};

UINT aColumns[DHCPSNAP_NODETYPE_MAX][MAX_COLUMNS] =
{
	{IDS_ROOT_NAME,           IDS_STATUS,       0,                  0,          0,		 0,	          0},
	{IDS_DHCPSERVER_NAME,     IDS_STATUS,       IDS_DESCRIPTION,    0,          0,		 0,	          0},
	{IDS_BOOT_IMAGE,          IDS_FILE_NAME,    IDS_FILE_SERVER,    0,          0,		 0,	          0},
	{IDS_SUPERSCOPE_NAME,     IDS_STATUS,       IDS_DESCRIPTION,    0,          0,		 0,	          0},
	{IDS_SCOPE_NAME,          0,                0,                  0,          0,		 0,	          0},
	{IDS_SCOPE_NAME,          0,                0,                  0,          0,		 0,	          0},
	{IDS_START_IP_ADDR,       IDS_END_IP_ADDR,  IDS_DESCRIPTION,    0,          0,		 0,	          0},
	{IDS_CLIENT_IP_ADDR,      IDS_NAME,         IDS_LEASE,          IDS_TYPE,   IDS_UID, IDS_COMMENT, 0},
	{IDS_CLIENT_IP_ADDR,      IDS_NAME,         IDS_LEASE_START,    IDS_LEASE,  IDS_CLIENT_ID, 0, 0},
	{IDS_RESERVATIONS_FOLDER, 0,                0,                  0,          0,		 0,	          0},
	{IDS_OPTION_NAME,         IDS_VENDOR,       IDS_VALUE,          IDS_CLASS,  0,		 0,	          0},
	{IDS_OPTION_NAME,         IDS_VENDOR,       IDS_VALUE,          IDS_CLASS,  0,		 0,	          0},
	{IDS_OPTION_NAME,         IDS_VENDOR,       IDS_VALUE,          IDS_CLASS,  0,		 0,	          0},
	{IDS_NAME,                IDS_COMMENT,      0,                  0,          0,		 0,	          0},
	{0,0,0,0,0,0,0}
};

//
// CODEWORK this should be in a resource, for example code on loading data resources see
//   D:\nt\private\net\ui\common\src\applib\applib\lbcolw.cxx ReloadColumnWidths()
//   JonN 10/11/96
//
int aColumnWidths[DHCPSNAP_NODETYPE_MAX][MAX_COLUMNS] =
{	
	{200       ,150       ,AUTO_WIDTH,AUTO_WIDTH,AUTO_WIDTH,AUTO_WIDTH,AUTO_WIDTH}, // DHCPSNAP_ROOT
	{250       ,150       ,200       ,AUTO_WIDTH,AUTO_WIDTH,AUTO_WIDTH,AUTO_WIDTH}, // DHCPSNAP_SERVER
	{175       ,175       ,175       ,AUTO_WIDTH,AUTO_WIDTH,AUTO_WIDTH,AUTO_WIDTH}, // DHCPSNAP_BOOTP_TABLE
	{200	   ,150       ,200       ,AUTO_WIDTH,AUTO_WIDTH,AUTO_WIDTH,AUTO_WIDTH}, // DHCPSNAP_SUPERSCOPE
	{150       ,AUTO_WIDTH,AUTO_WIDTH,AUTO_WIDTH,AUTO_WIDTH,AUTO_WIDTH,AUTO_WIDTH}, // DHCPSNAP_SCOPE
	{150       ,AUTO_WIDTH,AUTO_WIDTH,AUTO_WIDTH,AUTO_WIDTH,AUTO_WIDTH,AUTO_WIDTH}, // DHCPSNAP_MSCOPE
	{150	   ,150       ,250       ,AUTO_WIDTH,AUTO_WIDTH,AUTO_WIDTH,AUTO_WIDTH}, // DHCPSNAP_ADDRESS_POOL
	{125       ,125	      ,200       ,75        ,AUTO_WIDTH,AUTO_WIDTH,AUTO_WIDTH}, // DHCPSNAP_ACTIVE_LEASES
	{125       ,125	      ,200       ,200       ,AUTO_WIDTH,AUTO_WIDTH,AUTO_WIDTH}, // DHCPSNAP_MSCOPE_LEASES
	{200       ,AUTO_WIDTH,AUTO_WIDTH,AUTO_WIDTH,AUTO_WIDTH,AUTO_WIDTH,AUTO_WIDTH}, // DHCPSNAP_RESERVATIONS
	{175       ,100       ,200       ,150       ,AUTO_WIDTH,AUTO_WIDTH,AUTO_WIDTH}, // DHCPSNAP_RESERVATION_CLIENT
	{175       ,100       ,200       ,150       ,AUTO_WIDTH,AUTO_WIDTH,AUTO_WIDTH}, // DHCPSNAP_SCOPE_OPTIONS
    {175       ,100       ,200       ,150       ,AUTO_WIDTH,AUTO_WIDTH,AUTO_WIDTH}, // DHCPSNAP_SERVER_OPTIONS
    {175       ,200       ,200       ,AUTO_WIDTH,AUTO_WIDTH,AUTO_WIDTH,AUTO_WIDTH}  // DHCPSNAP_CLASSID_HOLDER
};

// array to hold all of the possible toolbar buttons
MMCBUTTON g_SnapinButtons[] =
{
 { TOOLBAR_IDX_ADD_SERVER,        IDS_ADD_SERVER,                TBSTATE_HIDDEN, TBSTYLE_BUTTON, NULL, NULL },
 { TOOLBAR_IDX_REFRESH,           IDS_REFRESH,                   TBSTATE_HIDDEN, TBSTYLE_BUTTON, NULL, NULL },
 { TOOLBAR_IDX_CREATE_SCOPE,      IDS_CREATE_NEW_SCOPE,          TBSTATE_HIDDEN, TBSTYLE_BUTTON, NULL, NULL },
 { TOOLBAR_IDX_CREATE_SUPERSCOPE, IDS_CREATE_NEW_SUPERSCOPE,     TBSTATE_HIDDEN, TBSTYLE_BUTTON, NULL, NULL },
 { TOOLBAR_IDX_DEACTIVATE,        IDS_DEACTIVATE,                TBSTATE_HIDDEN, TBSTYLE_BUTTON, NULL, NULL },
 { TOOLBAR_IDX_ACTIVATE,          IDS_ACTIVATE,                  TBSTATE_HIDDEN, TBSTYLE_BUTTON, NULL, NULL },
 { TOOLBAR_IDX_ADD_BOOTP,         IDS_CREATE_NEW_BOOT_IMAGE,     TBSTATE_HIDDEN, TBSTYLE_BUTTON, NULL, NULL },
 { TOOLBAR_IDX_ADD_RESERVATION,   IDS_CREATE_NEW_RESERVATION,    TBSTATE_HIDDEN, TBSTYLE_BUTTON, NULL, NULL },
 { TOOLBAR_IDX_ADD_EXCLUSION,     IDS_CREATE_NEW_EXCLUSION,      TBSTATE_HIDDEN, TBSTYLE_BUTTON, NULL, NULL },
 { TOOLBAR_IDX_OPTION_GLOBAL,     IDS_CREATE_OPTION_GLOBAL,      TBSTATE_HIDDEN, TBSTYLE_BUTTON, NULL, NULL },
 { TOOLBAR_IDX_OPTION_SCOPE,      IDS_CREATE_OPTION_SCOPE,       TBSTATE_HIDDEN, TBSTYLE_BUTTON, NULL, NULL },
 { TOOLBAR_IDX_OPTION_RESERVATION,IDS_CREATE_OPTION_RESERVATION, TBSTATE_HIDDEN, TBSTYLE_BUTTON, NULL, NULL },
};

// array to hold resource IDs for the toolbar button text
int g_SnapinButtonStrings[TOOLBAR_IDX_MAX][2] =
{
    {IDS_TB_TEXT_ADD_SERVER,         IDS_TB_TOOLTIP_ADD_SERVER},         // TOOLBAR_IDX_ADD_SERVER
    {IDS_TB_TEXT_REFRESH,            IDS_TB_TOOLTIP_REFRESH},            // TOOLBAR_IDX_REFRESH
    {IDS_TB_TEXT_CREATE_SCOPE,       IDS_TB_TOOLTIP_CREATE_SCOPE},       // TOOLBAR_IDX_CREATE_SCOPE
    {IDS_TB_TEXT_CREATE_SUPERSCOPE,  IDS_TB_TOOLTIP_CREATE_SUPERSCOPE},  // TOOLBAR_IDX_CREATE_SUPERSCOPE
    {IDS_TB_TEXT_DEACTIVATE,         IDS_TB_TOOLTIP_DEACTIVATE},         // TOOLBAR_IDX_DEACTIVATE
    {IDS_TB_TEXT_ACTIVATE,           IDS_TB_TOOLTIP_ACTIVATE},           // TOOLBAR_IDX_ACTIVATE
    {IDS_TB_TEXT_ADD_BOOTP,          IDS_TB_TOOLTIP_ADD_BOOTP},          // TOOLBAR_IDX_ADD_BOOTP
    {IDS_TB_TEXT_ADD_RESERVATION,    IDS_TB_TOOLTIP_ADD_RESERVATION},    // TOOLBAR_IDX_ADD_RESERVATION
    {IDS_TB_TEXT_ADD_EXCLUSION,      IDS_TB_TOOLTIP_ADD_EXCLUSION},      // TOOLBAR_IDX_ADD_EXCLUSION
    {IDS_TB_TEXT_OPTION_GLOBAL,      IDS_TB_TOOLTIP_OPTION_GLOBAL},      // TOOLBAR_IDX_OPTION_GLOBAL
    {IDS_TB_TEXT_OPTION_SCOPE,       IDS_TB_TOOLTIP_OPTION_SCOPE},       // TOOLBAR_IDX_OPTION_SCOPE
    {IDS_TB_TEXT_OPTION_RESERVATION, IDS_TB_TOOLTIP_OPTION_RESERVATION}, // TOOLBAR_IDX_OPTION_RESERVATION
};

#define HI HIDDEN
#define EN ENABLED

// default states for the toolbar buttons (only scope pane items have toolbar buttons)
MMC_BUTTON_STATE g_SnapinButtonStates[DHCPSNAP_NODETYPE_MAX][TOOLBAR_IDX_MAX] =
{
	{EN, HI, HI, HI, HI, HI, HI, HI, HI, HI, HI, HI}, // DHCPSNAP_ROOT
	{HI, HI, EN, EN, HI, HI, HI, HI, HI, HI, HI, HI}, // DHCPSNAP_SERVER
	{HI, HI, HI, HI, HI, HI, EN, HI, HI, HI, HI, HI}, // DHCPSNAP_BOOTP_TABLE
	{HI, HI, EN, HI, HI, HI, HI, HI, HI, HI, HI, HI}, // DHCPSNAP_SUPERSCOPE
	{HI, HI, HI, HI, HI, HI, HI, HI, HI, HI, HI, HI}, // DHCPSNAP_SCOPE
	{HI, HI, HI, HI, HI, HI, HI, HI, HI, HI, HI, HI}, // DHCPSNAP_MSCOPE
	{HI, HI, HI, HI, HI, HI, HI, HI, EN, HI, HI, HI}, // DHCPSNAP_ADDRESS_POOL
	{HI, HI, HI, HI, HI, HI, HI, HI, HI, HI, HI, HI}, // DHCPSNAP_ACTIVE_LEASES
	{HI, HI, HI, HI, HI, HI, HI, HI, HI, HI, HI, HI}, // DHCPSNAP_MSCOPE_LEASES
	{HI, HI, HI, HI, HI, HI, HI, EN, HI, HI, HI, HI}, // DHCPSNAP_RESERVATIONS
	{HI, HI, HI, HI, HI, HI, HI, HI, HI, HI, HI, EN}, // DHCPSNAP_RESERVATION_CLIENT
    {HI, HI, HI, HI, HI, HI, HI, HI, HI, HI, EN, HI}, // DHCPSNAP_SCOPE_OPTIONS
	{HI, HI, HI, HI, HI, HI, HI, HI, HI, EN, HI, HI}, // DHCPSNAP_SERVER_OPTIONS
    {HI, HI, HI, HI, HI, HI, HI, HI, HI, HI, HI, HI}, // DHCPSNAP_CLASSID_HOLDER
};

MMC_CONSOLE_VERB g_ConsoleVerbs[] =
{
	MMC_VERB_OPEN,
    MMC_VERB_COPY,
	MMC_VERB_PASTE,
	MMC_VERB_DELETE,
	MMC_VERB_PROPERTIES,
	MMC_VERB_RENAME,
	MMC_VERB_REFRESH,
	MMC_VERB_PRINT
};

// default states for the console verbs
MMC_BUTTON_STATE g_ConsoleVerbStates[DHCPSNAP_NODETYPE_MAX][ARRAYLEN(g_ConsoleVerbs)] =
{
	{HI, HI, HI, HI, HI, HI, HI, HI}, // DHCPSNAP_ROOT
	{HI, HI, HI, EN, EN, HI, EN, HI}, // DHCPSNAP_SERVER
	{HI, HI, HI, HI, HI, HI, EN, HI}, // DHCPSNAP_BOOTP_TABLE
	{HI, HI, HI, EN, EN, HI, EN, HI}, // DHCPSNAP_SUPERSCOPE
	{HI, HI, HI, EN, EN, HI, EN, HI}, // DHCPSNAP_SCOPE
	{HI, HI, HI, EN, EN, HI, EN, HI}, // DHCPSNAP_MSCOPE
	{HI, HI, HI, HI, HI, HI, EN, HI}, // DHCPSNAP_ADDRESS_POOL
	{HI, HI, HI, HI, HI, HI, EN, HI}, // DHCPSNAP_ACTIVE_LEASES
	{HI, HI, HI, HI, HI, HI, EN, HI}, // DHCPSNAP_MSCOPE_LEASES
	{HI, HI, HI, HI, HI, HI, EN, HI}, // DHCPSNAP_RESERVATIONS
	{HI, HI, HI, EN, EN, HI, EN, HI}, // DHCPSNAP_RESERVATION_CLIENT
    {HI, HI, HI, HI, HI, HI, EN, HI}, // DHCPSNAP_SCOPE_OPTIONS
	{HI, HI, HI, HI, HI, HI, EN, HI}, // DHCPSNAP_SERVER_OPTIONS
	{HI, HI, HI, HI, HI, HI, EN, HI}, // DHCPSNAP_CLASSID_HOLDER
	{HI, HI, HI, EN, HI, HI, EN, HI}, // DHCPSNAP_ACTIVE_LEASE
	{HI, HI, HI, HI, HI, HI, EN, HI}, // DHCPSNAP_ALLOCATION_RANGE
	{HI, HI, HI, EN, HI, HI, EN, HI}, // DHCPSNAP_EXCLUSION_RANGE
	{HI, HI, HI, EN, HI, HI, EN, HI}, // DHCPSNAP_BOOTP_ENTRY
    {HI, HI, HI, EN, EN, HI, EN, HI}, // DHCPSNAP_OPTION_ITEM
    {HI, HI, HI, EN, EN, HI, EN, HI}, // DHCPSNAP_CLASSID
    {HI, HI, HI, EN, HI, HI, EN, HI}  // DHCPSNAP_MCAST_LEASE
};

// default states for the console verbs
MMC_BUTTON_STATE g_ConsoleVerbStatesMultiSel[DHCPSNAP_NODETYPE_MAX][ARRAYLEN(g_ConsoleVerbs)] =
{
	{HI, HI, HI, HI, HI, HI, HI, HI}, // DHCPSNAP_ROOT
	{HI, HI, HI, EN, HI, HI, HI, HI}, // DHCPSNAP_SERVER
	{HI, HI, HI, EN, HI, HI, HI, HI}, // DHCPSNAP_BOOTP_TABLE
	{HI, HI, HI, EN, HI, HI, HI, HI}, // DHCPSNAP_SUPERSCOPE
	{HI, HI, HI, HI, HI, HI, HI, HI}, // DHCPSNAP_SCOPE
	{HI, HI, HI, HI, HI, HI, HI, HI}, // DHCPSNAP_MSCOPE
	{HI, HI, HI, EN, HI, HI, HI, HI}, // DHCPSNAP_ADDRESS_POOL
	{HI, HI, HI, EN, HI, HI, HI, HI}, // DHCPSNAP_ACTIVE_LEASES
	{HI, HI, HI, EN, HI, HI, HI, HI}, // DHCPSNAP_MSCOPE_LEASES
	{HI, HI, HI, HI, HI, HI, HI, HI}, // DHCPSNAP_RESERVATIONS
	{HI, HI, HI, EN, HI, HI, HI, HI}, // DHCPSNAP_RESERVATION_CLIENT
    {HI, HI, HI, EN, HI, HI, HI, HI}, // DHCPSNAP_SCOPE_OPTIONS
	{HI, HI, HI, EN, HI, HI, HI, HI}, // DHCPSNAP_SERVER_OPTIONS
	{HI, HI, HI, EN, HI, HI, HI, HI}, // DHCPSNAP_CLASSID_HOLDER
	{HI, HI, HI, HI, HI, HI, HI, HI}, // DHCPSNAP_ACTIVE_LEASE
	{HI, HI, HI, HI, HI, HI, HI, HI}, // DHCPSNAP_ALLOCATION_RANGE
	{HI, HI, HI, HI, HI, HI, HI, HI}, // DHCPSNAP_EXCLUSION_RANGE
	{HI, HI, HI, HI, HI, HI, HI, HI}, // DHCPSNAP_BOOTP_ENTRY
    {HI, HI, HI, HI, HI, HI, HI, HI}, // DHCPSNAP_OPTION_ITEM
    {HI, HI, HI, HI, HI, HI, HI, HI}, // DHCPSNAP_CLASSID
    {HI, HI, HI, HI, HI, HI, HI, HI}  // DHCPSNAP_MCAST_LEASE
};

// Help ID array for help on scope items
DWORD g_dwMMCHelp[DHCPSNAP_NODETYPE_MAX] =
{
	DHCPSNAP_HELP_ROOT,                 // DHCPSNAP_ROOT
	DHCPSNAP_HELP_SERVER,               // DHCPSNAP_SERVER
	DHCPSNAP_HELP_BOOTP_TABLE,          // DHCPSNAP_BOOTP_TABLE
	DHCPSNAP_HELP_SUPERSCOPE,           // DHCPSNAP_SUPERSCOPE
	DHCPSNAP_HELP_SCOPE,                // DHCPSNAP_SCOPE
	DHCPSNAP_HELP_MSCOPE,               // DHCPSNAP_MSCOPE
	DHCPSNAP_HELP_ADDRESS_POOL,         // DHCPSNAP_ADDRESS_POOL
	DHCPSNAP_HELP_ACTIVE_LEASES,        // DHCPSNAP_ACTIVE_LEASES
	DHCPSNAP_HELP_ACTIVE_LEASES,        // DHCPSNAP_MSCOPE_LEASES
	DHCPSNAP_HELP_RESERVATIONS,         // DHCPSNAP_RESERVATIONS
	DHCPSNAP_HELP_RESERVATION_CLIENT,   // DHCPSNAP_RESERVATION_CLIENT
    DHCPSNAP_HELP_SCOPE_OPTIONS,        // DHCPSNAP_SCOPE_OPTIONS
	DHCPSNAP_HELP_GLOBAL_OPTIONS,       // DHCPSNAP_SERVER_OPTIONS
	DHCPSNAP_HELP_CLASSID_HOLDER,       // DHCPSNAP_CLASSID_HOLDER
	DHCPSNAP_HELP_ACTIVE_LEASE,         // DHCPSNAP_ACTIVE_LEASE
	DHCPSNAP_HELP_ALLOCATION_RANGE,     // DHCPSNAP_ALLOCATION_RANGE
	DHCPSNAP_HELP_EXCLUSION_RANGE,      // DHCPSNAP_EXCLUSION_RANGE
	DHCPSNAP_HELP_BOOTP_ENTRY,          // DHCPSNAP_BOOTP_ENTRY
    DHCPSNAP_HELP_OPTION_ITEM,          // DHCPSNAP_OPTION_ITEM
    DHCPSNAP_HELP_CLASSID,              // DHCPSNAP_CLASSID
    DHCPSNAP_HELP_MCAST_LEASE           // DHCPSNAP_MCAST_LEASE
};

// help mapper for dialogs and property pages
struct ContextHelpMap
{
    UINT            uID;
    const DWORD *   pdwMap;
};

ContextHelpMap g_uContextHelp[DHCPSNAP_NUM_HELP_MAPS] =
{
    {IDD_ADD_SERVER,                    g_aHelpIDs_IDD_ADD_SERVER},
    {IDD_ADD_TO_SUPERSCOPE,             g_aHelpIDs_IDD_ADD_TO_SUPERSCOPE},
    {IDD_BINARY_EDITOR,                 g_aHelpIDs_IDD_BINARY_EDITOR},
    {IDD_BOOTP_NEW,                     g_aHelpIDs_IDD_BOOTP_NEW},
    {IDD_BROWSE_SERVERS,                g_aHelpIDs_IDD_BROWSE_SERVERS},
    {IDD_CLASSES,		                g_aHelpIDs_IDD_CLASSES},
    {IDD_CLASSID_NEW,                   g_aHelpIDs_IDD_CLASSID_NEW},
    {IDD_CREDENTIALS,                   g_aHelpIDs_IDD_CREDENTIALS},
    {IDD_DATA_ENTRY_BINARY,             g_aHelpIDs_IDD_DATA_ENTRY_BINARY},
    {IDD_DATA_ENTRY_BINARY_ARRAY,       g_aHelpIDs_IDD_DATA_ENTRY_BINARY_ARRAY},
    {IDD_DATA_ENTRY_DWORD,              g_aHelpIDs_IDD_DATA_ENTRY_DWORD},
    {IDD_DATA_ENTRY_IPADDRESS,          g_aHelpIDs_IDD_DATA_ENTRY_IPADDRESS},
    {IDD_DATA_ENTRY_IPADDRESS_ARRAY,    g_aHelpIDs_IDD_DATA_ENTRY_IPADDRESS_ARRAY},
    {IDD_DATA_ENTRY_NONE,               NULL},
    {IDD_DATA_ENTRY_STRING,             g_aHelpIDs_IDD_DATA_ENTRY_STRING},
    {IDD_DATA_ENTRY_ROUTE_ARRAY,        g_aHelpIDs_IDD_DATA_ENTRY_ROUTE_ARRAY},    
    {IDD_DEFAULT_VALUE,                 g_aHelpIDs_IDD_DEFAULT_VALUE},
    {IDD_DEFINE_PARAM,                  g_aHelpIDs_IDD_DEFINE_PARAM},
    {IDD_EXCLUSION_NEW,                 g_aHelpIDs_IDD_EXCLUSION_NEW},
	{IDD_GET_SERVER,					g_aHelpIDs_IDD_GET_SERVER},
	{IDD_GET_SERVER_CONFIRM,			g_aHelpIDs_IDD_GET_SERVER_CONFIRM},
    {IDD_IP_ARRAY_EDIT,                 g_aHelpIDs_IDD_IP_ARRAY_EDIT},
    {IDD_RECONCILIATION,                g_aHelpIDs_IDD_RECONCILIATION},
    {IDD_RESERVATION_NEW,               g_aHelpIDs_IDD_RESERVATION_NEW},
	{IDD_SERVER_BINDINGS,				g_aHelpIDs_IDD_SERVER_BINDINGS},
    {IDD_STATS_NARROW,                  NULL},
    {IDP_BOOTP_GENERAL,                 g_aHelpIDs_IDP_BOOTP_GENERAL},
    {IDP_DNS_INFORMATION,               g_aHelpIDs_IDP_DNS_INFORMATION},
    {IDP_MSCOPE_GENERAL,                g_aHelpIDs_IDP_MSCOPE_GENERAL},
    {IDP_MSCOPE_LIFETIME,               g_aHelpIDs_IDP_MSCOPE_LIFETIME},
    {IDP_OPTION_ADVANCED,               g_aHelpIDs_IDP_OPTION_ADVANCED},
    {IDP_OPTION_BASIC,                  g_aHelpIDs_IDP_OPTION_BASIC},
    {IDP_RESERVED_CLIENT_GENERAL,       g_aHelpIDs_IDP_RESERVED_CLIENT_GENERAL},
	{IDP_SCOPE_ADVANCED,			    g_aHelpIDs_IDP_SCOPE_ADVANCED},
    {IDP_SCOPE_GENERAL,                 g_aHelpIDs_IDP_SCOPE_GENERAL},
	{IDP_SERVER_ADVANCED,			    g_aHelpIDs_IDP_SERVER_ADVANCED},
    {IDP_SERVER_GENERAL,                g_aHelpIDs_IDP_SERVER_GENERAL},
    {IDP_SUPERSCOPE_GENERAL,            g_aHelpIDs_IDP_SUPERSCOPE_GENERAL},
};

CDhcpContextHelpMap     g_dhcpContextHelpMap;

DWORD * DhcpGetHelpMap(UINT uID) 
{
    DWORD * pdwMap = NULL;
    g_dhcpContextHelpMap.Lookup(uID, pdwMap);
    return pdwMap;
}

UINT g_uIconMap[ICON_IDX_MAX + 1][2] = 
{
    {IDI_ICON01,    ICON_IDX_ACTIVE_LEASES_FOLDER_OPEN},
    {IDI_ICON02,	ICON_IDX_ACTIVE_LEASES_LEAF},
    {IDI_ICON03,	ICON_IDX_ACTIVE_LEASES_FOLDER_CLOSED},
    {IDI_ICON04,	ICON_IDX_ACTIVE_LEASES_FOLDER_OPEN_BUSY},
    {IDI_ICON05,	ICON_IDX_ACTIVE_LEASES_LEAF_BUSY},
    {IDI_ICON06,	ICON_IDX_ACTIVE_LEASES_FOLDER_CLOSED_BUSY},
    {IDI_ICON07,	ICON_IDX_ACTIVE_LEASES_FOLDER_OPEN_LOST_CONNECTION},
    {IDI_ICON08,    ICON_IDX_ACTIVE_LEASES_LEAF_LOST_CONNECTION},
    {IDI_ICON09,	ICON_IDX_ACTIVE_LEASES_FOLDER_CLOSED_LOST_CONNECTION},
    {IDI_ICON10,	ICON_IDX_ADDR_POOL_FOLDER_OPEN},
    {IDI_ICON11,	ICON_IDX_ADDR_POOL_LEAF},
    {IDI_ICON12,	ICON_IDX_ADDR_POOL_FOLDER_CLOSED},
    {IDI_ICON13,	ICON_IDX_ADDR_POOL_FOLDER_OPEN_BUSY},
    {IDI_ICON14,	ICON_IDX_ADDR_POOL_LEAF_BUSY},
    {IDI_ICON15,	ICON_IDX_ADDR_POOL_FOLDER_CLOSED_BUSY},
    {IDI_ICON16,	ICON_IDX_ADDR_POOL_FOLDER_OPEN_LOST_CONNECTION},
    {IDI_ICON17,	ICON_IDX_ADDR_POOL_LEAF_LOST_CONNECTION},
    {IDI_ICON18,	ICON_IDX_ADDR_POOL_FOLDER_CLOSED_LOST_CONNECTION},
    {IDI_ICON19,	ICON_IDX_ALLOCATION_RANGE},
    {IDI_ICON20,	ICON_IDX_BOOTP_ENTRY},
	{IDI_ICON21,	ICON_IDX_BOOTP_TABLE_CLOSED},
	{IDI_ICON22,	ICON_IDX_BOOTP_TABLE_OPEN},
	{IDI_ICON87,	ICON_IDX_BOOTP_TABLE_OPEN_LOST_CONNECTION},
	{IDI_ICON88,	ICON_IDX_BOOTP_TABLE_OPEN_BUSY},
	{IDI_ICON89,	ICON_IDX_BOOTP_TABLE_CLOSED_LOST_CONNECTION},
	{IDI_ICON90,	ICON_IDX_BOOTP_TABLE_CLOSED_BUSY},
    {IDI_ICON23,	ICON_IDX_CLIENT},
    {IDI_ICON24,	ICON_IDX_CLIENT_DNS_REGISTERING},
    {IDI_ICON25,	ICON_IDX_CLIENT_EXPIRED},
    {IDI_ICON26,	ICON_IDX_CLIENT_RAS},
    {IDI_ICON27,	ICON_IDX_CLIENT_OPTION_FOLDER_OPEN},
    {IDI_ICON28,	ICON_IDX_CLIENT_OPTION_LEAF},
    {IDI_ICON29,	ICON_IDX_CLIENT_OPTION_FOLDER_CLOSED},
    {IDI_ICON30,	ICON_IDX_CLIENT_OPTION_FOLDER_OPEN_BUSY},
    {IDI_ICON31,	ICON_IDX_CLIENT_OPTION_LEAF_BUSY},
    {IDI_ICON32,	ICON_IDX_CLIENT_OPTION_FOLDER_CLOSED_BUSY},
    {IDI_ICON33,	ICON_IDX_CLIENT_OPTION_FOLDER_OPEN_LOST_CONNECTION},
    {IDI_ICON34,	ICON_IDX_CLIENT_OPTION_LEAF_LOST_CONNECTION},
    {IDI_ICON35,	ICON_IDX_CLIENT_OPTION_FOLDER_CLOSED_LOST_CONNECTION},
    {IDI_ICON36,	ICON_IDX_EXCLUSION_RANGE},
    {IDI_ICON37,	ICON_IDX_FOLDER_CLOSED},
    {IDI_ICON38,	ICON_IDX_FOLDER_OPEN},
    {IDI_ICON39,	ICON_IDX_RES_CLIENT},
    {IDI_ICON40,	ICON_IDX_RES_CLIENT_BUSY},
    {IDI_ICON41,    ICON_IDX_RES_CLIENT_LOST_CONNECTION},
    {IDI_ICON42,    ICON_IDX_RESERVATIONS_FOLDER_OPEN},
    {IDI_ICON43,	ICON_IDX_RESERVATIONS_FOLDER_CLOSED},
    {IDI_ICON44,	ICON_IDX_RESERVATIONS_FOLDER_OPEN_BUSY},
    {IDI_ICON45,	ICON_IDX_RESERVATIONS_FOLDER_CLOSED_BUSY},
    {IDI_ICON46,	ICON_IDX_RESERVATIONS_FOLDER_OPEN_LOST_CONNECTION},
    {IDI_ICON47,	ICON_IDX_RESERVATIONS_FOLDER_CLOSED_LOST_CONNECTION},
    {IDI_ICON48,	ICON_IDX_SCOPE_OPTION_FOLDER_OPEN},
    {IDI_ICON49,	ICON_IDX_SCOPE_OPTION_LEAF},
    {IDI_ICON50,	ICON_IDX_SCOPE_OPTION_FOLDER_CLOSED},
    {IDI_ICON51,	ICON_IDX_SCOPE_OPTION_FOLDER_OPEN_BUSY},
    {IDI_ICON52,	ICON_IDX_SCOPE_OPTION_LEAF_BUSY},
    {IDI_ICON53,	ICON_IDX_SCOPE_OPTION_FOLDER_CLOSED_BUSY},
    {IDI_ICON54,	ICON_IDX_SCOPE_OPTION_FOLDER_OPEN_LOST_CONNECTION},
    {IDI_ICON55,	ICON_IDX_SCOPE_OPTION_FOLDER_CLOSED_LOST_CONNECTION},
    {IDI_ICON56,	ICON_IDX_SCOPE_OPTION_LEAF_LOST_CONNECTION},
    {IDI_ICON57,	ICON_IDX_SERVER},
    {IDI_ICON58,	ICON_IDX_SERVER_WARNING},
    {IDI_ICON59,	ICON_IDX_SERVER_BUSY},
    {IDI_ICON60,	ICON_IDX_SERVER_CONNECTED},
    {IDI_ICON61,	ICON_IDX_SERVER_GROUP},
    {IDI_ICON62,	ICON_IDX_SERVER_ROGUE},
    {IDI_ICON63,	ICON_IDX_SERVER_LOST_CONNECTION},
    {IDI_ICON64,	ICON_IDX_SERVER_NO_ACCESS},
    {IDI_ICON65,	ICON_IDX_SERVER_ALERT},
    {IDI_ICON66,	ICON_IDX_SERVER_OPTION_FOLDER_OPEN},
    {IDI_ICON67,	ICON_IDX_SERVER_OPTION_LEAF},
    {IDI_ICON68,	ICON_IDX_SERVER_OPTION_FOLDER_CLOSED},
    {IDI_ICON69,	ICON_IDX_SERVER_OPTION_FOLDER_OPEN_BUSY},
    {IDI_ICON70,	ICON_IDX_SERVER_OPTION_LEAF_BUSY},
    {IDI_ICON71,	ICON_IDX_SERVER_OPTION_FOLDER_CLOSED_BUSY},
    {IDI_ICON72,	ICON_IDX_SERVER_OPTION_FOLDER_OPEN_LOST_CONNECTION},
    {IDI_ICON73,	ICON_IDX_SERVER_OPTION_LEAF_LOST_CONNECTION},
    {IDI_ICON74,	ICON_IDX_SERVER_OPTION_FOLDER_CLOSED_LOST_CONNECTION},
    {IDI_ICON75,	ICON_IDX_SCOPE_FOLDER_OPEN},
    {IDI_ICON91,	ICON_IDX_SCOPE_FOLDER_OPEN_BUSY},
	{IDI_ICON92,	ICON_IDX_SCOPE_FOLDER_CLOSED_BUSY},					
    {IDI_ICON76,	ICON_IDX_SCOPE_FOLDER_OPEN_WARNING},
    {IDI_ICON77,    ICON_IDX_SCOPE_FOLDER_CLOSED_WARNING},
    {IDI_ICON78,	ICON_IDX_SCOPE_FOLDER_OPEN_LOST_CONNECTION},
    {IDI_ICON79,	ICON_IDX_SCOPE_FOLDER_CLOSED_LOST_CONNECTION},
    {IDI_ICON80,	ICON_IDX_SCOPE_FOLDER_OPEN_ALERT},
    {IDI_ICON81,	ICON_IDX_SCOPE_INACTIVE_FOLDER_OPEN},
    {IDI_ICON82,	ICON_IDX_SCOPE_INACTIVE_FOLDER_CLOSED},
    {IDI_ICON83,	ICON_IDX_SCOPE_INACTIVE_FOLDER_OPEN_LOST_CONNECTION},
    {IDI_ICON84,	ICON_IDX_SCOPE_INACTIVE_FOLDER_CLOSED_LOST_CONNECTION},
    {IDI_ICON85,	ICON_IDX_SCOPE_FOLDER_CLOSED},
    {IDI_ICON86,	ICON_IDX_SCOPE_FOLDER_CLOSED_ALERT},
	{IDI_DHCP_SNAPIN, ICON_IDX_APPLICATION},
    {0, 0}
};

/*!--------------------------------------------------------------------------
	FilterOption
		Filters returns whether or not to filter out the given option.
		Some options we don't want the user to see.
	Author: EricDav
 ---------------------------------------------------------------------------*/
BOOL
FilterOption
(
    DHCP_OPTION_ID id
)
{
    //
    // Filter out subnet mask, lease duration,
    // T1, and T2
    //
    return (id == 1  ||  // Subnet mask
			id == 51 ||  // Client Lease Time
			id == 58 ||  // Time between addr assignment  to RENEWING state
			id == 59 ||  // Time from addr assignment to REBINDING state
			id == 81);   // Client DNS name registration
}

/*!--------------------------------------------------------------------------
	FilterUserClassOption
		Filters returns whether or not to filter out the given option for
        a user class. Some options we don't want the user to see.
	Author: EricDav
 ---------------------------------------------------------------------------*/
BOOL
FilterUserClassOption
(
    DHCP_OPTION_ID id
)
{
    //
    // Filter out subnet mask, 
    // T1, and T2
    //
    return (id == 1  ||  // Subnet mask
			id == 58 ||  // Time between addr assignment  to RENEWING state
			id == 59 ||  // Time from addr assignment to REBINDING state
			id == 81);   // Client DNS name registration
}


/*!--------------------------------------------------------------------------
	IsBasicOption
		Returns whether the given option is what we've defined as a 
		basic option.
	Author: EricDav
 ---------------------------------------------------------------------------*/
BOOL
IsBasicOption
(
    DHCP_OPTION_ID id
)
{
    //
    // Basic Options are:
	//	Router
	//	DNS Server
	//	Domain Name
	//	WINS/NBNS Servers
	//	WINS/NBT Node Type
    //
    return (id == 3  || 
			id == 6	 || 
			id == 15 || 
			id == 44 || 
			id == 46);
}

/*!--------------------------------------------------------------------------
	IsAdvancedOption
		Returns whether the given option is what we've defined as an
		advanced option.
	Author: EricDav
 ---------------------------------------------------------------------------*/
BOOL
IsAdvancedOption
(
    DHCP_OPTION_ID id
)
{
    //
    // All non-basic and non-custom options are advanced.
    //
    return (id < 128 && !IsBasicOption(id)); 
}

/*!--------------------------------------------------------------------------
	IsCustomOption
		Returns whether the given option is a user defined option.
	Author: EricDav
 ---------------------------------------------------------------------------*/
BOOL
IsCustomOption
(
    DHCP_OPTION_ID id
)
{
    //
    // Custom options are anything with an id > 128
	//
    return (id > 128);
}

/*!--------------------------------------------------------------------------
	GetSystemMessage
		Use FormatMessage() to get a system error message
	Author: EricDav
 ---------------------------------------------------------------------------*/
LONG 
GetSystemMessage 
(
    UINT	nId,
    TCHAR *	chBuffer,
    int		cbBuffSize 
)
{
    TCHAR * pszText = NULL ;
    HINSTANCE hdll = NULL ;

    DWORD flags = FORMAT_MESSAGE_IGNORE_INSERTS
        | FORMAT_MESSAGE_MAX_WIDTH_MASK;

    //
    //  Interpret the error.  Need to special case
    //  the lmerr & ntstatus ranges, as well as
    //  dhcp server error messages.
    //

    if ( nId >= NERR_BASE && nId <= MAX_NERR )
    {
        hdll = LoadLibraryEx( _T("netmsg.dll"), NULL,  LOAD_LIBRARY_AS_DATAFILE);
    }
    else 
	if ( nId >= 20000 && nId <= 20099 )
    {
		// DHCP Server error 
        hdll = LoadLibraryEx( _T("dhcpsapi.dll"), NULL, LOAD_LIBRARY_AS_DATAFILE );
    }
	else
	if (nId >= 0x5000 && nId < 0x50FF)
	{
		// It's an ADSI error.  
		hdll = LoadLibraryEx( _T("activeds.dll"), NULL, LOAD_LIBRARY_AS_DATAFILE );
		nId |= 0x80000000;
	}
    else 
	if( nId >= 0x40000000L )
    {
        hdll = LoadLibraryEx( _T("ntdll.dll"), NULL, LOAD_LIBRARY_AS_DATAFILE );
    }

    if ( hdll == NULL )
    {
        flags |= FORMAT_MESSAGE_FROM_SYSTEM;
    }
    else
    {
        flags |= FORMAT_MESSAGE_FROM_HMODULE;
    }

    //
    //  Let FormatMessage do the dirty work.
    //
    DWORD dwResult = ::FormatMessage( flags,
                      (LPVOID) hdll,
                      nId,
                      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                      chBuffer,
                      cbBuffSize,
                      NULL ) ;

    if ( hdll != NULL )
    {
        LONG err = GetLastError();
        FreeLibrary( hdll );
        if ( dwResult == 0 )
        {
            ::SetLastError( err );
        }
    }

    return dwResult ? 0 : ::GetLastError() ;
}

/*!--------------------------------------------------------------------------
	LoadMessage
		Loads the error message from the correct DLL.
	Author: EricDav
 ---------------------------------------------------------------------------*/
BOOL
LoadMessage 
(
    UINT	nIdPrompt,
    TCHAR *	chMsg,
    int		nMsgSize
)
{
    BOOL bOk;

    //
    // Substitute a friendly message for "RPC server not
    // available" and "No more endpoints available from
    // the endpoint mapper".
    //
    if (nIdPrompt == EPT_S_NOT_REGISTERED ||
        nIdPrompt == RPC_S_SERVER_UNAVAILABLE)
    {
        nIdPrompt = IDS_ERR_DHCP_DOWN;
    }
    else if (nIdPrompt == RPC_S_PROCNUM_OUT_OF_RANGE)
    {
        nIdPrompt = IDS_ERR_RPC_NO_ENTRY;      
    }

    //
    //  If it's a socket error or our error, the text is in our resource fork.
    //  Otherwise, use FormatMessage() and the appropriate DLL.
    //
    if ( (nIdPrompt >= IDS_ERR_BASE && nIdPrompt < IDS_MESG_MAX) || 
		 (nIdPrompt >= WSABASEERR && nIdPrompt < WSABASEERR + 2000)
       )
    {
        //
        //  It's in our resource fork
        //
        bOk = ::LoadString( AfxGetInstanceHandle(), nIdPrompt, chMsg, nMsgSize ) != 0 ;
    }
    else
	{
        //
        //  It's in the system somewhere.
        //
        bOk = GetSystemMessage( nIdPrompt, chMsg, nMsgSize ) == 0 ;
    }

    //
    //  If the error message did not compute, replace it.
    //
    if ( ! bOk ) 
    {
        TCHAR chBuff [STRING_LENGTH_MAX] ;
        static const TCHAR * pszReplacement = _T("System Error: %ld");
        const TCHAR * pszMsg = pszReplacement ;

        //
        //  Try to load the generic (translatable) error message text
        //
        if ( ::LoadString( AfxGetInstanceHandle(), IDS_ERR_MESSAGE_GENERIC, 
            chBuff, sizeof(chBuff)/sizeof(TCHAR) ) != 0 ) 
        {
            pszMsg = chBuff ;
        }
        ::wsprintf( chMsg, pszMsg, nIdPrompt ) ;
    }

    return bOk;
}

/*!--------------------------------------------------------------------------
	DhcpMessageBox
		Puts up a message box with the corresponding error text.
	Author: EricDav
 ---------------------------------------------------------------------------*/
int 
DhcpMessageBox 
(
    DWORD			dwIdPrompt,
    UINT			nType,
    const TCHAR *	pszSuffixString,
    UINT			nHelpContext 
)
{
    TCHAR chMesg [4000] ;
    BOOL bOk ;

    UINT        nIdPrompt = (UINT) dwIdPrompt;

    bOk = LoadMessage(nIdPrompt, chMesg, sizeof(chMesg)/sizeof(TCHAR));
    if ( pszSuffixString ) 
    {
        ::lstrcat( chMesg, _T("  ") ) ;
        ::lstrcat( chMesg, pszSuffixString ) ; 
    }

    return ::AfxMessageBox( chMesg, nType, nHelpContext ) ;
}

/*!--------------------------------------------------------------------------
	DhcpMessageBoxEx
		Puts up a message box with the corresponding error text.
	Author: EricDav
 ---------------------------------------------------------------------------*/
int 
DhcpMessageBoxEx
(
    DWORD       dwIdPrompt,
    LPCTSTR     pszPrefixMessage,
    UINT        nType,
    UINT        nHelpContext
)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());

    TCHAR       chMesg[4000];
    CString     strMessage;
    BOOL        bOk;

    UINT        nIdPrompt = (UINT) dwIdPrompt;

    bOk = LoadMessage(nIdPrompt, chMesg, sizeof(chMesg)/sizeof(TCHAR));
    if ( pszPrefixMessage ) 
    {
        strMessage = pszPrefixMessage;
        strMessage += _T("\n");
        strMessage += _T("\n");
        strMessage += chMesg;
    }
    else
    {
        strMessage = chMesg;
    }

    return AfxMessageBox(strMessage, nType, nHelpContext);
}

/*---------------------------------------------------------------------------
	Class CDhcpComponent implementation
 ---------------------------------------------------------------------------*/
CDhcpComponent::CDhcpComponent()
{
	m_pbmpToolbar = NULL;
}

CDhcpComponent::~CDhcpComponent()
{
    if (m_pbmpToolbar)
    {
        delete m_pbmpToolbar;
        m_pbmpToolbar = NULL;
    }
}

STDMETHODIMP CDhcpComponent::InitializeBitmaps(MMC_COOKIE cookie)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());

    ASSERT(m_spImageList != NULL);
    
    // Set the images
    HICON       hIcon;
    HRESULT     hr;
    LPOLESTR    pszGuid = NULL;
    long        lViewOptions = 0;
    CLSID       clsid;

    CORg (GetResultViewType(cookie, &pszGuid, &lViewOptions));
    CLSIDFromString(pszGuid, &clsid);

    // if the result pane is not the message view then add the icons
    if (clsid != CLSID_MessageView)
    {
        for (int i = 0; i < ICON_IDX_MAX; i++)
        {
            hIcon = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(g_uIconMap[i][0]));
            if (hIcon)
            {
                // call mmc
                hr = m_spImageList->ImageListSetIcon(reinterpret_cast<LONG_PTR*>(hIcon), g_uIconMap[i][1]);
            }
        }
    }
    
Error:
	return S_OK;
}

/*!--------------------------------------------------------------------------
	CDhcpComponentData::QueryDataObject
		For multiple select we need to add things to the data object.....
        In order to do this we need to call into the result handler for 
        the node
	Author: EricDav
 ---------------------------------------------------------------------------*/
STDMETHODIMP CDhcpComponent::QueryDataObject
(
    MMC_COOKIE          cookie, 
    DATA_OBJECT_TYPES   type,
    LPDATAOBJECT*       ppDataObject
)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());

    HRESULT hr = hrOK;
    SPITFSNode spRootNode;

    // this is a special case for multiple select.  We need to build a list
    // of GUIDs and the code to do this is in the handler...
    if (cookie == MMC_MULTI_SELECT_COOKIE)
    {
        SPITFSNode spNode;
        SPITFSResultHandler spResultHandler;

        CORg (GetSelectedNode(&spNode));
        CORg (spNode->GetResultHandler(&spResultHandler));

        spResultHandler->OnCreateDataObject(this, cookie, type, ppDataObject);
    }
    else
    if (cookie == MMC_WINDOW_COOKIE)
    {
        // this cookie needs the text for the static root node, so build the DO with
        // the root node cookie
        m_spNodeMgr->GetRootNode(&spRootNode);
        CORg (m_spComponentData->QueryDataObject((MMC_COOKIE) spRootNode->GetData(TFS_DATA_COOKIE), type, ppDataObject));
    }
    else
    {
        // Delegate it to the IComponentData
        Assert(m_spComponentData != NULL);
        CORg (m_spComponentData->QueryDataObject(cookie, type, ppDataObject));
    }

Error:
    return hr;
}

/*!--------------------------------------------------------------------------
	CDhcpComponentData::SetControlbar
		-
	Author: EricDav, KennT
 ---------------------------------------------------------------------------*/
HRESULT
CDhcpComponent::SetControlbar
(
	LPCONTROLBAR	pControlbar
)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());

    HRESULT hr = hrOK;
    SPIToolbar  spToolbar;

    COM_PROTECT_TRY
    {
        if (pControlbar)
        {
            // Create the Toolbar
            GetToolbar(&spToolbar);

            if (!spToolbar)
            {
		        CORg(pControlbar->Create(TOOLBAR, this, reinterpret_cast<LPUNKNOWN*>(&spToolbar)));
		        
                if (!spToolbar)
                    goto Error;

                SetToolbar(spToolbar);

		        // Add the bitmap
                m_pbmpToolbar = new CBitmap;
		        m_pbmpToolbar->LoadBitmap(IDB_TOOLBAR);
		        hr = spToolbar->AddBitmap(TOOLBAR_IDX_MAX, *m_pbmpToolbar, 16, 16, RGB(192, 192, 192));
		        ASSERT(SUCCEEDED(hr));

		        // Add the buttons to the toolbar
		        for (int i = 0; i < TOOLBAR_IDX_MAX; i++)
                {
                    CString strText, strTooltip;
                
                    strText.LoadString(g_SnapinButtonStrings[i][0]);
                    strTooltip.LoadString(g_SnapinButtonStrings[i][1]);

                    g_SnapinButtons[i].lpButtonText = (LPOLESTR) ((LPCTSTR) strText);
                    g_SnapinButtons[i].lpTooltipText = (LPOLESTR) ((LPCTSTR) strTooltip);

                    hr = spToolbar->InsertButton(i, &g_SnapinButtons[i]);
		            ASSERT(SUCCEEDED(hr));
                }
            }
        }
    }
    COM_PROTECT_CATCH

    // store the control bar away for future use
Error:
    m_spControlbar.Set(pControlbar);

	return hr;
}

/*!--------------------------------------------------------------------------
	CDhcpComponentData::ControlbarNotify
		-
	Author: EricDav
 ---------------------------------------------------------------------------*/
STDMETHODIMP 
CDhcpComponent::ControlbarNotify
(
	MMC_NOTIFY_TYPE event, 
	LPARAM			arg, 
	LPARAM			param
)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());

    HRESULT             hr = hrOK;
	SPINTERNAL		    spInternal;
	SPITFSNode          spNode;
    MMC_COOKIE          cookie;
    LPDATAOBJECT        pDataObject;
    SPIDataObject       spDataObject;
    DHCPTOOLBARNOTIFY   dhcpToolbarNotify;
	SPIControlBar       spControlbar;
    SPIToolbar          spToolbar;
    SPITFSNodeHandler   spNodeHandler;
    SPITFSResultHandler spResultHandler;
    BOOL                bScope;
    BOOL                bSelect;

    COM_PROTECT_TRY
    {
        CORg(GetControlbar(&spControlbar));
        Assert(spControlbar != NULL);

        CORg(GetToolbar(&spToolbar));
        Assert(spToolbar != NULL);

        // set the controlbar and toolbar pointers in the notify struct
        dhcpToolbarNotify.pControlbar = spControlbar;
        dhcpToolbarNotify.pToolbar = spToolbar;
        
        switch (event)
        {
            case MMCN_SELECT:
                // extract the node information from the data object
                bScope = LOWORD(arg);
                bSelect = HIWORD(arg);
    
                if (!bScope)
                {
                    Assert(param);
                    pDataObject = reinterpret_cast<LPDATAOBJECT>(param);
                    if (pDataObject == NULL)
                        return hr;

                    if ( IS_SPECIAL_DATAOBJECT(pDataObject) ||
                         IsMMCMultiSelectDataObject(pDataObject) )
                    {
                        // CODEWORK:  Do we need to do anything special to the toolbar
                        // during multiselect?  Disable our toolbar buttons?
                        GetSelectedNode(&spNode);
                    }
                    else
                    {
                        CORg(ExtractNodeFromDataObject(m_spNodeMgr,
							                           m_spTFSComponentData->GetCoClassID(),
							                           pDataObject, 
                                                       FALSE,
							                           &spNode,
                                                       NULL, 
                                                       &spInternal));

                        if (spInternal->m_type == CCT_RESULT)
                        {
                            // a result item was selected
                            cookie = spNode->GetData(TFS_DATA_COOKIE);
                        }
                        else
                        {
                            // a scope item in the result pane was selected
                            cookie = NULL;
                        }
                    }
                    
                    if (spNode)
                    {
                        CORg( spNode->GetResultHandler(&spResultHandler) );

                        dhcpToolbarNotify.event = event;
                        dhcpToolbarNotify.id = param;
                        dhcpToolbarNotify.bSelect = bSelect;

                        if (spResultHandler)
			                CORg( spResultHandler->UserResultNotify(spNode, DHCP_MSG_CONTROLBAR_NOTIFY, (LPARAM) &dhcpToolbarNotify) );
                    }
                }
                else
                {
                    dhcpToolbarNotify.cookie = 0;
                    dhcpToolbarNotify.event = event;
                    dhcpToolbarNotify.id = 0;
                    dhcpToolbarNotify.bSelect = bSelect;

                    // check to see if an item is being deselected
                    Assert(param);
                    pDataObject = reinterpret_cast<LPDATAOBJECT>(param);
                    if (pDataObject == NULL)
                        return hr;

                    CORg(ExtractNodeFromDataObject(m_spNodeMgr,
							                       m_spTFSComponentData->GetCoClassID(),
							                       pDataObject, 
                                                   FALSE,
							                       &spNode,
                                                   NULL, 
                                                   &spInternal));

                    CORg( spNode->GetHandler(&spNodeHandler) );
        
            
                    if (spNodeHandler)
			            CORg( spNodeHandler->UserNotify(spNode, DHCP_MSG_CONTROLBAR_NOTIFY, (LPARAM) &dhcpToolbarNotify) );
                }
                break;

            case MMCN_BTN_CLICK:
                Assert(arg);
                pDataObject = reinterpret_cast<LPDATAOBJECT>(arg);
                if (pDataObject == NULL)
                    return hr;

                if ( IS_SPECIAL_DATAOBJECT(pDataObject) )
                {
                    // get a data object for the selected node.
                    GetSelectedNode(&spNode);

                    CORg(QueryDataObject((MMC_COOKIE) spNode->GetData(TFS_DATA_COOKIE), CCT_SCOPE, &spDataObject));
                    spNode.Release();                

                    pDataObject = spDataObject;
                }

                CORg(ExtractNodeFromDataObject(m_spNodeMgr,
							                   m_spTFSComponentData->GetCoClassID(),
							                   pDataObject, 
                                               FALSE,
							                   &spNode,
                                               NULL, 
                                               &spInternal));

                if (spInternal)
                {
                    switch (spInternal->m_type)
                    {
                        case CCT_RESULT:
                            cookie = spNode->GetData(TFS_DATA_COOKIE);
                            CORg( spNode->GetResultHandler(&spResultHandler) );
		                    
                            dhcpToolbarNotify.cookie = cookie;
                            dhcpToolbarNotify.event = event;
                            dhcpToolbarNotify.id = param;
                            dhcpToolbarNotify.bSelect = TRUE;

                            if (spResultHandler)
			                    CORg( spResultHandler->UserResultNotify(spNode, 
                                                                        DHCP_MSG_CONTROLBAR_NOTIFY, 
                                                                        (LPARAM) &dhcpToolbarNotify) );

                            break;

                        case CCT_SCOPE:
                            CORg( spNode->GetHandler(&spNodeHandler) );
		                    
                            dhcpToolbarNotify.cookie = 0;
                            dhcpToolbarNotify.event = event;
                            dhcpToolbarNotify.id = param;
                            dhcpToolbarNotify.bSelect = TRUE;

                            if (spNodeHandler)
			                    CORg( spNodeHandler->UserNotify(spNode, 
                                                                DHCP_MSG_CONTROLBAR_NOTIFY, 
                                                                (LPARAM) &dhcpToolbarNotify) );
                            break;
    
                        default:
                            Assert(FALSE);
                            break;
                    }
                }
                break;

            case MMCN_DESELECT_ALL:
                // what are we supposed to do here???
                break;

            default:
                Panic1("CDhcpComponent::ControlbarNotify - Unknown event %d", event);
                break;

        }
        COM_PROTECT_ERROR_LABEL;
    }
    COM_PROTECT_CATCH

    return hr;
}

/*!--------------------------------------------------------------------------
	CDhcpComponentData::OnSnapinHelp
		-
	Author: EricDav
 ---------------------------------------------------------------------------*/
STDMETHODIMP 
CDhcpComponent::OnSnapinHelp
(
	LPDATAOBJECT	pDataObject,
	LPARAM			arg, 
	LPARAM			param
)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());

	HRESULT hr = hrOK;

    HtmlHelpA(NULL, DHCPSNAP_HELP_FILE_NAME, HH_DISPLAY_TOPIC, 0);

	return hr;
}

/*---------------------------------------------------------------------------
	Class CDhcpComponentData implementation
 ---------------------------------------------------------------------------*/
CDhcpComponentData::CDhcpComponentData()
{
    gliDhcpsnapVersion.LowPart = DHCPSNAP_MINOR_VERSION;
	gliDhcpsnapVersion.HighPart = DHCPSNAP_MAJOR_VERSION;

    // initialize our global help map
    for (int i = 0; i < DHCPSNAP_NUM_HELP_MAPS; i++)
    {
        g_dhcpContextHelpMap.SetAt(g_uContextHelp[i].uID, (LPDWORD) g_uContextHelp[i].pdwMap);
    }
}

/*!--------------------------------------------------------------------------
	CDhcpComponentData::OnInitialize
		-
	Author: EricDav, KennT
 ---------------------------------------------------------------------------*/
STDMETHODIMP CDhcpComponentData::OnInitialize(LPIMAGELIST pScopeImage)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());

    HICON   hIcon;

    // thread deletes itself
    CStandaloneAuthServerWorker * pWorker = new CStandaloneAuthServerWorker();
    pWorker->CreateThread();

    // initialize icon images with MMC
    for (int i = 0; i < ICON_IDX_MAX; i++)
    {
        hIcon = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(g_uIconMap[i][0]));
        if (hIcon)
        {
            // call mmc
            VERIFY(SUCCEEDED(pScopeImage->ImageListSetIcon(reinterpret_cast<LONG_PTR*>(hIcon), g_uIconMap[i][1])));
        }
    }

	return hrOK;
}

/*!--------------------------------------------------------------------------
	CDhcpComponentData::OnDestroy
		-
	Author: EricDav, KennT
 ---------------------------------------------------------------------------*/
STDMETHODIMP CDhcpComponentData::OnDestroy()
{
	m_spNodeMgr.Release();

    if (g_bDhcpDsInitialized)
    {
        ::DhcpDsCleanup();
        g_bDhcpDsInitialized = FALSE;
    }

    return hrOK;
}

/*!--------------------------------------------------------------------------
	CDhcpComponentData::OnInitializeNodeMgr
		-
	Author: KennT
 ---------------------------------------------------------------------------*/
STDMETHODIMP 
CDhcpComponentData::OnInitializeNodeMgr
(
	ITFSComponentData *	pTFSCompData, 
	ITFSNodeMgr *		pNodeMgr
)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	// For now create a new node handler for each new node,
	// this is rather bogus as it can get expensive.  We can
	// consider creating only a single node handler for each
	// node type.
	CDhcpRootHandler *	pHandler = NULL;
	SPITFSNodeHandler	spHandler;
	SPITFSNode			spNode;
	HRESULT				hr = hrOK;

	try
	{
		pHandler = new CDhcpRootHandler(pTFSCompData);

		// Do this so that it will get released correctly
		spHandler = pHandler;
	}
	catch(...)
	{
		hr = E_OUTOFMEMORY;
	}
	CORg( hr );
	
	// Create the root node for this sick puppy
	CORg( CreateContainerTFSNode(&spNode,
								 &GUID_DhcpRootNodeType,
								 pHandler,
								 pHandler,		 /* result handler */
								 pNodeMgr) );

	// Need to initialize the data for the root node
	pHandler->InitializeNode(spNode);	

	CORg( pNodeMgr->SetRootNode(spNode) );
	m_spRootNode.Set(spNode);

    // setup watermark info
    if (g_WatermarkInfoServer.hHeader == NULL)
    {
        // haven't been initialized yet
        InitWatermarkInfo(AfxGetInstanceHandle(),
                          &g_WatermarkInfoServer,      
                          IDB_SRVWIZ_BANNER,        // Header ID
                          IDB_SRVWIZ_WATERMARK,     // Watermark ID
                          NULL,                     // hPalette
                          FALSE);                   // bStretch

        InitWatermarkInfo(AfxGetInstanceHandle(),
                          &g_WatermarkInfoScope,      
                          IDB_SCPWIZ_BANNER,        // Header ID
                          IDB_SCPWIZ_WATERMARK,     // Watermark ID
                          NULL,                     // hPalette
                          FALSE);                   // bStretch
    }

    pTFSCompData->SetHTMLHelpFileName(_T(DHCPSNAP_HELP_FILE_NAME));
    
	// disable taskpads by default
	pTFSCompData->SetTaskpadState(TASKPAD_ROOT_INDEX, FALSE);
    pTFSCompData->SetTaskpadState(TASKPAD_SERVER_INDEX, FALSE);


Error:	
	return hr;
}

/*!--------------------------------------------------------------------------
	CDhcpComponentData::OnCreateComponent
		-
	Author: EricDav, KennT
 ---------------------------------------------------------------------------*/
STDMETHODIMP 
CDhcpComponentData::OnCreateComponent
(
	LPCOMPONENT *ppComponent
)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

    ASSERT(ppComponent != NULL);
	
	HRESULT			  hr = hrOK;
	CDhcpComponent *  pComp = NULL;

	try
	{
		pComp = new CDhcpComponent;
	}
	catch(...)
	{
		hr = E_OUTOFMEMORY;
	}

	if (FHrSucceeded(hr))
	{
		pComp->Construct(m_spNodeMgr,
						static_cast<IComponentData *>(this),
						m_spTFSComponentData);
		*ppComponent = static_cast<IComponent *>(pComp);
	}
	return hr;
}

/*!--------------------------------------------------------------------------
	CDhcpComponentData::GetCoClassID
		-
	Author: KennT
 ---------------------------------------------------------------------------*/
STDMETHODIMP_(const CLSID *) 
CDhcpComponentData::GetCoClassID()
{
	return &CLSID_DhcpSnapin;
}

/*!--------------------------------------------------------------------------
	CDhcpComponentData::OnCreateDataObject
		-
	Author: KennT
 ---------------------------------------------------------------------------*/
STDMETHODIMP 
CDhcpComponentData::OnCreateDataObject
(
	MMC_COOKIE			cookie, 
	DATA_OBJECT_TYPES	type, 
	IDataObject **		ppDataObject
)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());

    Assert(ppDataObject != NULL);

	CDataObject *	pObject = NULL;
	SPIDataObject	spDataObject;
	
	pObject = new CDataObject;
	spDataObject = pObject;	// do this so that it gets released correctly
						
    Assert(pObject != NULL);

    // Save cookie and type for delayed rendering
    pObject->SetType(type);
    pObject->SetCookie(cookie);

    // Store the coclass with the data object
    pObject->SetClsid(*GetCoClassID());

	pObject->SetTFSComponentData(m_spTFSComponentData);

    return  pObject->QueryInterface(IID_IDataObject, 
									reinterpret_cast<void**>(ppDataObject));
}

///////////////////////////////////////////////////////////////////////////////
//// IPersistStream interface members
STDMETHODIMP 
CDhcpComponentData::GetClassID
(
	CLSID *pClassID
)
{
    ASSERT(pClassID != NULL);

    // Copy the CLSID for this snapin
    *pClassID = CLSID_DhcpSnapin;

    return hrOK;
}

STDMETHODIMP 
CDhcpComponentData::IsDirty()
{
	return m_spRootNode->GetData(TFS_DATA_DIRTY) ? hrOK : hrFalse;
}

STDMETHODIMP 
CDhcpComponentData::Load
(
	IStream *pStm
)
{
	HRESULT         hr = hrOK;
	LARGE_INTEGER   liSavedVersion;
	CString         str;
    
	ASSERT(pStm);

    CStringArray    strArrayIp;
    CStringArray    strArrayName;
    CDWordArray     dwArrayServerOptions;
    CDWordArray     dwArrayRefreshInterval;
	CDWordArray     dwArrayColumnInfo;
    DWORD           dwFileVersion;
    CDhcpRootHandler * pRootHandler;
    DWORD           dwFlags = 0;
    int             i, j;

    ASSERT(pStm);
    
    // set the mode for this stream
    XferStream xferStream(pStm, XferStream::MODE_READ);    
    
    // read the version of the file format
    CORg(xferStream.XferDWORD(DHCPSTRM_TAG_VERSION, &dwFileVersion));
	if (dwFileVersion < DHCPSNAP_FILE_VERSION)
	{
	    AFX_MANAGE_STATE(AfxGetStaticModuleState());
		AfxMessageBox(_T("This console file was saved with a previous version of the snapin and is not compatible.  The settings could not be restored."));
		return hr;
	}

    // Read the version # of the admin tool
    CORg(xferStream.XferLARGEINTEGER(DHCPSTRM_TAG_VERSIONADMIN, &liSavedVersion));
	if (liSavedVersion.QuadPart < gliDhcpsnapVersion.QuadPart)
	{
		// File is an older version.  Warn the user and then don't
		// load anything else
		Assert(FALSE);
	}

	// Read the root node name
    CORg(xferStream.XferCString(DHCPSTRM_TAB_SNAPIN_NAME, &str));
	Assert(m_spRootNode);
	pRootHandler = GETHANDLER(CDhcpRootHandler, m_spRootNode);
	pRootHandler->SetDisplayName(str);
    
    // now read all of the server information
    CORg(xferStream.XferCStringArray(DHCPSTRM_TAG_SERVER_IP, &strArrayIp));
    CORg(xferStream.XferCStringArray(DHCPSTRM_TAG_SERVER_NAME, &strArrayName));
    CORg(xferStream.XferDWORDArray(DHCPSTRM_TAG_SERVER_OPTIONS, &dwArrayServerOptions));
    CORg(xferStream.XferDWORDArray(DHCPSTRM_TAG_SERVER_REFRESH_INTERVAL, &dwArrayRefreshInterval));

	// now load the column information
	for (i = 0; i < NUM_SCOPE_ITEMS; i++)
	{
		CORg(xferStream.XferDWORDArray(DHCPSTRM_TAG_COLUMN_INFO, &dwArrayColumnInfo));

		for (j = 0; j < MAX_COLUMNS; j++)
		{
            // mmc now saves column widths for us, but we don't want to change the
            // format of this file, so just don't set our internal struct
			//aColumnWidths[i][j] = dwArrayColumnInfo[j];
		}

	}

    // now create the servers based on the information
    for (i = 0; i < strArrayIp.GetSize(); i++)
	{
		//
		// now create the server object
		//
		pRootHandler->AddServer((LPCWSTR) strArrayIp[i], 
                                strArrayName[i],
                                FALSE, 
                                dwArrayServerOptions[i], 
                                dwArrayRefreshInterval[i]);
	}

    // read in flags (for taskpads)
    CORg(xferStream.XferDWORD(DHCPSTRM_TAG_SNAPIN_OPTIONS, &dwFlags));

    if (!FUseTaskpadsByDefault(NULL))
        dwFlags = 0;

	// disable taskpads, the default is off
    //m_spTFSComponentData->SetTaskpadState(TASKPAD_ROOT_INDEX, dwFlags & TASKPAD_ROOT_FLAG);
    //m_spTFSComponentData->SetTaskpadState(TASKPAD_SERVER_INDEX, dwFlags & TASKPAD_SERVER_FLAG);

Error:
    return SUCCEEDED(hr) ? S_OK : E_FAIL;
}


STDMETHODIMP 
CDhcpComponentData::Save
(
	IStream *pStm, 
	BOOL	 fClearDirty
)
{
	HRESULT			hr = hrOK;
    CStringArray	strArrayIp;
    CStringArray	strArrayName;
    CDWordArray		dwArrayServerOptions;
    CDWordArray		dwArrayRefreshInterval;
	CDWordArray		dwArrayColumnInfo;
	CString			str;
    DWORD			dwFileVersion = DHCPSNAP_FILE_VERSION;
	CDhcpRootHandler * pRootHandler;
	SPITFSNodeEnum	spNodeEnum;
    SPITFSNode		spCurrentNode;
    ULONG			nNumReturned = 0;
    int             nNumServers = 0, nVisibleCount = 0;
    int				i, j, nCount = 0;
    CDhcpServer *   pServer;
    DWORD           dwFlags = 0;

    ASSERT(pStm);
    
    // set the mode for this stream
    XferStream xferStream(pStm, XferStream::MODE_WRITE);    

    // Write the version # of the file format
    CORg(xferStream.XferDWORD(DHCPSTRM_TAG_VERSION, &dwFileVersion));
	
    // Write the version # of the admin tool
    CORg(xferStream.XferLARGEINTEGER(DHCPSTRM_TAG_VERSIONADMIN, &gliDhcpsnapVersion));

	// write the root node name
    Assert(m_spRootNode);
	pRootHandler = GETHANDLER(CDhcpRootHandler, m_spRootNode);
	str = pRootHandler->GetDisplayName();

    CORg(xferStream.XferCString(DHCPSTRM_TAB_SNAPIN_NAME, &str));

	//
	// Build our array of servers
	//
	hr = m_spRootNode->GetChildCount(&nVisibleCount, &nNumServers);

    strArrayIp.SetSize(nNumServers);
    strArrayName.SetSize(nNumServers);
    dwArrayServerOptions.SetSize(nNumServers);
    dwArrayRefreshInterval.SetSize(nNumServers);
	dwArrayColumnInfo.SetSize(MAX_COLUMNS);

	//
	// loop and save off all the server's attributes
	//
    m_spRootNode->GetEnum(&spNodeEnum);

	spNodeEnum->Next(1, &spCurrentNode, &nNumReturned);
    while (nNumReturned)
	{
		pServer = GETHANDLER(CDhcpServer, spCurrentNode);

        // query the server for it's options:
        // auto refresh, bootp and classid visibility
        // NOTE: the audit logging state is also kept in here, but
        // it will get updated when the server node is enumerated
        dwArrayServerOptions[nCount] = pServer->GetServerOptions();
        pServer->GetAutoRefresh(NULL, &dwArrayRefreshInterval[nCount]);

		// put the information in our array
		strArrayIp[nCount] = pServer->GetIpAddress();
        strArrayName[nCount] = pServer->GetName();

        // go to the next node
        spCurrentNode.Release();
        spNodeEnum->Next(1, &spCurrentNode, &nNumReturned);

        nCount++;
	}

    // now write out all of the server information
    CORg(xferStream.XferCStringArray(DHCPSTRM_TAG_SERVER_IP, &strArrayIp));
    CORg(xferStream.XferCStringArray(DHCPSTRM_TAG_SERVER_NAME, &strArrayName));
    CORg(xferStream.XferDWORDArray(DHCPSTRM_TAG_SERVER_OPTIONS, &dwArrayServerOptions));
    CORg(xferStream.XferDWORDArray(DHCPSTRM_TAG_SERVER_REFRESH_INTERVAL, &dwArrayRefreshInterval));

	// now save the column information
	for (i = 0; i < NUM_SCOPE_ITEMS; i++)
	{
		CORg(xferStream.XferDWORDArray(DHCPSTRM_TAG_COLUMN_INFO, &dwArrayColumnInfo));

		for (j = 0; j < MAX_COLUMNS; j++)
		{
			dwArrayColumnInfo[j] = aColumnWidths[i][j];
		}
	}

	if (fClearDirty)
	{
		m_spRootNode->SetData(TFS_DATA_DIRTY, FALSE);
	}

    // save off taskpad states

    // root node taskpad state
    if (m_spTFSComponentData->GetTaskpadState(TASKPAD_ROOT_INDEX))
        dwFlags |= TASKPAD_ROOT_FLAG;

    // server node taskpad state
    if (m_spTFSComponentData->GetTaskpadState(TASKPAD_SERVER_INDEX))
        dwFlags |= TASKPAD_SERVER_FLAG;

    CORg(xferStream.XferDWORD(DHCPSTRM_TAG_SNAPIN_OPTIONS, &dwFlags));

Error:
    return SUCCEEDED(hr) ? S_OK : STG_E_CANTSAVE;
}


STDMETHODIMP 
CDhcpComponentData::GetSizeMax
(
	ULARGE_INTEGER *pcbSize
)
{
    ASSERT(pcbSize);

    // Set the size of the string to be saved
    ULISet32(*pcbSize, 10240);

    return S_OK;
}

STDMETHODIMP 
CDhcpComponentData::InitNew()
{
	return hrOK;
}

HRESULT 
CDhcpComponentData::FinalConstruct()
{
	HRESULT				hr = hrOK;
	
	hr = CComponentData::FinalConstruct();
	
	if (FHrSucceeded(hr))
	{
		m_spTFSComponentData->GetNodeMgr(&m_spNodeMgr);
	}
	return hr;
}

void 
CDhcpComponentData::FinalRelease()
{
	CComponentData::FinalRelease();
}