#include "pch.h"
#pragma hdrstop

#include "nsbase.h"
#include <nsres.h>
#include "ncmisc.h"
#include "foldres.h"
#include "foldinc.h"    // Standard shell\folder includes
#include "connlist.h"
#include "iconhandler.h"

template <class E> class ENUM_IDI_MAP
{
public:
    E   EnumEntry;
    int iIcon;
};

template <class E> int MapIconEnumToResourceID(const ENUM_IDI_MAP<E> IconEnumArray[], DWORD dwElems, const E EnumMatch)
{
    if (0 == EnumMatch)
    {
        return 0;
    }
    
    for (DWORD x = 0; x < dwElems; x++)
    {
        if (EnumMatch == IconEnumArray[x].EnumEntry)
        {
            return IconEnumArray[x].iIcon;
        }  
    }
    
    AssertSz(FALSE, "Could not map match to Icon enum array");
    return 0;
};

static const ENUM_IDI_MAP<ENUM_STAT_ICON> c_STATUS_ICONS[] = 
{
    ICO_STAT_FAULT,         IDI_CFI_STAT_FAULT,
    ICO_STAT_INVALID_IP,    IDI_CFI_STAT_QUESTION,
    ICO_STAT_EAPOL_FAILED,  IDI_CFI_STAT_QUESTION
};

static const ENUM_IDI_MAP<ENUM_CHARACTERISTICS_ICON> c_CHARACTERISTICS_ICON[] = 
{
    ICO_CHAR_INCOMING,      IDI_OVL_INCOMING,
    ICO_CHAR_DEFAULT,       IDI_OVL_DEFAULT,
    ICO_CHAR_FIREWALLED,    IDI_OVL_FIREWALLED,
    ICO_CHAR_SHARED,        IDI_OVL_SHARED,
};

static const ENUM_IDI_MAP<ENUM_CONNECTION_ICON> c_CONNECTION_ICONS[] = 
{
    ICO_CONN_BOTHOFF,       IDI_CFI_CONN_ALLOFF,
    ICO_CONN_RIGHTON,       IDI_CFI_CONN_RIGHTON,
    ICO_CONN_LEFTON,        IDI_CFI_CONN_LEFTON,
    ICO_CONN_BOTHON,        IDI_CFI_CONN_BOTHON,
};

struct NC_MEDIATYPE_ICON
{
    DWORD               ncm;  // NETCON_MEDIATYPE (Shifted left by SHIFT_NETCON_MEDIATYPE)
    DWORD               ncsm; // NETCON_SUBMEDIATYPE (Shifted left by SHIFT_NETCON_SUBMEDIATYPE)
    DWORD               dwMasksSupported;
    INT                 iIcon;
    INT                 iIconDisabled; // Only for dwMasksSupported == MASK_NO_CONNECTIONOVERLAY
};

static const NC_MEDIATYPE_ICON c_NCM_ICONS[] = 
{
//    NETCON_MEDIATYPE (Shifted left by SHIFT_NETCON_MEDIATYPE)
//      |                                              NETCON_SUBMEDIATYPE (Shifted left by SHIFT_NETCON_SUBMEDIATYPE (0) )
//      |                                                       |            dwMasksSupported
//      |                                                       |                  |                       iIcon                 
//      |                                                       |                  |                          |                    Disabled Icon 
//      |                                                       |                  |                          |                        | (for MASK_NO_CONNECTIONOVERLAY)
//      v                                                       v                  v                          v                        v 
    NCM_NONE                 << SHIFT_NETCON_MEDIATYPE, NCSM_NONE,    MASK_NO_CONNECTIONOVERLAY,    IDI_CFI_RASSERVER,        IDI_CFI_RASSERVER,
    NCM_BRIDGE               << SHIFT_NETCON_MEDIATYPE, NCSM_NONE,    MASK_STATUSOVERLAY,           IDI_CFI_BRIDGE_CONNECTED, IDI_CFI_BRIDGE_DISCONNECTED,
    NCM_SHAREDACCESSHOST_LAN << SHIFT_NETCON_MEDIATYPE, NCSM_NONE,    MASK_NO_CONNECTIONOVERLAY,    IDI_CFI_SAH_LAN,          IDI_CFI_SAH_LAN,   
    NCM_SHAREDACCESSHOST_RAS << SHIFT_NETCON_MEDIATYPE, NCSM_NONE,    MASK_NO_CONNECTIONOVERLAY,    IDI_CFI_SAH_RAS,          IDI_CFI_SAH_RAS,   
    NCM_DIRECT               << SHIFT_NETCON_MEDIATYPE, NCSM_NONE,    MASK_SUPPORT_ALL,             IDI_CFI_DIRECT,           0,
    NCM_DIRECT               << SHIFT_NETCON_MEDIATYPE, NCSM_DIRECT,  MASK_SUPPORT_ALL,             IDI_CFI_DIRECT,           0,
    NCM_DIRECT               << SHIFT_NETCON_MEDIATYPE, NCSM_IRDA,    MASK_SUPPORT_ALL,             IDI_CFI_DIRECT,           0,
    NCM_ISDN                 << SHIFT_NETCON_MEDIATYPE, NCSM_NONE,    MASK_SUPPORT_ALL,             IDI_CFI_ISDN,             0,
    NCM_LAN                  << SHIFT_NETCON_MEDIATYPE, NCSM_1394,    MASK_SUPPORT_ALL,             IDI_CFI_LAN,              0,
    NCM_LAN                  << SHIFT_NETCON_MEDIATYPE, NCSM_ATM,     MASK_SUPPORT_ALL,             IDI_CFI_LAN,              0,
    NCM_LAN                  << SHIFT_NETCON_MEDIATYPE, NCSM_ELAN,    MASK_SUPPORT_ALL,             IDI_CFI_LAN,              0,
    NCM_LAN                  << SHIFT_NETCON_MEDIATYPE, NCSM_LAN,     MASK_SUPPORT_ALL,             IDI_CFI_LAN,              0,
    NCM_LAN                  << SHIFT_NETCON_MEDIATYPE, NCSM_WIRELESS,MASK_SUPPORT_ALL,             IDI_CFI_WIRELESS,         0,
    NCM_PPPOE                << SHIFT_NETCON_MEDIATYPE, NCSM_NONE,    MASK_SUPPORT_ALL,             IDI_CFI_PPPOE,            0,
    NCM_PHONE                << SHIFT_NETCON_MEDIATYPE, NCSM_NONE,    MASK_SUPPORT_ALL,             IDI_CFI_PHONE,            0,
    NCM_PHONE                << SHIFT_NETCON_MEDIATYPE, NCSM_CM,      MASK_SUPPORT_ALL,             IDI_CFI_CM,               0,
    NCM_TUNNEL               << SHIFT_NETCON_MEDIATYPE, NCSM_NONE,    MASK_SUPPORT_ALL,             IDI_CFI_VPN,              0,
    NCM_TUNNEL               << SHIFT_NETCON_MEDIATYPE, NCSM_CM,      MASK_SUPPORT_ALL,             IDI_CFI_CM,               0,
};

struct NC_STATUS_ICON
{
    NETCON_STATUS        ncs;
    DWORD                dwStatIcon;
    ENUM_CONNECTION_ICON enumConnectionIcon;
};

static const NC_STATUS_ICON c_NCS_ICONS[] = 
{
//   NETCON_STATUS
//        |                         dwStatIcon
//        |                           |                                  enumConnectionIcon
//        |                           |                                      |
//        v                           v                                      v
    NCS_AUTHENTICATING,           ICO_STAT_NONE,                           ICO_CONN_BOTHON,
    NCS_AUTHENTICATION_SUCCEEDED, ICO_STAT_NONE,                           ICO_CONN_BOTHON,
    NCS_AUTHENTICATION_FAILED,    ICO_STAT_EAPOL_FAILED,                   ICO_CONN_BOTHON,
    NCS_CREDENTIALS_REQUIRED,     ICO_STAT_EAPOL_FAILED,                   ICO_CONN_BOTHON,
    NCS_CONNECTED,                ICO_STAT_NONE,                           ICO_CONN_BOTHON,
    NCS_DISCONNECTING,            ICO_STAT_NONE,                           ICO_CONN_BOTHON,
    NCS_CONNECTING,               ICO_STAT_DISABLED | ICO_STAT_NONE,       ICO_CONN_BOTHOFF,
    NCS_DISCONNECTED,             ICO_STAT_DISABLED | ICO_STAT_NONE,       ICO_CONN_BOTHOFF,
    NCS_INVALID_ADDRESS,          ICO_STAT_INVALID_IP,                     ICO_CONN_BOTHON,
    NCS_HARDWARE_DISABLED,        ICO_STAT_FAULT,                          ICO_CONN_BOTHON,
    NCS_HARDWARE_MALFUNCTION,     ICO_STAT_FAULT,                          ICO_CONN_BOTHON,
    NCS_HARDWARE_NOT_PRESENT,     ICO_STAT_FAULT,                          ICO_CONN_BOTHON,
    NCS_MEDIA_DISCONNECTED,       ICO_STAT_FAULT,                          ICO_CONN_BOTHON,
};

//+---------------------------------------------------------------------------
//
//  Function:   CNetConfigIcons::CNetConfigIcons
//
//  Purpose:    CNetConfigIcons constructor
//
//  Arguments:
//      none
//
//  Returns:
//      none
//
//  Author:     deonb    18 Feb 2001
//
//  Notes:  
//
CNetConfigIcons::CNetConfigIcons(IN HINSTANCE hInstance) : m_hInstance(hInstance)
{
    TraceFileFunc(ttidIcons);

    dwLastBrandedId = 0;
    InitializeCriticalSection(&csNetConfigIcons);
}

//+---------------------------------------------------------------------------
//
//  Function:   CNetConfigIcons::~CNetConfigIcons
//
//  Purpose:    CNetConfigIcons destructor
//
//  Arguments:
//      none
//
//  Returns:
//      none
//
//  Author:     deonb    18 Feb 2001
//
//  Notes:  
//
CNetConfigIcons::~CNetConfigIcons()
{
    // Can't trace in this function!

    IMAGELISTMAP::iterator iter;
    
    for (iter = m_ImageLists.begin(); iter != m_ImageLists.end(); iter++)
    {
        HIMAGELIST hImageLst = iter->second;
        ImageList_Destroy(hImageLst);
    }

    m_ImageLists.clear();
    DeleteCriticalSection(&csNetConfigIcons);
}

//+---------------------------------------------------------------------------
//
//  Function:   CNetConfigIcons::HrMergeTwoIcons
//
//  Purpose:    Merge a new icon unto an existing one
//
//  Arguments:
//      dwIconSize     [in]     Size of the icon
//      phMergedIcon   [in out] Icon 1 to merge, and contains the merged
//                              icon on output
//      hIconToMerge   [in]     Icon 2 to merge with
//
//  Returns:
//      HRESULT
//
//  Author:     deonb    4 Apr 2001
//
//  Notes:
//
HRESULT CNetConfigIcons::HrMergeTwoIcons(IN DWORD dwIconSize, IN OUT HICON *phMergedIcon, IN HICON hIconToMergeWith)
{
    HRESULT hr = S_FALSE;
    Assert(phMergedIcon);

    HIMAGELIST hImageLst = NULL;

    IMAGELISTMAP::iterator i = m_ImageLists.find(dwIconSize);
    if (i == m_ImageLists.end())
    {
        hImageLst = ImageList_Create(dwIconSize, dwIconSize, ILC_COLOR32 | ILC_MASK, 2, 0);
        if (hImageLst)
        {
            m_ImageLists[dwIconSize] = hImageLst;
        }
        else
        {
            hr = E_FAIL;
        }             
    }
    else
    {
        hImageLst = i->second;
    }

    if (SUCCEEDED(hr))
    {
        if (*phMergedIcon)
        {
            if (hIconToMergeWith)
            {
                hr = E_FAIL;

                // Merge the 2 icons;
                if (ImageList_RemoveAll(hImageLst))
                {
                    int iIcon1 = ImageList_AddIcon(hImageLst, *phMergedIcon);
                    if (-1 != iIcon1)
                    {
                        int iIcon2 = ImageList_AddIcon(hImageLst, hIconToMergeWith);
                        if (-1 != iIcon2)
                        {
                            if (ImageList_SetOverlayImage(hImageLst, iIcon2, 1))
                            {
                                DestroyIcon(*phMergedIcon); // Delete the current icon

                                *phMergedIcon = ImageList_GetIcon(hImageLst, iIcon1, INDEXTOOVERLAYMASK(1));
                                hr = S_OK;
                            }
                        }
                    }
                }
            }
            // else Nothing. Stays the same.
        }
        else
        {
            // Copy icon 2 to icon 1
            *phMergedIcon = CopyIcon(hIconToMergeWith);
        }
    }

    return hr;
};

//+---------------------------------------------------------------------------
//
//  Function:   CNetConfigIcons::HrGetInternalIconIDForPIDL
//
//  Purpose:    Map the connection state and connection type to the
//              appropriate icon resource IDs.
//
//  Arguments:
//      uFlags     [in]    The GIL_xxx shell flags
//      cfe        [in]    The connection folder entry
//      dwIcon     [out]   The ID of the icon
//
//  Returns:
//      HRESULT
//
//  Author:     deonb    18 Feb 2001
//
//  Notes:
//
HRESULT CNetConfigIcons::HrGetInternalIconIDForPIDL(IN UINT uFlags, IN const CConFoldEntry& cfe, OUT DWORD& dwIcon)
{
    TraceFileFunc(ttidIcons);

    if (cfe.GetCharacteristics() & NCCF_BRANDED)
    {
        AssertSz(FALSE, "Call HrGetBrandedIconIDForPIDL instead for branded icons");
        return E_INVALIDARG;
    }

    Assert(!cfe.empty());

    BOOL fValidIcon = FALSE;
    if (cfe.GetWizard() == WIZARD_MNC)
    {
        dwIcon = ICO_MGR_RESOURCEID | IDI_CONFOLD_WIZARD;
        fValidIcon = TRUE;
    }
    else if (cfe.GetWizard() == WIZARD_HNW)
    {
        dwIcon = ICO_MGR_RESOURCEID | IDI_CONFOLD_HOMENET_WIZARD;
        fValidIcon = TRUE;
    }
    else
    {
        dwIcon = ICO_MGR_INTERNAL;

        Assert(cfe.GetWizard() == WIZARD_NOT_WIZARD);

        const NETCON_SUBMEDIATYPE ncsm = cfe.GetNetConSubMediaType();
        const NETCON_MEDIATYPE    ncm  = cfe.GetNetConMediaType();
        const NETCON_STATUS       ncs  = cfe.GetNetConStatus();
        
        // Find the Status part of the icon
        for (DWORD dwLoop = 0; (dwLoop < celems(c_NCM_ICONS)); dwLoop++)
        {
            const NC_STATUS_ICON& ncsIcon = c_NCS_ICONS[dwLoop];

            if (ncs == ncsIcon.ncs)
            {
                Assert((ncsIcon.dwStatIcon         & (MASK_STATUS | MASK_STATUS_DISABLED) ) == ncsIcon.dwStatIcon);
                Assert((ncsIcon.enumConnectionIcon & (MASK_CONNECTION) ) == ncsIcon.enumConnectionIcon);

                dwIcon |= ncsIcon.dwStatIcon;
                dwIcon |= ncsIcon.enumConnectionIcon;
                dwIcon |= ncm  << SHIFT_NETCON_MEDIATYPE;
                dwIcon |= ncsm << SHIFT_NETCON_SUBMEDIATYPE;
                fValidIcon = TRUE;
                
                break;
            }
        }
    }

    AssertSz(fValidIcon, "Could not obtain an icon for this connection");

    if (fValidIcon)
    {
        return S_OK;
    }
    else
    {
        return E_FAIL;
    }
}

//+---------------------------------------------------------------------------
//
//  Function:   CNetConfigIcons::HrMergeCharacteristicsIcons
//
//  Purpose:    Merge the characteristics icons unto an input icon
//
//  Arguments:
//      dwIconSize     [in]     Size of the icon
//      dwIconId       [in]     Icon ID (to read Characteristics info from)
//      phMergedIcon   [in out] The icon to merge with, and contains the merged
//                              icon on output
//
//  Returns:
//      HRESULT
//
//  Author:     deonb    4 Apr 2001
//
//  Notes:
//
HRESULT CNetConfigIcons::HrMergeCharacteristicsIcons(IN DWORD dwIconSize, IN DWORD dwIconId, IN OUT HICON *phMergedIcon)
{
    HRESULT hr = S_OK;

    Assert(phMergedIcon);

    if (!(dwIconId & MASK_CHARACTERISTICS))
    {
        return S_FALSE;
    }

    // Characteristics
    int iFireWalled   = MapIconEnumToResourceID(c_CHARACTERISTICS_ICON, celems(c_CHARACTERISTICS_ICON), static_cast<ENUM_CHARACTERISTICS_ICON>(dwIconId & ICO_CHAR_FIREWALLED));
    int iIncoming     = MapIconEnumToResourceID(c_CHARACTERISTICS_ICON, celems(c_CHARACTERISTICS_ICON), static_cast<ENUM_CHARACTERISTICS_ICON>(dwIconId & ICO_CHAR_INCOMING));
    int iShared       = MapIconEnumToResourceID(c_CHARACTERISTICS_ICON, celems(c_CHARACTERISTICS_ICON), static_cast<ENUM_CHARACTERISTICS_ICON>(dwIconId & ICO_CHAR_SHARED));
    int iDefault      = MapIconEnumToResourceID(c_CHARACTERISTICS_ICON, celems(c_CHARACTERISTICS_ICON), static_cast<ENUM_CHARACTERISTICS_ICON>(dwIconId & ICO_CHAR_DEFAULT));

    HICON hFireWalled = iFireWalled ? LoadIconSize(m_hInstance, MAKEINTRESOURCE(iFireWalled), dwIconSize) : NULL;
    HICON hShared     = iShared     ? LoadIconSize(m_hInstance, MAKEINTRESOURCE(iShared),     dwIconSize) : NULL;
    HICON hDefault    = iDefault    ? LoadIconSize(m_hInstance, MAKEINTRESOURCE(iDefault),    dwIconSize) : NULL;
    HICON hIncoming   = NULL;
    
    if (dwIconSize != GetSystemMetrics(SM_CXSMICON)) // Shouldn't display in 16x16
    {
        hIncoming = iIncoming ? LoadIconSize(m_hInstance, MAKEINTRESOURCE(iIncoming), dwIconSize) : NULL;
        AssertSz(FImplies(iIncoming, hIncoming),     "Could not load the Incoming Icon");
    }

    AssertSz(FImplies(iFireWalled, hFireWalled), "Could not load the FireWalled Icon");
    AssertSz(FImplies(iShared, hShared),         "Could not load the Shared Icon");
    AssertSz(FImplies(iDefault, hDefault),       "Could not load the Default Icon");

    HICON hIconArray[] = {hFireWalled, hIncoming, hShared, hDefault};

    for (int x = 0; x < celems(hIconArray); x++)
    {
        hr = HrMergeTwoIcons(dwIconSize, phMergedIcon, hIconArray[x]);
        if (FAILED(hr))
        {
            break;
        }
    }

    for (int x = 0; x < celems(hIconArray); x++)
    {
        if (hIconArray[x])
        {
            DestroyIcon(hIconArray[x]);
            hIconArray[x] = NULL;
        }
    }

    AssertSz(SUCCEEDED(hr) && *phMergedIcon, "Could not load a characteristics icon");

    return hr;
}

//+---------------------------------------------------------------------------
//
//  Function:   CNetConfigIcons::HrGetInternalIconFromIconId
//
//  Purpose:    Loads the netshell internal icon given the icon ID 
//               (from HrGetInternalIconIDForPIDL)
//
//  Arguments:
//      dwIconSize [in] Size of the icon required
//      dwIconId   [in] Icon ID - from HrGetInternalIconIDForPIDL
//      hIcon      [in] The icon that was loaded
//
//  Returns:
//      HRESULT
//
//  Author:     deonb    18 Feb 2001
//
//  Notes:
//
HRESULT CNetConfigIcons::HrGetInternalIconFromIconId(IN DWORD dwIconSize, IN DWORD dwIconId, OUT HICON &hIcon)
{
    TraceFileFunc(ttidIcons);

    DWORD dwlrFlags = 0;

    if ( (dwIconId & MASK_ICONMANAGER) != ICO_MGR_INTERNAL)
    {
        AssertSz(FALSE, "This is not an internal icon");
        return E_INVALIDARG;
    }

    HRESULT hr = E_FAIL;

    DWORD ncm  = (dwIconId & MASK_NETCON_MEDIATYPE);
    DWORD ncsm = (dwIconId & MASK_NETCON_SUBMEDIATYPE);

    BOOL fDisabledStatus = (dwIconId & ICO_STAT_DISABLED);

    // Status & Connection
    int iStatus       = MapIconEnumToResourceID(c_STATUS_ICONS,     celems(c_STATUS_ICONS),     static_cast<ENUM_STAT_ICON>(dwIconId & MASK_STATUS));
    int iConnection   = MapIconEnumToResourceID(c_CONNECTION_ICONS, celems(c_CONNECTION_ICONS), static_cast<ENUM_CONNECTION_ICON>(dwIconId & MASK_CONNECTION));

    int iMediaType          = 0;

    // Media Type
    for (int x = 0; x < celems(c_NCM_ICONS); x++)
    {
        const NC_MEDIATYPE_ICON& ncmIcon = c_NCM_ICONS[x];

        // Use NCSM if available, otherwise use NCM
        if ( ((NCSM_NONE == ncsm) && (NCSM_NONE == ncmIcon.ncsm) && (ncm == ncmIcon.ncm)) ||
             ((NCSM_NONE != ncsm) && (ncsm == ncmIcon.ncsm)) )
        {
            if (!(ncmIcon.dwMasksSupported & MASK_CONNECTION))
            {
                iConnection    = 0;
            }

            if (!(ncmIcon.dwMasksSupported & MASK_STATUS))
            {
                iStatus        = 0;
            }
            
            iMediaType = ncmIcon.iIcon;

            if (!(iConnection || iStatus) && 
                 (fDisabledStatus))
            {
                Assert(ncmIcon.iIconDisabled);
                iMediaType = ncmIcon.iIconDisabled;
            }
        }
    }

    Assert(iMediaType);
    if (iMediaType)
    {
        HICON hMediaType  = iMediaType  ? LoadIconSize(m_hInstance, MAKEINTRESOURCE(iMediaType), dwIconSize)  : NULL;
        HICON hStatus     = iStatus     ? LoadIconSize(m_hInstance, MAKEINTRESOURCE(iStatus),    dwIconSize)  : NULL;
        HICON hConnection = NULL;

        if (dwIconSize != GetSystemMetrics(SM_CXSMICON)) // Shouldn't display in 16x16
        {
            hConnection = iConnection ? LoadIconSize(m_hInstance, MAKEINTRESOURCE(iConnection),  dwIconSize)  : NULL;
            AssertSz(FImplies(iConnection, hConnection), "Could not load the Connection Icon");
        }

        AssertSz(FImplies(iMediaType, hMediaType),   "Could not load the Media Type Icon");
        AssertSz(FImplies(iStatus, hStatus),         "Could not load the Status Icon");

        HICON hIconArray[] = {hMediaType, hStatus, hConnection};
        hIcon = NULL;

        for (int x = 0; x < celems(hIconArray); x++)
        {
            hr = HrMergeTwoIcons(dwIconSize, &hIcon, hIconArray[x]);
            if (FAILED(hr))
            {
                break;
            }
        }

        for (int x = 0; x < celems(hIconArray); x++)
        {
            if (hIconArray[x])
            {
                DestroyIcon(hIconArray[x]);
                hIconArray[x] = NULL;
            }
        }

        if (SUCCEEDED(hr))
        {
            hr = HrMergeCharacteristicsIcons(dwIconSize, dwIconId, &hIcon);
            if (SUCCEEDED(hr))
            {
                hr = S_OK;
            }

        }
    }

    AssertSz(SUCCEEDED(hr) && hIcon, "Could not load any icon");

    return hr;
}


//+---------------------------------------------------------------------------
//
//  Function:   CNetConfigIcons::HrGetResourceIconFromIconId
//
//  Purpose:    Loads a resource icon given the icon ID 
//               (from HrGetInternalIconIDForPIDL)
//
//  Arguments:
//      dwIconSize [in] Size of the icon required
//      dwIconId   [in] Icon ID - from HrGetInternalIconIDForPIDL
//      hIcon      [in] The icon that was loaded
//
//  Returns:
//      HRESULT
//
//  Author:     deonb    18 Feb 2001
//
//  Notes:
//
HRESULT CNetConfigIcons::HrGetResourceIconFromIconId(IN DWORD dwIconSize, IN DWORD dwIconId, OUT HICON &hIcon)
{
    TraceFileFunc(ttidIcons);

    DWORD dwlrFlags = 0;

    if ( (dwIconId & MASK_ICONMANAGER) != ICO_MGR_RESOURCEID)
    {
        AssertSz(FALSE, "This is not a resource id icon manager icon");
        return E_INVALIDARG;
    }

    HRESULT hr = S_OK;

    int iIcon = dwIconId & MASK_BRANDORRESOURCEID; // Clear the rest of the bits;

    hIcon = LoadIconSize(m_hInstance, MAKEINTRESOURCE(iIcon), dwIconSize);
    if (!hIcon)
    {
        hr = HRESULT_FROM_WIN32(GetLastError());
    }
    else
    {
        hr = HrMergeCharacteristicsIcons(dwIconSize, dwIconId, &hIcon);
        if (SUCCEEDED(hr))
        {
            hr = S_OK;
        }
    }

    TraceHr(ttidError, FAL, hr, FALSE, "Could not load icon %d (size %d x %d) from resource file", iIcon, dwIconSize, dwIconSize);

    return hr;
}

//+---------------------------------------------------------------------------
//
//  Function:   CNetConfigIcons::HrGetBrandedIconIDForPIDL
//
//  Purpose:    Initializes the branded icon info from a file
//
//  Arguments:
//      uFlags     [in]    The GIL_xxx shell flags
//      cfe        [in]    The connection folder entry
//      dwIcon     [out]   The ID of the icon
//
//  Returns:
//      HRESULT
//
//  Author:     deonb    18 Feb 2001
//
//  Notes: We store this internally into a map - hence we can't cache
//         branded icons since we might not end up with the same id in the map
//
HRESULT CNetConfigIcons::HrGetBrandedIconIDForPIDL(IN UINT uFlags, IN const CConFoldEntry& cfe, OUT DWORD& dwIcon)
{
    TraceFileFunc(ttidIcons);

    HRESULT hr = S_OK;

    if (!(cfe.GetCharacteristics() & NCCF_BRANDED))
    {
        AssertSz(FALSE, "Call HrGetInternalIconIDForPIDL instead for non-branded icons");
        return E_INVALIDARG;
    }

    Assert(!cfe.empty());

    if (cfe.GetWizard() != WIZARD_NOT_WIZARD)
    {
        AssertSz(FALSE, "You're not allowed to brand the wizard");
        hr = E_INVALIDARG;
    }
    else
    {
        dwIcon = ICO_MGR_CM;

        if (g_ccl.IsInitialized() == FALSE)
        {
            g_ccl.HrRefreshConManEntries();
        }
        
        ConnListEntry  cle;
        hr = g_ccl.HrFindConnectionByGuid(&(cfe.GetGuidID()), cle);
        if (S_OK == hr)
        {
            tstring szBrandedFileName;
            BOOL bBrandedName = FALSE;
            
            if (cle.pcbi)
            {
                if (cle.pcbi->szwLargeIconPath)
                {
                    szBrandedFileName = cle.pcbi->szwLargeIconPath;
                    bBrandedName = TRUE;
                }
                else if (cle.pcbi->szwSmallIconPath)
                {
                    szBrandedFileName = cle.pcbi->szwSmallIconPath;
                    bBrandedName = TRUE;
                }
            }

            if (bBrandedName)
            {
                BrandedNames::const_iterator i = m_BrandedNames.find(szBrandedFileName);
                if (i == m_BrandedNames.end()) // Doesn't exist yet
                {
                    dwLastBrandedId++;
                    m_BrandedNames[szBrandedFileName] = dwLastBrandedId;
                    dwIcon |= dwLastBrandedId;
                }
                else
                {
                    dwIcon |= i->second;
                }
            }
            else
            {
                CConFoldEntry cfeTmp;
                cfeTmp = cfe;
                cfeTmp.SetCharacteristics(cfe.GetCharacteristics() & ~NCCF_BRANDED);
                cfeTmp.SetNetConSubMediaType(NCSM_CM);
                dwIcon = 0;
                hr = HrGetInternalIconIDForPIDL(uFlags, cfeTmp, dwIcon);
            }
        }
        else
        {
            hr = E_FILE_NOT_FOUND;
        }
    }

    TraceHr(ttidError, FAL, hr, FALSE, "Could not obtain an icon for this connection");

    return hr;
}

//+---------------------------------------------------------------------------
//
//  Function:   CNetConfigIcons::HrGetBrandedIconFromIconId
//
//  Purpose:    Loads the branded icon given the icon ID 
//               (from HrGetBrandedIconIDForPIDL)
//
//  Arguments:
//      dwIconSize [in] Size of the icon required
//      dwIconId   [in] Icon ID - from HrGetBrandedIconIDForPIDL
//      hIcon      [in] The icon that was loaded
//
//  Returns:
//      HRESULT
//
//  Author:     deonb    18 Feb 2001
//
//  Notes:
//
HRESULT CNetConfigIcons::HrGetBrandedIconFromIconId(IN DWORD dwIconSize, IN DWORD dwIconId, OUT HICON &hIcon)
{
    TraceFileFunc(ttidIcons);

    if ( (dwIconId & MASK_ICONMANAGER) != ICO_MGR_CM)
    {
        AssertSz(FALSE, "This is not a branded icon");
        return E_INVALIDARG;
    }

    HRESULT hr = S_OK;
    
    DWORD dwIconIdTmp;
    dwIconIdTmp = dwIconId & MASK_BRANDORRESOURCEID;

    Assert(dwIconIdTmp);

    if (dwIconIdTmp)
    {
        BOOL bFound = FALSE;
        tstring szBrandedFileName;
        for (BrandedNames::iterator i = m_BrandedNames.begin(); i != m_BrandedNames.end(); i++)
        {
            if (i->second == dwIconIdTmp)
            {
#ifdef DBG
                if (bFound)
                {
                    AssertSz(FALSE, "Multiple icon IDs in branded table found");
                }
#endif
                bFound = TRUE;
                szBrandedFileName = i->first;
                break;
            }
        }

        if (!bFound)
        {
            AssertSz(FALSE, "Branded icon id not found in branded table");
            return E_FAIL;
        }

        hIcon = static_cast<HICON>(LoadImage(
            NULL,
            szBrandedFileName.c_str(),
            IMAGE_ICON,
            dwIconSize, dwIconSize,
            LR_LOADFROMFILE));
    }

    if (!hIcon)
    {
        hr = HRESULT_FROM_WIN32(GetLastError());
    }
    else
    {
        hr = HrMergeCharacteristicsIcons(dwIconSize, dwIconId, &hIcon);
        if (SUCCEEDED(hr))
        {
            hr = S_OK;
        }

    }
    
    TraceHr(ttidError, FAL, hr, FALSE, "CNetConfigIcons::HrGetBrandedIconFromIconId");
    return hr;
}

//+---------------------------------------------------------------------------
//
//  Function:   CNetConfigIcons::HrGetIconIDForPIDL
//
//  Purpose:    Get a unique icon number given a Connection Folder Entry
//
//  Arguments:
//      uFlags     [in]    The GIL_xxx shell flags
//      cfe        [in]   The connection folder entry
//      dwIcon     [out]  The ID of the icon
//      pfCanCache [out]  Whether we can cache the icon
//
//  Returns:
//      HRESULT
//
//  Author:     deonb    18 Feb 2001
//
//  Notes:
//
HRESULT CNetConfigIcons::HrGetIconIDForPIDL(IN UINT uFlags, IN const CConFoldEntry& cfe, OUT DWORD& dwIconId, OUT LPBOOL pfCanCache)
{
    TraceFileFunc(ttidIcons);

    CExceptionSafeLock EsLock(&csNetConfigIcons);

    HRESULT hr = S_OK;
    if (cfe.GetCharacteristics() & NCCF_BRANDED)
    {
        *pfCanCache = FALSE;
        hr = HrGetBrandedIconIDForPIDL(uFlags, cfe, dwIconId);
    }
    else
    {
#ifdef DBG
        if (FIsDebugFlagSet(dfidDontCacheShellIcons))
        {
            *pfCanCache = FALSE;
        }
        else
        {
            *pfCanCache = TRUE;
        }
#else
        *pfCanCache = TRUE;
#endif
        hr = HrGetInternalIconIDForPIDL(uFlags, cfe, dwIconId);
    }

    if (FAILED(hr))
    {
        return hr;
    }

    Assert( (dwIconId & ~MASK_CHARACTERISTICS) == dwIconId); // Make sure we did't overflow into the overlay

    if (!(GIL_FORSHORTCUT & uFlags))
    {
        DWORD dwOverlay = 0;
        if ( (cfe.GetCharacteristics() & NCCF_INCOMING_ONLY) &&
             (cfe.GetNetConMediaType() != NCM_NONE) ) // No overlay for "default" incoming connection
        {
            dwIconId |= ICO_CHAR_INCOMING;
        }

        if (cfe.GetCharacteristics() & NCCF_SHARED)
        {
            dwIconId |= ICO_CHAR_SHARED;
        }
    
        if (cfe.GetCharacteristics() & NCCF_FIREWALLED)
        {
            dwIconId |= ICO_CHAR_FIREWALLED;
        }

        if (cfe.GetCharacteristics() & NCCF_DEFAULT)
        {
            dwIconId |= ICO_CHAR_DEFAULT;
        }
    }

    return hr;
}

//+---------------------------------------------------------------------------
//
//  Function:   CNetConfigIcons::HrGetIconFromIconId
//
//  Purpose:    Loads an icon given the icon ID (branded or internal)
//
//  Arguments:
//      dwIconSize [in] Size of the icon required
//      dwIconId   [in] Icon ID - from HrGetIconIDForPIDL
//      hIcon      [in] The icon that was loaded
//
//  Returns:
//
//  Author:     deonb    18 Feb 2001
//
//  Notes:
//
HRESULT CNetConfigIcons::HrGetIconFromIconId(IN DWORD dwIconSize, IN DWORD dwIconId, OUT HICON &hIcon)
{ 
    TraceFileFunc(ttidIcons);

    CExceptionSafeLock EsLock(&csNetConfigIcons);

    HRESULT hr = S_OK;
    switch (dwIconId & MASK_ICONMANAGER)
    {
        case ICO_MGR_CM:
            hr = HrGetBrandedIconFromIconId(dwIconSize, dwIconId, hIcon);
            break;

        case ICO_MGR_INTERNAL:
            hr = HrGetInternalIconFromIconId(dwIconSize, dwIconId, hIcon);
            break;

        case ICO_MGR_RESOURCEID:
            hr = HrGetResourceIconFromIconId(dwIconSize, dwIconId, hIcon);
            break;

        default:
            hr = E_INVALIDARG;
            AssertSz(FALSE, "Unknown Icon manager");
            break;
    }

    if (SUCCEEDED(hr))
    {
        DWORD dwOverlays = (dwIconId & MASK_CHARACTERISTICS); // get the mask bits
    }
    return hr;
}

//+---------------------------------------------------------------------------
//
//  Function:   CNetConfigIcons::HrGetIconFromIconId
//
//  Purpose:    Loads an icon given the icon ID (branded or internal)
//
//  Arguments:
//      dwIconSize        [in] Size of the icon required
//      ncm               [in] The NETCON_MEDIATYPE
//      ncsm              [in] The NETCON_SUBMEDIATYPE
//      dwConnectionIcon  [in] ENUM_CONNECTION_ICON (Not shifted (IOW: 0 or 4,5,6,7)
//      dwCharacteristics [in] The NCCF_CHARACTERISTICS flag (0 allowed)
//      phIcon            [in] The resulting icon. Destroy using DestroyIcon
//
//  Returns:
//
//  Author:     deonb    23 Apr 2001
//
//  Notes:
//
HRESULT CNetConfigIcons::HrGetIconFromMediaType(DWORD dwIconSize, IN NETCON_MEDIATYPE ncm, IN NETCON_SUBMEDIATYPE ncsm, IN DWORD dwConnectionIcon, IN DWORD dwCharacteristics, OUT HICON *phIcon)
{
    HRESULT hr = S_OK;

    CConFoldEntry cfe;

    // Is this a request for a special folder icon?
    if ( (0xFFFFFFFF == dwCharacteristics)  &&
         (NCM_NONE == ncm) &&
         (NCSM_NONE == ncsm)
        )
    {
        BOOL bFoundIcon = FALSE;
        int iIcon = 0;

        switch (dwConnectionIcon)
        {
            case 0x80000000:
                iIcon = IDI_CONNECTIONS_FOLDER_LARGE2;
                bFoundIcon = TRUE;
                break;

            case 0x80000001:
                iIcon = IDI_CONFOLD_WIZARD;
                bFoundIcon = TRUE;
                break;

            case 0x80000002:
                iIcon = IDI_CONFOLD_HOMENET_WIZARD;
                bFoundIcon = TRUE;
                break;
        }

        if (bFoundIcon)
        {
            *phIcon = LoadIconSize(_Module.GetResourceInstance(), MAKEINTRESOURCE(iIcon), dwIconSize);
            if (*phIcon)
            {
                return S_OK;
            }
            else
            {
                return HrFromLastWin32Error();
            }
        }
    }

    // No? Then load a media type icon
    NETCON_STATUS ncs;
    if (ICO_CONN_BOTHOFF == dwConnectionIcon)
    {
        ncs = NCS_DISCONNECTED;
    }
    else
    {
        ncs = NCS_CONNECTED;
    }

    // Most of these values (except for ncm, ncsm, ncs) are totally fake. 
    // However, we need to initialize this structure with 
    // something or it will assert on us.
    //
    // HrGetIconIDForPidl will only use ncm, ncsm, ncs & dwCharacteristics
    hr = cfe.HrInitData(WIZARD_NOT_WIZARD,
                        ncm,
                        ncsm,
                        ncs,
                        &(CLSID_ConnectionCommonUi), // FAKE
                        &(CLSID_ConnectionCommonUi), // FAKE
                        dwCharacteristics,
                        reinterpret_cast<LPBYTE>("PersistData"), // FAKE
                        celems("PersistData"),      // FAKE
                        L"Name",                    // FAKE
                        L"DeviceName",              // FAKE
                        L"PhoneOrHostAddress");     // FAKE
    if (SUCCEEDED(hr))
    {
        DWORD dwIconId;
        BOOL  fCanCache;
        hr = HrGetIconIDForPIDL(0, cfe, dwIconId, &fCanCache);
        if (SUCCEEDED(hr))
        {
            dwIconId &= ~MASK_CONNECTION; // Clear the current connection mask
            dwIconId |= (dwConnectionIcon << SHIFT_CONNECTION); // Set the new connection mask

            hr = HrGetIconFromIconId(dwIconSize, dwIconId, *phIcon);
        }
    }

    return hr;
}

//+---------------------------------------------------------------------------
//
//  Function:   CNetConfigIcons::HrUpdateSystemImageListForPIDL
//
//  Purpose:    Notifies the shell that we've changed an icon
//
//  Arguments:
//      cfe [in] The connection folder entry that changed
//
//  Returns:
//      HRESULT
//
//  Author:     deonb    18 Feb 2001
//
//  Notes:
//
HRESULT CNetConfigIcons::HrUpdateSystemImageListForPIDL(IN const CConFoldEntry& cfe)
{
    TraceFileFunc(ttidIcons);

    HRESULT hr = S_OK;
    DWORD dwIcon;
    BOOL  fCacheThisIcon;
    hr = g_pNetConfigIcons->HrGetIconIDForPIDL(0, cfe, dwIcon, &fCacheThisIcon);
    if (SUCCEEDED(hr))
    {
        ULONG  uFlags = GIL_PERINSTANCE | GIL_NOTFILENAME;
        if (!fCacheThisIcon)
        {
             uFlags |= GIL_DONTCACHE;
        }
        int    iIcon = static_cast<int>(dwIcon);
        int    iCachedImage = Shell_GetCachedImageIndex(c_szNetShellIcon, iIcon, uFlags);

        TraceTag(ttidIcons, "%S->SHUpdateImage [0x%08x] (iCachedImage=%d)", cfe.GetName(), dwIcon, iCachedImage);
        if (-1 != iCachedImage)
        {
            SHUpdateImage(c_szNetShellIcon, iIcon, uFlags, iCachedImage);
        }

        DWORD dwIconForShortcut;
        hr = g_pNetConfigIcons->HrGetIconIDForPIDL(GIL_FORSHORTCUT, cfe, dwIconForShortcut, &fCacheThisIcon);
        {
            if (dwIconForShortcut != dwIcon)
            {
                iIcon = static_cast<int>(dwIconForShortcut);
                iCachedImage = Shell_GetCachedImageIndex(c_szNetShellIcon, iIcon, uFlags);

                TraceTag(ttidIcons, "%S->SHUpdateImage GIL_FORSHORTCUT [0x%08x] (iCachedImage=%d)", cfe.GetName(), dwIcon, iCachedImage);
                if (-1 != iCachedImage)
                {
                    SHUpdateImage(c_szNetShellIcon, iIcon, uFlags, iCachedImage);
                }
            }
        }
    }
    
    return hr;
}