// fldricon.cpp : Implementation of CWebViewFolderIcon
#include "priv.h"

#include <shsemip.h>
#include <shellp.h>
#include <mshtml.h>
#include <mshtmdid.h>
#include <fldricon.h>
#include <exdispid.h>
#include <shguidp.h>
#include <hlink.h>
#include <shlwapi.h>
#include <windowsx.h>
#include <wchar.h>
#include <shdocvw.h>  // for IEParseDisplayNameW() & IEGetNameAndFlags()
#include <wingdi.h>

#include <varutil.h>

#define UNINITIALIZE_BOOL   5

const CLSID CLSID_WebViewFolderIconOld = {0xe5df9d10,0x3b52,0x11d1,{0x83,0xe8,0x00,0xa0,0xc9,0x0d,0xc8,0x49}}; // retired from service, so made private


//  PERF: Shell allocator, inserted here because SHRealloc 
//  isn't imported into webvw, this module's hosting executable.
//  If we get SHRealloc, the following block can be removed:
#define _EXPL_SHELL_ALLOCATOR_

#ifdef  _EXPL_SHELL_ALLOCATOR_

#define SHRealloc(pv, cb)     shrealloc(pv, cb)

void* shrealloc(void* pv,  size_t cb)
{
    void *pvRet = NULL;
    IMalloc* pMalloc;
    if (SUCCEEDED(SHGetMalloc(&pMalloc)))  
    {
        pvRet = pMalloc->Realloc(pv, cb);
        pMalloc->Release();
    }
    return pvRet;
}

#endif _EXPL_SHELL_ALLOCATOR_

// For registering the window class
const TCHAR * const g_szWindowClassName = TEXT("WebViewFolderIcon view messaging");

DWORD IntSqrt(DWORD dwNum)
{
    // This code came from "drawpie.c"
    DWORD dwSqrt = 0;
    DWORD dwRemain = 0;
    DWORD dwTry = 0;

    for (int i=0; i<16; ++i) 
    {
        dwRemain = (dwRemain<<2) | (dwNum>>30);
        dwSqrt <<= 1;
        dwTry = dwSqrt*2 + 1;

        if (dwRemain >= dwTry) 
        {
            dwRemain -= dwTry;
            dwSqrt |= 0x01;
        }
        dwNum <<= 2;
    }
    return dwSqrt;
}   

// Make sure you don't begin a drag with random clicking
BOOL CheckForDragBegin(HWND hwnd, int x, int y)
{
    RECT rc;
    int dxClickRect = GetSystemMetrics(SM_CXDRAG);
    int dyClickRect = GetSystemMetrics(SM_CYDRAG);

    ASSERT((dxClickRect > 1) && (dyClickRect > 1));

    // See if the user moves a certain number of pixels in any direction
    SetRect(&rc, x - dxClickRect, y - dyClickRect, x + dxClickRect, y + dyClickRect);

    MapWindowRect(hwnd, NULL, &rc);

    SetCapture(hwnd);

    do 
    {
        MSG msg;

        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            // See if the application wants to process the message...
            if (CallMsgFilter(&msg, MSGF_COMMCTRL_BEGINDRAG) != 0)
                continue;

            switch (msg.message) 
            {
            case WM_LBUTTONUP:
            case WM_RBUTTONUP:
                PostMessage(msg.hwnd, msg.message, msg.wParam, msg.lParam);
                ReleaseCapture();
                return FALSE;

            case WM_LBUTTONDOWN:
            case WM_RBUTTONDOWN:
                ReleaseCapture();
                return FALSE;

            case WM_MOUSEMOVE:
                if (!PtInRect(&rc, msg.pt)) 
                {
                    ReleaseCapture();
                    return TRUE;
                }
                break;

            default:
                if (GetCapture() != hwnd)
                    ReleaseCapture();
                
                TranslateMessage(&msg);
                DispatchMessage(&msg);
                break;
            }
        }
        else WaitMessage();         /* Don't chew 100% CPU */

        // WM_CANCELMODE messages will unset the capture, in that
        // case I want to exit this loop
    } while (GetCapture() == hwnd);

    return FALSE;
}

///////////////////////////////////
//
//  CWebViewFolderIcon functions
//
///////////////////////////////////

CWebViewFolderIcon::CWebViewFolderIcon() :
    m_pccpDV(NULL),
    m_hIcon(0),
    m_iIconIndex(-1),
    m_hbm(NULL),
    m_pthumb(NULL),
    m_pidl(NULL),
    m_msgHwnd(NULL),
    m_pdispWindow(NULL),
    m_dwThumbnailID(0),
    m_bHilite(FALSE)
{
    m_percentScale = 100;
    m_lImageWidth = 0; 
    m_lImageHeight = 0;
    m_sizLabel.cx = m_sizLabel.cy = 0;
    m_pszDisplayName = NULL;

    m_bHasRect = FALSE;
    m_ViewUser = VIEW_LARGEICON;
    m_ViewCurrent = VIEW_LARGEICON;
    m_clickStyle = 2;                   // Default is double-click
    m_fUseSystemColors = TRUE;
    m_bAdvPropsOn = VARIANT_TRUE;
    m_bRegWndClass = FALSE;
    m_ullFreeSpace = 0;
    m_ullUsedSpace = 0;
    m_ullTotalSpace = 0;
    m_highestIndexSlice = 0;
    m_fTabRecieved = FALSE;
    m_pcm3 = NULL;
    m_pDropTargetCache = NULL;
    m_fIsHostWebView = UNINITIALIZE_BOOL;

    m_hdc = NULL;
    m_fRectAdjusted = 0;
    m_hbmDrag = NULL;

    m_hdsaSlices = DSA_Create(sizeof(PieSlice_S), SLICE_NUM_GROW);

    /*
     *  Listview puts a SM_CXEDGE between the icon and the label,
     *  so we will default to that value.  (Clients can adjust with
     *  labelGap property.)
     */
    m_cxLabelGap = GetSystemMetrics(SM_CXEDGE);

    m_pfont = NULL;
    m_hfAmbient = NULL;

}

CWebViewFolderIcon::~CWebViewFolderIcon()
{
    _ClearLabel();
    _ClearAmbientFont();

    if (m_hIcon) 
    {
        DestroyIcon(m_hIcon);
        m_hIcon = NULL;
    }
    
    if (m_hdc)
    {
        DeleteDC(m_hdc);
        m_hdc = NULL;
    }

    if (m_hbmDrag)
    {
        DeleteObject(m_hbmDrag);
        m_hbmDrag = NULL;
    }
    
    ILFree(m_pidl);

    if (m_hbm)
    {
        DeleteObject(m_hbm);
        m_hbm = NULL;
    }

    if (m_hfAmbient)
    {
        DeleteObject(m_hfAmbient);
        m_hfAmbient = NULL;
    }

    ATOMICRELEASE(m_pDropTargetCache);
    ATOMICRELEASE(m_pthumb);

    DSA_Destroy(m_hdsaSlices);

    if (m_msgHwnd)
        ::DestroyWindow(m_msgHwnd);

    if (m_bRegWndClass)
    {
        UnregisterClass(g_szWindowClassName, _Module.GetModuleInstance());
    }
}

HRESULT CWebViewFolderIcon::_SetupWindow(void)
{
    // On the first time register the messaging window
    if (!m_bRegWndClass)
    {
        // Create Window Class for messaging
        m_msgWc.style = 0;
        m_msgWc.lpfnWndProc = CWebViewFolderIcon::WndProc;
        m_msgWc.cbClsExtra = 0;
        m_msgWc.cbWndExtra = 0;
        m_msgWc.hInstance = _Module.GetModuleInstance();
        m_msgWc.hIcon = NULL;
        m_msgWc.hCursor = NULL;
        m_msgWc.hbrBackground = NULL;
        m_msgWc.lpszMenuName = NULL;
        m_msgWc.lpszClassName = g_szWindowClassName;

        m_bRegWndClass = RegisterClass(&m_msgWc);
    }

    if (!m_msgHwnd)
    {
        m_msgHwnd = CreateWindow(g_szWindowClassName, NULL, WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 
                             CW_USEDEFAULT, NULL, NULL, _Module.GetModuleInstance(), this);
    }

    return m_msgHwnd ? S_OK : E_FAIL;
}

// Must be called before using the IThumbnail.  Also sets up the thumbnail message window
HRESULT CWebViewFolderIcon::SetupIThumbnail(void)
{
    HRESULT hr = _SetupWindow();
    if (SUCCEEDED(hr))
    {
        if (m_pthumb)
            hr = S_OK;
        else
        {
            hr = CoCreateInstance(CLSID_Thumbnail, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IThumbnail2, &m_pthumb));
            if (SUCCEEDED(hr))
                hr = m_pthumb->Init(m_msgHwnd, WM_HTML_BITMAP);
        }
    }
    return hr;
}

// General functions
HRESULT CWebViewFolderIcon::_InvokeOnThumbnailReady()
{
    // Fire off "OnThumbnailReady" event to our connection points to indicate that
    // either a thumbnail has been computed or we have no thumbnail for this file.
    DISPPARAMS dp = {0, NULL, 0, NULL};     // no parameters

    //Lock();
    for (IUnknown** pp = m_vec.begin(); pp < m_vec.end(); pp++)
    {
        if (pp)
        {
            IDispatch* pDispatch = SAFECAST(*pp, IDispatch*);
            pDispatch->Invoke(DISPID_WEBVIEWFOLDERICON_ONTHUMBNAILREADY, IID_NULL,
                    LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dp, NULL, NULL, NULL);
        }
    }
    //Unlock();

    FireViewChange();

    return S_OK;
}

// The S_FALSE return value indicates that this function has succeeded, but the out pidl is still NULL
HRESULT CWebViewFolderIcon::_GetFullPidl(LPITEMIDLIST *ppidl)
{
    *ppidl = NULL;

    HRESULT hr;
    if (m_pidl)
    {
        hr = SHILClone(m_pidl, ppidl);  // dupe our copy
    }
    else
    {
        // This used to be an EVAL, but it can legitimately fail if the script did not
        // specify a valid path
        // This will fail if we are hosted in a web page instead of the HTML WebView frame in DefView.
        IUnknown *punk;
        hr = IUnknown_QueryService(m_spClientSite, SID_SFolderView, IID_PPV_ARG(IUnknown, &punk));
        if (SUCCEEDED(hr))
        {   
            if (S_OK == SHGetIDListFromUnk(punk, ppidl))
            {
                Pidl_Set(&m_pidl, *ppidl);  // cache a copy of this
            }
            punk->Release();
        }
    }
    return hr;                       
}


HRESULT _GetPidlAndShellFolderFromPidl(LPITEMIDLIST pidl, LPITEMIDLIST *ppidlLast, IShellFolder** ppsfParent)
{
    LPCITEMIDLIST pidlLast;
    HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, ppsfParent), &pidlLast);
    if (SUCCEEDED(hr))
    {
        *ppidlLast = ILClone(pidlLast);
    }
    return hr;
}

// RETURN VALUES:
//      SUCCEEDED() means *ppidlLast and/or *ppsfParent can be NULL.
//      FAILED() means a *ppidlLast *ppsfParent are going to be returned NULL.
HRESULT CWebViewFolderIcon::_GetPidlAndShellFolder(LPITEMIDLIST *ppidlLast, IShellFolder** ppsfParent)
{
    LPITEMIDLIST pidl;
    HRESULT hr = _GetFullPidl(&pidl);
    if (hr == S_OK)
    {
        hr = _GetPidlAndShellFolderFromPidl(pidl, ppidlLast, ppsfParent);
        ILFree(pidl);
    }
    else
    {
        *ppidlLast = NULL;
        *ppsfParent = NULL;
    }

    return hr;
}

// Get Trident's HWND
HRESULT CWebViewFolderIcon::_GetHwnd(HWND* phwnd)
{
    HRESULT hr;

    if (m_spInPlaceSite)
    {
        hr = m_spInPlaceSite->GetWindow(phwnd);
    }
    else
    {
        IOleInPlaceSiteWindowless * poipsw;
        hr = m_spClientSite->QueryInterface(IID_PPV_ARG(IOleInPlaceSiteWindowless, &poipsw));
        if (EVAL(SUCCEEDED(hr)))
        {
            hr = poipsw->GetWindow(phwnd);
            poipsw->Release();
        }
    }
    return hr;
}

HRESULT CWebViewFolderIcon::_GetChildUIObjectOf(REFIID riid, void **ppvObj)
{
    LPITEMIDLIST pidlLast;
    IShellFolder *psfParent;
    HRESULT hr = _GetPidlAndShellFolder(&pidlLast, &psfParent);
    if (hr == S_OK)
    {
        HWND hwnd;
        
        _GetHwnd(&hwnd);
        hr = psfParent->GetUIObjectOf(hwnd, 1, (LPCITEMIDLIST *)&pidlLast, riid, NULL, ppvObj);
        psfParent->Release();
        ILFree(pidlLast);
    }
    else
        hr = E_FAIL;

    return hr;
}

//  Center point of focus rectangle
HRESULT CWebViewFolderIcon::_GetCenterPoint(POINT *pt)
{
    pt->y = ((m_rcPos.top + m_rcPos.bottom)/2);
    pt->x = ((m_rcPos.left + m_rcPos.right)/2);

    return S_OK;
}

HRESULT CWebViewFolderIcon::_IsSafe()
{
    HRESULT hr;

    if (0==m_dwCurrentSafety)
    {
        hr = S_OK;
    }
    else
    {
        if (_IsPubWizHosted())
            hr = S_OK;
        else
            hr = IsSafePage(m_spClientSite);
    }

    return hr;
}


BOOL CWebViewFolderIcon::IsSafeToDefaultVerb(void)
{
    return S_OK == _IsSafe();
}

//  If the focus rectangle is not in the specified RectState (on or off) change it and reset m_bHasRect
void CWebViewFolderIcon::_FlipFocusRect(BOOL RectState)
{
    if (m_bHasRect != RectState)    // needs flipping
    {
        m_bHasRect = RectState;
        ForceRedraw();
    }
    return;
}

// Extract a ULONGLONG from two VARIANT's
ULONGLONG CWebViewFolderIcon::GetUllMemFromVars(VARIANT *pvarHi, VARIANT *pvarLo)
{
    ULARGE_INTEGER uli;

    uli.HighPart = pvarHi->ulVal;
    uli.LowPart = pvarLo->ulVal;

    return uli.QuadPart;
}

// Returns the integer percent from the string percent.  Returns -1 if the string is invalid;
int CWebViewFolderIcon::GetPercentFromStrW(LPCWSTR pwzPercent)
{
    int percent = -1;
    int numchar = lstrlenW(pwzPercent);
    ASSERT(numchar>0);

    if (pwzPercent[numchar-1] == '%')
    {
        LPWSTR pwzTempPct = SysAllocString(pwzPercent);

        if (pwzTempPct)
        {
            pwzTempPct[numchar-1] = '\0';

            for (int i=0 ; i < (numchar-2) ; i++)
            {
                if (!((pwzTempPct[i] >= '0') && (pwzTempPct[i] <= '9')))
                {
                    percent = 100;  // 100% is the default to use in error conditions
                    break;
                }
            }

            if ((-1 == percent) && !StrToIntExW(pwzTempPct, STIF_DEFAULT, &percent))
            {
                percent = -1;
            }

            SysFreeString(pwzTempPct);
        }
    }

    return percent;
}

BOOL CWebViewFolderIcon::_WebViewOpen(void)
{
    BOOL Processed = FALSE;

    if (IsSafeToDefaultVerb())
    {   
        Processed = TRUE;
        //
        // if the context menu option does not work, we try a shell execute on the pidl
        //
        if (FAILED(_DoContextMenuCmd(TRUE, 0, 0)))
        {   
            if (m_pidl)
            {
                SHELLEXECUTEINFO sei = { 0 };

                sei.cbSize     = sizeof(sei);
                sei.fMask      = SEE_MASK_INVOKEIDLIST;
                sei.nShow      = SW_SHOWNORMAL;
                sei.lpIDList   = m_pidl;

                if (!ShellExecuteEx(&sei))
                {
                    Processed = FALSE;
                }
            }
        }
    }
    return Processed;
}


void CWebViewFolderIcon::_ClearLabel(void)
{
    if (m_pszDisplayName)
    {
        CoTaskMemFree(m_pszDisplayName);
        m_pszDisplayName = NULL;
        m_sizLabel.cx = m_sizLabel.cy = 0;
    }
}

void  CWebViewFolderIcon::_GetLabel(IShellFolder *psf, LPCITEMIDLIST pidlItem)
{
    if ((m_ViewUser & VIEW_WITHLABEL) && psf)
    {
        STRRET str;
        if (SUCCEEDED(psf->GetDisplayNameOf(pidlItem, SHGDN_INFOLDER, &str)))
        {
            AssertMsg(m_pszDisplayName == NULL, TEXT("CWebViewFolderIcon::_GetLabel - leaking m_pszDisplayName!"));
            StrRetToStr(&str, pidlItem, &m_pszDisplayName);
        }
    }
}

void CWebViewFolderIcon::_ClearAmbientFont(void)
{
    if (m_pfont)            // Font came from container
    {
        if (m_hfAmbient)
            m_pfont->ReleaseHfont(m_hfAmbient);
        m_pfont->Release();
        m_pfont = NULL;

    }
    else                    // Font was created by us
    {
        if (m_hfAmbient)
            DeleteObject(m_hfAmbient);
    }
    m_hfAmbient = NULL;

}

void CWebViewFolderIcon::_GetAmbientFont(void)
{
    if (!m_hfAmbient)
    {
        // Try to get the ambient font from our container
        if (SUCCEEDED(GetAmbientFont(&m_pfont)))
        {
            if (SUCCEEDED(m_pfont->get_hFont(&m_hfAmbient)))
            {
                // Yay, everybody is happy
                m_pfont->AddRefHfont(m_hfAmbient);
            }
            else
            {
                // Darn, couldn't get the font from container
                // Clean up and use the fallback
                _ClearAmbientFont();
                goto fallback;
            }
        }
        else
        {
    fallback:
            // No ambient font -- use the icon title font
            LOGFONT lf;
            SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, FALSE);
            m_hfAmbient = CreateFontIndirect(&lf);
        }
    }
}


HRESULT CWebViewFolderIcon::InitImage(void)
{
    HRESULT hr = E_FAIL;

    // Cancel pending bitmap request if you had a functioning IThumbnail
    // but didn't receive the bitmap
    if (m_pthumb && (m_hbm == NULL))
    {
        m_pthumb->GetBitmap(NULL, 0, 0, 0);
    }

    m_dwThumbnailID++;

    // Initialize the image
    switch (_ViewType(m_ViewUser))
    {
    case VIEW_THUMBVIEW:
        hr = InitThumbnail();
        if (hr != S_OK)
        {   // Default to icon view, but return the previous hr
            InitIcon();
        }
        break;

    case VIEW_PIECHART:
        hr = InitPieGraph();
        if (hr != S_OK)
        {   // Default to icon view, but return the previous hr
            InitIcon();
        }
        break;

    default:
        hr = InitIcon();
        break;
    }

    if (SUCCEEDED(hr))          //  Force a Redraw
        UpdateSize();

    return hr;    
}

HRESULT CWebViewFolderIcon::_GetPathW(LPWSTR psz)
{
    *psz = 0;
    HRESULT hr = E_FAIL;
    LPITEMIDLIST pidl;
    if (S_OK == _GetFullPidl(&pidl))
    {
        if (SHGetPathFromIDListW(pidl, psz))
            hr = S_OK;
        ILFree(pidl);
    }
    return hr;
}


HRESULT CWebViewFolderIcon::InitPieGraph(void)
{
    HRESULT hr = S_FALSE;
    
    WCHAR wzPath[MAX_PATH];
    if (SUCCEEDED(_GetPathW(wzPath)))
    {
        //  Check to see if it is a root
        if (PathIsRootW(wzPath))
        {
            if (SUCCEEDED(ComputeFreeSpace(wzPath)))
            {
                m_ViewCurrent = VIEW_PIECHART;
                m_lImageHeight = PIEVIEW_DEFAULT;
                m_lImageWidth = PIEVIEW_DEFAULT;
                hr = S_OK;
            }
        }
        else        // not the root, change view to large icon
            m_ViewCurrent = VIEW_LARGEICON;
    }
    return hr;
}

HRESULT CWebViewFolderIcon::InitThumbnail(void)
{
    m_lImageHeight = THUMBVIEW_DEFAULT;
    m_lImageWidth = THUMBVIEW_DEFAULT;

    //  Get thumbnail bitmap from the path
    HRESULT hr = S_FALSE;
    LPITEMIDLIST pidl;
    if (S_OK == _GetFullPidl(&pidl))
    {
        hr = SetupIThumbnail();
        if (SUCCEEDED(hr))
        {
            LONG lWidth = _GetScaledImageWidth();
            LONG lHeight = _GetScaledImageHeight();

            // Sends the WM_HTML_BITMAP message
            hr = m_pthumb->GetBitmapFromIDList(pidl, m_dwThumbnailID, lWidth, lHeight);
            if (SUCCEEDED(hr))
                m_ViewCurrent = VIEW_THUMBVIEW;
            else
                hr = S_FALSE;
        }
        ILFree(pidl);
    }
    return hr;
}

HRESULT CWebViewFolderIcon::_MakeRoomForLabel()
{
    /*
     *  If we got a label, then make room for it.
     */
    if (m_pszDisplayName)
    {
        GETDCSTATE dcs;
        HDC hdc = IUnknown_GetDC(m_spClientSite, &m_rcPos, &dcs);
        _GetAmbientFont();

        HFONT hfPrev = SelectFont(hdc, m_hfAmbient);

        m_sizLabel.cx = m_sizLabel.cy = 0;
        GetTextExtentPoint(hdc, m_pszDisplayName, lstrlen(m_pszDisplayName), &m_sizLabel);
        SelectFont(hdc, hfPrev);

        IUnknown_ReleaseDC(hdc, &dcs);
    }
    return S_OK;
}

HRESULT CWebViewFolderIcon::InitIcon(void)
{
    LPITEMIDLIST            pidlLast;
    CComPtr<IShellFolder>   spsfParent;
    INT                     iIconIndex = II_DESKTOP;  

    _ClearLabel();

    //  Get icon index
    HRESULT hr = _GetPidlAndShellFolder(&pidlLast, &spsfParent);
    if (SUCCEEDED(hr))
    {
        if (m_ViewUser & VIEW_WITHLABEL)
        {
            _GetLabel(spsfParent, pidlLast);
        }

        //  _GetPidlAndShellFolder() may succeed and spsfParent and pidlLast can be NULL.
        //  In this case the icon will default to II_FOLDER

        //  Is it the default folder case?
        if (hr == S_FALSE)
        {
            //  Yes, so just use the default folder icon.
            iIconIndex = II_FOLDER;   
        }
        else if (spsfParent && pidlLast)
        {
            iIconIndex = SHMapPIDLToSystemImageListIndex(spsfParent, pidlLast, NULL);
            if (iIconIndex <= 0)
            {
                iIconIndex = II_FOLDER;
            }
        }
        //  else it defaults to the desktop
        
        //  Extract icon
        hr = E_FAIL;     //  We haven't gotten it yet
       
        if (m_hIcon)
        {
            // If the indexes match, we can use the previous value as a cache, otherwise,
            // we need to free it.  We also need to free the bitmap in this case.
            if (iIconIndex != m_iIconIndex)
            {
                DestroyIcon(m_hIcon);
                m_hIcon = 0;
            }
            else
            {
                hr = S_OK;      //  Use the one we have already
            }
        }

        // We also need to check and free the bitmap
        if (m_hbm)
        {
            DeleteObject(m_hbm);
            m_hbm = 0;
        }

        if (FAILED(hr))         //  Different icon
        {
            HIMAGELIST  himlSysLarge;
            HIMAGELIST  himlSysSmall;
            
            if ((iIconIndex > 0) && Shell_GetImageLists(&himlSysLarge, &himlSysSmall))
            {
                switch (_ViewType(m_ViewUser))  
                {
                case VIEW_SMALLICON:
                    m_hIcon = ImageList_GetIcon(himlSysSmall, iIconIndex, 0);
                    m_ViewCurrent = m_ViewUser;
                    break;

                case VIEW_LARGEICON:
                    m_hIcon = ImageList_GetIcon(himlSysLarge, iIconIndex, 0);     
                    m_ViewCurrent = m_ViewUser;
                    break;

                default:  // Falls here for large icon and default
                    m_hIcon = ImageList_GetIcon(himlSysLarge, iIconIndex, 0);     
                    m_ViewCurrent = VIEW_LARGEICON;
                    break;
                }  // switch
                
                if (m_hIcon)
                {
                    ICONINFO    iconinfo;
                    
                    //  Get icon size
                    if (GetIconInfo(m_hIcon, &iconinfo))
                    {
                        BITMAP  bm;
                        
                        if (GetObject(iconinfo.hbmColor, sizeof(bm), &bm))
                        {
                            m_lImageWidth = bm.bmWidth;
                            m_lImageHeight = bm.bmHeight;

                            // Hold on to the color hbm for use as a drag image.
                            m_hbm = iconinfo.hbmColor;
                            hr = S_OK;
                        }
                        else
                        {
                            DeleteObject(iconinfo.hbmColor);
                        }

                        DeleteObject(iconinfo.hbmMask);
                    }
                }
            }
        }
        
        ILFree(pidlLast);

        _MakeRoomForLabel();
    }

    if (FAILED(hr))
    {
        //  Couldn't get the icon so set the size to something resonable so that the rest
        //  of the page looks normal

        m_lImageWidth =  LARGE_ICON_DEFAULT;
        m_lImageHeight = LARGE_ICON_DEFAULT;
        UpdateSize();       //  Force an update
    }

    return hr;
} 

HRESULT CWebViewFolderIcon::UpdateSize(void)
{
    HRESULT                   hr = E_FAIL;
      
    // Get the IHtmlStyle
    if (m_spClientSite) 
    {
        CComPtr<IOleControlSite>  spControlSite;

        hr = m_spClientSite->QueryInterface(IID_PPV_ARG(IOleControlSite, &spControlSite));
        if (EVAL(SUCCEEDED(hr)))
        {
            CComPtr<IDispatch> spdisp;

            hr = spControlSite->GetExtendedControl(&spdisp);
            if (EVAL(SUCCEEDED(hr)))
            {
                CComPtr<IHTMLElement> spElement;

                hr = spdisp->QueryInterface(IID_PPV_ARG(IHTMLElement, &spElement));
                if (EVAL(SUCCEEDED(hr)))
                {
                    CComPtr<IHTMLStyle> spStyle;
                    
                    hr = spElement->get_style(&spStyle);
                    if (EVAL(SUCCEEDED(hr)))
                    {
                        CComVariant vWidth(_GetControlWidth(), VT_I4);
                        CComVariant vHeight(_GetControlHeight(), VT_I4);
                        
                        // Set the height and width
                        spStyle->put_width(vWidth);
                        spStyle->put_height(vHeight);
                    }
                }
            }
        }
    }
    return hr;
}

HRESULT CWebViewFolderIcon::ForceRedraw(void)
{
    IOleInPlaceSiteEx *pins;
   
    // Get the IHtmlStyle
    if (m_spClientSite) 
    {
        if (SUCCEEDED(m_spClientSite->QueryInterface(IID_PPV_ARG(IOleInPlaceSiteEx, &pins)))) 
        {
            HWND hwnd;
            if (SUCCEEDED(pins->GetWindow(&hwnd))) 
            {
                ::InvalidateRgn(hwnd, NULL, TRUE);
            }
            pins->Release();
        }
    }

    return S_OK;
}

/////////////////////////////////////////////////////////////////////////////
// IOleInPlaceObject

STDMETHODIMP CWebViewFolderIcon::UIDeactivate(void)
{
    if (m_bAdvPropsOn)
        _FlipFocusRect(FALSE);

    return IOleInPlaceObject_UIDeactivate();
}

// *** IOleInPlaceActiveObject ***
HRESULT CWebViewFolderIcon::TranslateAccelerator(LPMSG pMsg)
{
    HRESULT hr = S_OK;
    if (!m_fTabRecieved)
    {
        hr = IOleInPlaceActiveObjectImpl<CWebViewFolderIcon>::TranslateAccelerator(pMsg);

        // If we did not handle this and if it is a tab (and we are not getting it in a cycle), forward it to trident, if present.
        if (hr != S_OK && pMsg && (pMsg->wParam == VK_TAB || pMsg->wParam == VK_F6) && m_spClientSite)
        {
            HWND hwnd;
            if (SUCCEEDED(_GetHwnd(&hwnd)) && (GetFocus() != hwnd))
            {
                ::SetFocus(hwnd);
                hr = S_OK;
            }
            else
            {
                IOleControlSite* pocs = NULL;
                if (SUCCEEDED(m_spClientSite->QueryInterface(IID_PPV_ARG(IOleControlSite, &pocs))))
                {
                    DWORD grfModifiers = 0;
                    if (GetKeyState(VK_SHIFT) & 0x8000)
                    {
                        grfModifiers |= 0x1;    //KEYMOD_SHIFT
                    }
                    if (GetKeyState(VK_CONTROL) & 0x8000)
                    {
                        grfModifiers |= 0x2;    //KEYMOD_CONTROL;
                    }
                    if (GetKeyState(VK_MENU) & 0x8000)
                    {
                        grfModifiers |= 0x4;    //KEYMOD_ALT;
                    }
                    m_fTabRecieved = TRUE;
                    hr = pocs->TranslateAccelerator(pMsg, grfModifiers);
                    m_fTabRecieved = FALSE;
                }
            }
        }
    }
    return hr;
}

/////////////////////////////////////////////////////////////////////////////
// ATL

HRESULT CWebViewFolderIcon::DoVerbUIActivate(LPCRECT prcPosRect, HWND hwndParent)
{
    if (m_bAdvPropsOn)
        _FlipFocusRect(TRUE);

    return IOleObjectImpl<CWebViewFolderIcon>::DoVerbUIActivate(prcPosRect, hwndParent);
}

/////////////////////////////////////////////////////////////////////////////
// IDispatch 

STDMETHODIMP CWebViewFolderIcon::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, 
                      WORD wFlags, DISPPARAMS *pDispParams, 
                      VARIANT *pVarResult, EXCEPINFO *pExcepInfo,
                      UINT *puArgErr)
{
    HRESULT hr;

    //
    // We are overloading this dispatch implementation to be an html window event
    // sink and implement the scale property.  This is safe since the dispid ranges
    // don't overlap.
    // Likewise we overload now for notifications that come from the browser object...
    //

    if (dispidMember == DISPID_HTMLWINDOWEVENTS_ONLOAD) 
    {
        hr = OnWindowLoad();
    } 
    else if (dispidMember == DISPID_HTMLWINDOWEVENTS_ONUNLOAD) 
    {
        hr = OnWindowUnLoad();    
    }
    else
    {
        hr = IDispatchImpl<IWebViewFolderIcon3, &IID_IWebViewFolderIcon3, &LIBID_WEBVWLib>::Invoke(
              dispidMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
    }

    return hr;  
}


/////////////////////////////////////////////////////////////////////////////
// IViewObjectEx

STDMETHODIMP CWebViewFolderIcon::GetViewStatus(DWORD* pdwStatus)
{
    *pdwStatus = VIEWSTATUS_DVASPECTTRANSPARENT;
    return S_OK;
}


/////////////////////////////////////////////////////////////////////////////
// IPointerInactive

STDMETHODIMP CWebViewFolderIcon::GetActivationPolicy(DWORD* pdwPolicy)
{
    if (!m_bAdvPropsOn)
        return S_OK;

    *pdwPolicy = POINTERINACTIVE_ACTIVATEONDRAG;
    return S_OK;
}


/////////////////////////////////////////////////////////////////////////////
// IOleInPlaceObjectWindowless

// To implement Windowless DropTarget
STDMETHODIMP CWebViewFolderIcon::GetDropTarget(IDropTarget **ppDropTarget)
{
    HRESULT hr = S_OK;

    if (ppDropTarget)
        *ppDropTarget = NULL;

    if (m_bAdvPropsOn)
    {
        // Do we need to populate m_pDropTargetCache?
        if (!m_pDropTargetCache)
        {
            // Yes, so try to get it now.
            hr = _GetChildUIObjectOf(IID_PPV_ARG(IDropTarget, &m_pDropTargetCache));
        }

        if (m_pDropTargetCache)
            hr = m_pDropTargetCache->QueryInterface(IID_PPV_ARG(IDropTarget, ppDropTarget));
        else
            hr = E_FAIL;
    }

    return hr;
}


/////////////////////////////////////////////////////////////////////////////
// IOleObject

STDMETHODIMP CWebViewFolderIcon::SetClientSite(IOleClientSite *pClientSite)
{
    HRESULT hr;

    // Deal with the old client site
    if (pClientSite == NULL && m_spClientSite)
    {
        // We need to unadvise from the defview object now...
        if (m_pccpDV) 
        {
            m_pccpDV->Unadvise(m_dwCookieDV);
            m_pccpDV->Release();
            m_pccpDV = NULL;
        }
        DisconnectHtmlEvents(m_pdispWindow, m_dwHtmlWindowAdviseCookie);
        m_dwHtmlWindowAdviseCookie = 0;
    }

    hr = IOleObjectImpl<CWebViewFolderIcon>::SetClientSite(pClientSite);

    if ((pClientSite != NULL) && SUCCEEDED(hr))
    { 
        ConnectHtmlEvents(this, m_spClientSite, &m_pdispWindow, &m_dwHtmlWindowAdviseCookie);

        // OK now lets register ourself with the Defview to get any events that they may generate...
        IServiceProvider *pspTLB;
        hr = IUnknown_QueryService(m_spClientSite, SID_STopLevelBrowser, IID_PPV_ARG(IServiceProvider, &pspTLB));
        if (SUCCEEDED(hr)) 
        {
            IExpDispSupport *peds;
            hr = pspTLB->QueryService(IID_IExpDispSupport, IID_PPV_ARG(IExpDispSupport, &peds));
            if (SUCCEEDED(hr)) 
            {
                hr = peds->FindCIE4ConnectionPoint(DIID_DWebBrowserEvents2, &m_pccpDV);
                if (SUCCEEDED(hr)) 
                {
                    hr = m_pccpDV->Advise(SAFECAST(this, IDispatch*), &m_dwCookieDV);
                }
                peds->Release();
            }
            pspTLB->Release();
        }
    }

    return hr;
}


UINT g_cfPreferedEffect = 0;

HRESULT _SetPreferedDropEffect(IDataObject *pdtobj, DWORD dwEffect)
{
    if (g_cfPreferedEffect == 0)
        g_cfPreferedEffect = RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT);

    HRESULT hr = E_OUTOFMEMORY;
    DWORD *pdw = (DWORD *)GlobalAlloc(GPTR, sizeof(DWORD));
    if (pdw)
    {
        STGMEDIUM medium;
        FORMATETC fmte = {(CLIPFORMAT)g_cfPreferedEffect, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
        *pdw = dwEffect;

        medium.tymed = TYMED_HGLOBAL;
        medium.hGlobal = pdw;
        medium.pUnkForRelease = NULL;

        hr = pdtobj->SetData(&fmte, &medium, TRUE);

        if (FAILED(hr))
            GlobalFree((HGLOBAL)pdw);
    }
    return hr;
}

/////////////////////////////////////////////////////////////////////////////
// Event Handlers

HRESULT CWebViewFolderIcon::DragDrop(int iClickXPos, int iClickYPos)
{
    if (!m_bAdvPropsOn)
        return S_OK;

    LPITEMIDLIST pidlLast;
    IShellFolder *psfParent;
    HRESULT hr = _GetPidlAndShellFolder(&pidlLast, &psfParent);

    if (hr == S_OK)
    {
        IDataObject *pdtobj;

        hr = psfParent->GetUIObjectOf(NULL, 1, (LPCITEMIDLIST*) &pidlLast, 
                                      IID_PPV_ARG_NULL(IDataObject, &pdtobj));
        if (SUCCEEDED(hr))
        {
            DWORD dwEffect = DROPEFFECT_MOVE | DROPEFFECT_COPY | DROPEFFECT_LINK;

            psfParent->GetAttributesOf(1, (LPCITEMIDLIST*) &pidlLast, &dwEffect);
            dwEffect &= DROPEFFECT_MOVE | DROPEFFECT_COPY | DROPEFFECT_LINK;
            
            if (dwEffect)
            {
                HRESULT hrOleInit = SHCoInitialize();
                HWND hwnd;
                
                hr = _GetHwnd(&hwnd);
                
                if (SUCCEEDED(hr))
                {
                    DWORD dwEffectOut;
                    
                    _SetPreferedDropEffect(pdtobj, DROPEFFECT_LINK);  
                    
                    // Set the drag image and effect; we don't care if 
                    // it fails, we'll just use the default.
                    _SetDragImage(iClickXPos, iClickYPos, pdtobj);


                    hr = SHDoDragDrop(hwnd, pdtobj, NULL, dwEffect, &dwEffectOut);
                }
                SHCoUninitialize(hrOleInit);
            }
            
            pdtobj->Release();
        }
        psfParent->Release();
        ILFree(pidlLast);
    }

    return hr;
}

// SetDragImage
//
// Sets the drag image to be identical to the icon
HRESULT CWebViewFolderIcon::_SetDragImage(int iClickXPos, int iClickYPos, IDataObject *pdtobj)
{
    // Check things that need to be valid for us to work
    AssertMsg(m_hdc != NULL , TEXT("CWebViewFolderIcon:_SetDragImage() m_hdc is null"));
    AssertMsg(m_hbmDrag != NULL, TEXT("CWebViewFolderIcon:_SetDragImage m_hbmDrag is null"));

    // If the image is a pie chart, it isn't loaded into m_hbm, so we need
    // to do that first
    if (m_ViewCurrent == VIEW_PIECHART)
    {
        _GetPieChartIntoBitmap();
    }

    // Get a dragdrop helper to set our image
    IDragSourceHelper *pdsh;
    HRESULT hr = CoCreateInstance(CLSID_DragDropHelper, NULL, CLSCTX_INPROC_SERVER, 
        IID_PPV_ARG(IDragSourceHelper, &pdsh));
    if (SUCCEEDED(hr))
    {
        BITMAPINFOHEADER bmi = {0};
        BITMAP           bm = {0};
        UINT uBufferOffset = 0;
        
        // This is a screwy procedure to use GetDIBits.  
        // See knowledge base Q80080

        GetObject(m_hbm, sizeof(BITMAP), &bm);

        bmi.biSize          = sizeof(BITMAPINFOHEADER);
        bmi.biWidth         = bm.bmWidth;
        bmi.biHeight        = bm.bmHeight;
        bmi.biPlanes        = 1;
        bmi.biBitCount      = bm.bmPlanes * bm.bmBitsPixel;
        
        // This needs to be one of these 4 values
        if (bmi.biBitCount <= 1)
            bmi.biBitCount = 1;
        else if (bmi.biBitCount <= 4)
            bmi.biBitCount = 4;
        else if (bmi.biBitCount <= 8)
            bmi.biBitCount = 8;
        else
            bmi.biBitCount = 24;
        
        bmi.biCompression   = BI_RGB;

        // Total size of buffer for info struct and color table
        uBufferOffset = sizeof(BITMAPINFOHEADER) + 
            ((bmi.biBitCount == 24) ? 0 : ((1 << bmi.biBitCount) * sizeof(RGBQUAD)));
        
        // Buffer for bitmap bits, so we can copy them.
        BYTE * psBits = (BYTE *) SHAlloc(uBufferOffset);

        if (psBits)
        {
            // Put bmi into the memory block
            CopyMemory(psBits, &bmi, sizeof(BITMAPINFOHEADER));

            // Get the size of the buffer needed for bitmap bits
            if (GetDIBits(m_hdc, m_hbm, 0, 0, NULL, (BITMAPINFO *) psBits, DIB_RGB_COLORS))
            {
                // Realloc our buffer to be big enough
                psBits = (BYTE *) SHRealloc(psBits, uBufferOffset + ((BITMAPINFOHEADER *) psBits)->biSizeImage);

                if (psBits)
                {
                    // Fill the buffer
                    if (GetDIBits(m_hdc, m_hbm, 0, bmi.biHeight, 
                        (void *)(psBits + uBufferOffset), (BITMAPINFO *)psBits, 
                        DIB_RGB_COLORS))
                    {
                        SHDRAGIMAGE shdi;  // Drag images struct
                        
                        shdi.hbmpDragImage = CreateBitmapIndirect(&bm);
                        
                        if (shdi.hbmpDragImage)
                        {
                            // Set the drag image bitmap
                            if (SetDIBits(m_hdc, shdi.hbmpDragImage, 0, m_lImageHeight, 
                                (void *)(psBits + uBufferOffset), (BITMAPINFO *)psBits, 
                                DIB_RGB_COLORS))
                            {
                                // Populate the drag image structure
                                shdi.sizeDragImage.cx = m_lImageWidth;
                                shdi.sizeDragImage.cy = m_lImageHeight;
                                
                                shdi.ptOffset.x = iClickXPos - m_rcPos.left;
                                shdi.ptOffset.y = iClickYPos - m_rcPos.top;
                                
                                shdi.crColorKey = 0;
                                
                                // Set the drag image
                                hr = pdsh->InitializeFromBitmap(&shdi, pdtobj); 
                            }
                            else
                            {
                                hr = E_FAIL;  // Can't SetDIBits
                            }
                        }
                        else
                        {
                            hr = E_OUTOFMEMORY;  // Can't alloc hbmpDragImage
                        }
                    }
                    else
                    {
                        hr = E_FAIL;  // Can't fill psBits
                    }
                    // Free psBits below...
                }
                else
                {
                    hr = E_OUTOFMEMORY;  // Can't realloc psBits
                    
                    // Free psbits here; it still has the old contents
                    SHFree(psBits);
                    psBits = NULL;
                }
            }
            else
            {
                hr = E_FAIL;  // Can't get image size
            }
            if (psBits)
                SHFree(psBits);
        }
        else
        {
            hr = E_OUTOFMEMORY;  // Can't alloc psBits
        }        
        pdsh->Release();
    }
    
    return hr;
}

HRESULT CWebViewFolderIcon::_GetPieChartIntoBitmap()
{
    BITMAP bm;
    
    // It is possible for m_hbm to be alloced, so check for it.
    if (m_hbm)
    {
        DeleteObject(m_hbm);
    }
    
    // Notice that because we want to draw into a new DC starting
    // from the origin, but our rect contains the coords for the
    // original DC, it is neccessary to adjust the coords so that
    // the rect starts at 0, 0 but still has the same proportions.  
    // Since OnDraw() resets the rect each time, we don't have to
    // preserve it and do have to do this each time.  Finally, since
    // Draw3dPie adjusts the rect dimensions for itself, we only want
    // to fix this once.
    if (!m_fRectAdjusted)
    {
        m_rect.right -= m_rect.left;
        m_rect.left = 0;
        m_rect.bottom -= m_rect.top;
        m_rect.top = 0;
        m_fRectAdjusted = 1;
    }
    
    // Get the bitmap
    GetObject(m_hbmDrag, sizeof(BITMAP), &bm);
    m_hbm = CreateBitmapIndirect(&bm);
    
    if (m_hbm)
    {
        // Select into the new DC, and draw our pie
        HBITMAP hbmOld = (HBITMAP) SelectObject(m_hdc, m_hbm);
        DWORD dwPercent1000 = 0;
        
        if (EVAL((m_ullTotalSpace > 0) && (m_ullFreeSpace <= m_ullTotalSpace)))
        {
            ComputeSlicePct(m_ullUsedSpace, &dwPercent1000);
        }
        
        Draw3dPie(m_hdc, &m_rect, dwPercent1000, m_ChartColors);
        
        SelectObject(m_hdc, hbmOld);
    }
    
    return S_OK;
}


LRESULT CWebViewFolderIcon::OnInitPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & bHandled)
{
    if (m_pcm3)
        m_pcm3->HandleMenuMsg(uMsg, wParam, lParam);

    return 0;
}


LRESULT CWebViewFolderIcon::OnKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & bHandled)
{
    if (!m_bAdvPropsOn)
        return TRUE;

    if ((int)wParam != VK_RETURN && (int) wParam != VK_SPACE)
    {
        return FALSE;
    }
    else
        return _WebViewOpen();
}


LRESULT CWebViewFolderIcon::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & bHandled)
{
    if (m_bAdvPropsOn)
    {
        _DisplayContextMenu(-1, -1);
    }

    return TRUE;
}


// NOTE: our drag drop code captures the mouse and has to do funky stuff to
// make sure we get this button up message. if you have problems with this check
// the code in CheckForDragBegin()

LRESULT CWebViewFolderIcon::OnButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & bHandled)
{
    BOOL Processed = FALSE;
    
    if (!m_bAdvPropsOn)
        return TRUE; 

    HWND hwnd;
    if (EVAL(SUCCEEDED(_GetHwnd(&hwnd))))
    {
        if (CheckForDragBegin(hwnd, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)))
        {
            IUnknown *punk;
            if (EVAL(SUCCEEDED(IUnknown_QueryService(m_spClientSite, SID_STopLevelBrowser, IID_PPV_ARG(IUnknown, &punk)))))
            {
                if (SUCCEEDED(DragDrop(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))))
                {
                    Processed = TRUE;
                }
            }
        }
    }

    /*
     *  In single-click mode, open on single left click.
     */
    if (!Processed && uMsg == WM_LBUTTONDOWN && m_clickStyle == 1)
        return _WebViewOpen();

    return Processed;
}

//  Only valid for the HTML window case
LRESULT CWebViewFolderIcon::OnLButtonDoubleClick(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & bHandled)
{
    if (!m_bAdvPropsOn || m_clickStyle != 2)
        return TRUE;

    return _WebViewOpen();
}


LRESULT CWebViewFolderIcon::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & bHandled)
{
    if (!m_bAdvPropsOn)
        return TRUE;

    //
    // the first time we get a WM_MOUSEMOVE event, we set m_bHilite to be TRUE and ignore 
    // subsequent WM_MOUSEMOVEs. OnMouseLeave() sets m_bHilite to FALSE in response to 
    // a WM_MOUSELEAVE msg.
    //
    if (!m_bHilite)
    {   
        m_bHilite = TRUE;
        return SUCCEEDED(ForceRedraw());
    }
    else
    {
        return TRUE;
    }
}

LRESULT CWebViewFolderIcon::OnMouseLeave(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & bHandled)
{
    if (!m_bAdvPropsOn)
        return TRUE;

    m_bHilite = FALSE;
    return SUCCEEDED(ForceRedraw());
}

// The Right Mouse button came up so we want to

LRESULT CWebViewFolderIcon::OnRButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & bHandled)
{
    LRESULT lResult = FALSE;

    if (!m_bAdvPropsOn)
        return TRUE;

    HRESULT hr = _IsSafe();
    if (S_OK == hr)
    {
        hr = _DisplayContextMenu(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
        if (SUCCEEDED(hr))
        {
            lResult = TRUE;
        }
    }

    return lResult;
}


BOOL CWebViewFolderIcon::_IsHostWebView(void)
{
    if (UNINITIALIZE_BOOL == m_fIsHostWebView)
    {
        CComPtr<IDefViewID> spDefView;

        m_fIsHostWebView = FALSE;
        // This will fail if we are hosted in a web page instead of the HTML WebView frame in DefView.
        if (SUCCEEDED(IUnknown_QueryService(m_spClientSite, SID_SFolderView, IID_PPV_ARG(IDefViewID, &spDefView))))
        {
            m_fIsHostWebView = TRUE;
        }
    }

    return m_fIsHostWebView;
}


BOOL CWebViewFolderIcon::_IsPubWizHosted(void)
{
    IPropertyBag *ppb;
    HRESULT hr = IUnknown_QueryService(m_spClientSite, SID_WebWizardHost, IID_PPV_ARG(IPropertyBag, &ppb));
    if (SUCCEEDED(hr))
    {
        ppb->Release();
    }
    return SUCCEEDED(hr);
}


/****************************************************\
    DESCRIPTION:
        We need a little special
    work on the Context Menu since it points to the
    same folder we are in.  So the "Send To" menu
    needs massaging and the "Open" verb needs to
    be removed.

    TODO: I think we should also do this:
    case WM_MENUCHAR:
        _pcm->HandleMenuMsg2(uMsg, wParam, lParam, &lres);
        break;
    case WM_DRAWITEM:
    case WM_MEASUREITEM:
        _pcm->HandleMenuMsg(uMsg, wParam, lParam);
        break;

    case WM_INITMENUPOPUP:
        _pcm->HandleMenuMsg(WM_INITMENUPOPUP, (WPARAM)hmenuPopup, (LPARAM)MAKELONG(nIndex, fSystemMenu)
        break;
\****************************************************/
HRESULT CWebViewFolderIcon::_DisplayContextMenu(long nXCord, long nYCord)
{    
    if (!m_bAdvPropsOn)
    {
        return S_OK;
    }
    
    // respect system policies
    if (SHRestricted(REST_NOVIEWCONTEXTMENU)) 
    {
        return E_FAIL;
    }        
    return _DoContextMenuCmd(FALSE, nXCord, nYCord);
}


//
// bDefault == TRUE  > Function executes the default context menu verb, ignores the coords
// bDefault == FALSE > Function pops up a menu at the given coords and executes the desired verb
//
HRESULT CWebViewFolderIcon::_DoContextMenuCmd(BOOL bDefault, long nXCord, long nYCord)
{
    IContextMenu *pcm;
    HRESULT hr = _GetChildUIObjectOf(IID_PPV_ARG(IContextMenu, &pcm));
    if (SUCCEEDED(hr))
    {
        HMENU hpopup = CreatePopupMenu();            
        if (hpopup)
        {
            // SetSite required if you want in place navigation
            IUnknown_SetSite(pcm, m_spClientSite);
            hr = pcm->QueryContextMenu(hpopup, 0, ID_FIRST, ID_LAST, CMF_NORMAL);
            if (SUCCEEDED(hr))
            {
                HWND hwnd;
                hr = _GetHwnd(&hwnd);
                if (SUCCEEDED(hr))
                {
                    UINT idCmd = -1;
                    if (bDefault) // invoke the default verb
                    {
                        idCmd = GetMenuDefaultItem(hpopup, FALSE, GMDI_GOINTOPOPUPS);
                    }
                    else
                    {
                        //
                        // popup the menu and get the command to be executed
                        //
                        POINT point = {nXCord, nYCord};

                        // NTRAID#106655 05-02-2000 arisha
                        // We need to add support to be able to modify the context menu from script.
                        // Below, we make sure we do not remove the "open" verb from the context
                        // menu if we are displaying it in the VIEW_LARGEICONLABEL mode.
                        if (_IsHostWebView() && (m_ViewCurrent != VIEW_LARGEICONLABEL))
                        {
                            hr = ContextMenu_DeleteCommandByName(pcm, hpopup, ID_FIRST, TEXT("open"));
                        }
                        if ((point.x == -1) && (point.y == -1))
                        {
                            _GetCenterPoint(&point);
                        }
                        ::ClientToScreen(hwnd, &point);

                        pcm->QueryInterface(IID_PPV_ARG(IContextMenu3, &m_pcm3));
                        
                        if (SUCCEEDED(_SetupWindow()))
                        {
                            idCmd = TrackPopupMenu(hpopup, TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN, 
                                                       (int)point.x, (int)point.y,
                                                       0, m_msgHwnd, NULL);
                        }
                        if (!IsSafeToDefaultVerb() || 0 == idCmd) // 0 implies user cancelled selection
                        {
                            idCmd = -1;
                        }
                        
                        ATOMICRELEASE(m_pcm3);
                    }    
                    if (idCmd != -1)
                    {
                        CMINVOKECOMMANDINFO cmdInfo = 
                        {
                            sizeof(cmdInfo),
                            0,
                            hwnd,
                            (LPSTR)MAKEINTRESOURCE(idCmd),
                            NULL,
                            NULL,
                            SW_NORMAL
                        };
                        hr = pcm->InvokeCommand(&cmdInfo);                        
                    }
                }                
            }
            IUnknown_SetSite(pcm, NULL);                                
            DestroyMenu(hpopup);            
        }
        pcm->Release();
    }
    return hr;
}


HRESULT CWebViewFolderIcon::OnAmbientPropertyChange(DISPID dispid)
{
    switch (dispid)
    {
    case DISPID_UNKNOWN:
    case DISPID_AMBIENT_FONT:

        // changing the font means we need to recompute our label
        if (m_pszDisplayName)
        {
            CComPtr<IFont> spFont;
            if (SUCCEEDED(GetAmbientFont(&spFont)))
            {
                if (spFont->IsEqual(m_pfont) != S_OK)
                {
                    _ClearAmbientFont();
                    _MakeRoomForLabel();
                }
            }
        }
        // FALL THROUGH

    case DISPID_AMBIENT_BACKCOLOR:
    case DISPID_AMBIENT_FORECOLOR:
        ForceRedraw();
        break;
    }

    return S_OK;
}

COLORREF _TranslateColor(OLE_COLOR oclr)
{
    COLORREF clr;
    if (FAILED(OleTranslateColor(oclr, NULL, &clr)))
        clr = oclr;
    return clr;
}


HRESULT CWebViewFolderIcon::OnDraw(ATL_DRAWINFO& di)
{
    RECT& rc = *(RECT*)di.prcBounds;
    LONG  lImageWidth = _GetScaledImageWidth();
    LONG  lImageHeight = _GetScaledImageHeight();

    // Grab our hdc and rect to be used in _SetDragImage
    if (m_hdc)
    {
        DeleteDC(m_hdc);
    }

    m_hdc = CreateCompatibleDC(di.hdcDraw);

    if (m_hbmDrag)
    {
        DeleteObject(m_hbmDrag);
    }

    m_hbmDrag = CreateCompatibleBitmap(di.hdcDraw, m_lImageWidth, m_lImageHeight);
    m_rect = rc;
    m_fRectAdjusted = 0;

    
    //
    // Draw the folder icon
    //
    if ((m_ViewCurrent == VIEW_THUMBVIEW) || (m_ViewCurrent == VIEW_PIECHART))
    {
        HDC hdc =   di.hdcDraw; 
        HDC         hdcBitmap;
        BITMAP      bm;
        HPALETTE    hpal = NULL;

        ASSERT(hdc);

        // Create pallete appropriate for this HDC
        if (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE)
        {
            hpal = SHCreateShellPalette(hdc);
            HPALETTE hpalOld = SelectPalette(hdc, hpal, TRUE);
            RealizePalette(hdc);

            // Old one needs to be selected back in
            SelectPalette(hdc, hpalOld, TRUE);
        }

        hdcBitmap = CreateCompatibleDC(hdc); 

        if (hdcBitmap)
        {
            //  Draw pie chart
            if (m_ViewCurrent == VIEW_PIECHART)
            {
                DWORD dwPercent1000 = 0;

                if (1) // m_fUseSystemColors.  When do we want this off?
                {
                    // system colors can change!
                    m_ChartColors[PIE_USEDCOLOR] = GetSysColor(COLOR_3DFACE);
                    m_ChartColors[PIE_FREECOLOR] = GetSysColor(COLOR_3DHILIGHT);
                    m_ChartColors[PIE_USEDSHADOW] = GetSysColor(COLOR_3DSHADOW);
                    m_ChartColors[PIE_FREESHADOW] = GetSysColor(COLOR_3DFACE);
                }
                else if (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE)
                {
                    // Call GetNearestColor on the colors to make sure they're on the palette
                    // Of course, system colors ARE on the palette (I think)
                    DWORD dw = 0;       // index
                    for (dw = 0; dw < PIE_NUM; dw++)
                    {
                        m_ChartColors[dw] = GetNearestColor(hdc, m_ChartColors[dw]);
                    }
                }

                if (EVAL((m_ullTotalSpace > 0) && (m_ullFreeSpace <= m_ullTotalSpace)))
                {
                    ComputeSlicePct(m_ullUsedSpace, &dwPercent1000);
                }

                Draw3dPie(hdc, &rc, dwPercent1000, m_ChartColors);
            }
            else    // Draw the Bitmap
            {
                SelectObject(hdcBitmap, m_hbm);
                GetObject(m_hbm, sizeof(bm), &bm);

                //  Bitmap exactly fits the rectangle
                if (bm.bmWidth == rc.right - rc.left && bm.bmHeight == rc.bottom - rc.top)
                {
                    BitBlt(hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, hdcBitmap, 0, 0, SRCCOPY);
                }
                //  Stretch Bitmap to fit the rectangle
                else
                {
                    SetStretchBltMode(hdc, COLORONCOLOR);
                    StretchBlt(hdc, rc.left, rc.top, lImageWidth, lImageHeight, hdcBitmap, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
                }
            }

            DeleteDC(hdcBitmap);
        }
    }
    else if (m_hIcon) 
    {
        DrawIconEx(di.hdcDraw, rc.left, rc.top, m_hIcon, lImageWidth, lImageHeight, 0, 0, DI_NORMAL);
    }

    // Draw the label (if any)
    if (m_pszDisplayName)
    {
        TEXTMETRIC tm;
        TCHAR szFace[32];
        HFONT hFontHilite = NULL;

        //
        // first get the current font properties, there seems to be no straightforward way
        // to just obtain the LOGFONT structure from an HFONT object, so we have to select it
        // to a DC, then obtain the text metrics and use them to create a new font with or
        // without the underline based on m_bHilite value.
        //
        HFONT hfPrev = SelectFont(di.hdcDraw, m_hfAmbient);
        GetTextFace(di.hdcDraw,ARRAYSIZE(szFace), szFace);        
        if (szFace[0] && GetTextMetrics(di.hdcDraw,&tm))
        {
            hFontHilite = CreateFont(tm.tmHeight,
                                              tm.tmAveCharWidth,
                                              0, //Escapement,
                                              0, //Orientation,
                                              tm.tmWeight,
                                              (DWORD) tm.tmItalic,
                                              (DWORD) m_bHilite, // Hilite is by underlining
                                              tm.tmStruckOut,
                                              tm.tmCharSet,
                                              OUT_DEFAULT_PRECIS,
                                              CLIP_DEFAULT_PRECIS,
                                              DEFAULT_QUALITY,
                                              tm.tmPitchAndFamily,
                                              szFace);
            if (hFontHilite)
            {
                SelectFont(di.hdcDraw, hFontHilite);                                  
            }
        }
        
        OLE_COLOR oclrTxt, oclrBk;
        COLORREF clrTxtPrev, clrBkPrev;
        HRESULT hrTxt, hrBk;

        hrTxt = GetAmbientForeColor(oclrTxt);
        if (SUCCEEDED(hrTxt))
            clrTxtPrev = SetTextColor(di.hdcDraw, _TranslateColor(oclrTxt));

        hrBk = GetAmbientBackColor(oclrBk);
        if (SUCCEEDED(hrBk))
            clrBkPrev = SetBkColor(di.hdcDraw, _TranslateColor(oclrBk));

        TextOut(di.hdcDraw, rc.left + lImageWidth + m_cxLabelGap, rc.top + lImageHeight/2 - m_sizLabel.cy/2,
                m_pszDisplayName, lstrlen(m_pszDisplayName));

        if (m_bHasRect)
        {
            RECT rcFocus;
            rcFocus.top = rc.top + lImageHeight/2 - m_sizLabel.cy/2;
            rcFocus.bottom = rcFocus.top + m_sizLabel.cy;
            rcFocus.left = rc.left + lImageWidth + m_cxLabelGap - 1;
            rcFocus.right = rcFocus.left + m_sizLabel.cx + 1;
            DrawFocusRect(di.hdcDraw, &rcFocus);
        }

        if (SUCCEEDED(hrTxt))
            SetTextColor(di.hdcDraw, clrTxtPrev);

        if (SUCCEEDED(hrBk))
            SetBkColor(di.hdcDraw, clrBkPrev);

        SelectFont(di.hdcDraw, hfPrev);

        if (hFontHilite)
        {
            DeleteObject(hFontHilite);
            hFontHilite = NULL;
        }
    }

    return S_OK;
}

HRESULT CWebViewFolderIcon::OnWindowLoad() 
{
    return InitImage();
}

HRESULT CWebViewFolderIcon::OnImageChanged() 
{
    HRESULT hr = InitImage();

    if (SUCCEEDED(hr))
        ForceRedraw();

    return hr;
}

HRESULT CWebViewFolderIcon::OnWindowUnLoad() 
{
    // nothing here now...
    return S_OK;
}

STDMETHODIMP CWebViewFolderIcon::get_scale(BSTR *pbstrScale)
{
    if (S_OK != _IsSafe())
    {
        return E_ACCESSDENIED;
    }
    else
    {
        WCHAR wzScale[MAX_SCALE_STR];

        wnsprintfW(wzScale, ARRAYSIZE(wzScale), L"%d", m_percentScale);

        *pbstrScale = SysAllocString(wzScale);

        return S_OK;
    }
}

STDMETHODIMP CWebViewFolderIcon::put_scale(BSTR bstrScale)
{
    if (S_OK != _IsSafe())
    {
        return E_ACCESSDENIED;
    }
    else
    {
        int numchar = lstrlenW(bstrScale);
        int tempScale = 0;

        if (numchar && bstrScale[numchar-1] == '%')
        {
            tempScale = GetPercentFromStrW(bstrScale);
        }
        else 
        {
            // valid number
            for (int i=0 ; i < (numchar-2) ; i++)
            {
                if (!((bstrScale[i] >= '0') && (bstrScale[i] <= '9')))
                {
                    tempScale = -1;
                    break;
                }
            }

            if ((tempScale != -1) && !StrToIntExW(bstrScale, STIF_DEFAULT, &tempScale))
            {
                tempScale = -1;
            }
        }

        if (tempScale > 0)
        {
            if (m_percentScale != tempScale)
            {
                m_percentScale = tempScale;
                return UpdateSize();
            }
            else
                return S_OK;
        }

        return S_FALSE;
    }
}

STDMETHODIMP CWebViewFolderIcon::get_advproperty(VARIANT_BOOL *pvarbAdvProp)
{
    if (S_OK != _IsSafe())
    {
        return E_ACCESSDENIED;
    }
    else
    {
        *pvarbAdvProp = (VARIANT_BOOL)m_bAdvPropsOn;
    
        return S_OK;
    }

}
    
STDMETHODIMP CWebViewFolderIcon::put_advproperty(VARIANT_BOOL varbAdvProp)
{
    if (S_OK != _IsSafe())
    {
        return E_ACCESSDENIED;
    }
    else
    {
        if (varbAdvProp != m_bAdvPropsOn)
        {
            m_bAdvPropsOn = varbAdvProp;
            return OnImageChanged();
        }

        return S_OK;
    }
}

STDMETHODIMP CWebViewFolderIcon::get_view(BSTR *pbstrView)
{
    if (S_OK != _IsSafe())
    {
        return E_ACCESSDENIED;
    }
    else
    {
        HRESULT hr = S_FALSE;  
        LPCWSTR  pwzTempView;

        switch (m_ViewCurrent)   
        {
            case VIEW_THUMBVIEW:
                {
                    pwzTempView = SZ_THUMB_VIEW;
                    break;
                }
            case VIEW_PIECHART:
                {
                    pwzTempView = SZ_PIE_VIEW;
                    break;
                }
            case VIEW_SMALLICON:
                {
                    pwzTempView = SZ_SMALL_ICON;
                    break;
                }

            case VIEW_SMALLICONLABEL:
                {
                    pwzTempView = SZ_SMALL_ICON_LABEL;
                    break;
                }

            case VIEW_LARGEICONLABEL:
                {
                    pwzTempView = SZ_LARGE_ICON_LABEL;
                    break;
                }

            default:        // default and large icon
                {
                    pwzTempView = SZ_LARGE_ICON;
                    break;
                }
        }

        *pbstrView = SysAllocString(pwzTempView);
        if (*pbstrView)
            hr = S_OK;

        return hr;
    }
}

STDMETHODIMP CWebViewFolderIcon::put_view(BSTR bstrView)
{
    if (S_OK != _IsSafe())
    {
        return E_ACCESSDENIED;
    }
    else
    {
        HRESULT hr = S_OK;
        VIEWS View = VIEW_LARGEICON;

        if (StrCmpIW(bstrView, SZ_LARGE_ICON) == 0)
        {
            View = VIEW_LARGEICON;
        }
        else if (StrCmpIW(bstrView, SZ_SMALL_ICON) == 0)
        {
            View = VIEW_SMALLICON;
        }
        else if (StrCmpIW(bstrView, SZ_SMALL_ICON_LABEL) == 0)
        {
            View = VIEW_SMALLICONLABEL;
        }
        else if (StrCmpIW(bstrView, SZ_LARGE_ICON_LABEL) == 0)
        {
            View = VIEW_LARGEICONLABEL;
        }
        else if (StrCmpIW(bstrView, SZ_THUMB_VIEW) == 0)
        {
            View = VIEW_THUMBVIEW;
        }
        else if (StrCmpIW(bstrView, SZ_PIE_VIEW) == 0)
        {
            View = VIEW_PIECHART;
        }
        else
            hr = S_FALSE;
        
        if ((S_OK == hr) && (m_ViewUser != View))
        {
            m_ViewUser = View;

            hr = OnImageChanged();
        }

        return hr;
    }
}


/**************************************************************\
    DESCRIPTION:
        The caller is getting the path of our control.

    SECURITY:
        We only trust callers from safe pages.  This method
    secifically worries about untrusted callers using us to
    find out what paths on the file system exists or don't exist.  
\**************************************************************/
STDMETHODIMP CWebViewFolderIcon::get_path(BSTR *pbstrPath)
{
    AssertMsg((NULL != m_spClientSite.p), TEXT("CWebViewFolderIcon::get_path() We need m_spClientSite for our security test and it's NULL. BAD, BAD, BAD!"));
    HRESULT hr;

    if (S_OK != _IsSafe())
    {
        // We don't trust this host, so we are going to not carry
        // out the action.  We are going to return E_ACCESSDENIED so they can't
        // determine if the path exists or not.
        hr = E_ACCESSDENIED;
    }
    else
    {
        LPITEMIDLIST pidlFull;

        hr = S_FALSE;
        *pbstrPath = NULL;
        if (S_OK == _GetFullPidl(&pidlFull))
        {
            WCHAR wzPath[INTERNET_MAX_URL_LENGTH];

            if (S_OK == SHGetNameAndFlagsW(pidlFull, SHGDN_FORPARSING, wzPath, ARRAYSIZE(wzPath), NULL))
            {
                *pbstrPath = SysAllocString(wzPath);  
                if (*pbstrPath)
                    hr = S_OK;
            }

            ILFree(pidlFull);
        }
    }
    
    return hr;
}


/**************************************************************\
    DESCRIPTION:
        The caller is setting the path of our control.  Our
    control will render a view of this item, which is often and
    icon.  

    SECURITY:
        We only trust callers from safe pages.  This method
    secifically worries about untrusted callers using us to
    find out what paths on the file system exists or don't exist.  
\**************************************************************/
STDMETHODIMP CWebViewFolderIcon::put_path(BSTR bstrPath)
{
    AssertMsg((NULL != m_spClientSite.p), TEXT("CWebViewFolderIcon::put_path() We need m_spClientSite for our security test and it's NULL. BAD, BAD, BAD!"));
    HRESULT hr;

    if (S_OK != _IsSafe())
    {
        // We don't trust this host, so we are going to not carry
        // out the action.  We are going to return E_ACCESSDENIED so they can't
        // determine if the path exists or not.
        hr = E_ACCESSDENIED;
    }
    else
    {
        hr = S_FALSE;
        LPITEMIDLIST pidlNew;
    
        hr = IEParseDisplayNameW(CP_ACP, bstrPath, &pidlNew);
        if (SUCCEEDED(hr))
        {
            ATOMICRELEASE(m_pDropTargetCache);      // We will want another IDropTarget for this new pidl.
            ILFree(m_pidl);
            m_pidl = pidlNew;

            hr = OnImageChanged();
            AssertMsg(SUCCEEDED(hr), TEXT("CWebViewFolderIcon::put_path() failed to create the image so the image will be incorrect.  Please find out why."));

            hr = S_OK;
        }
    }
    
    return hr;
}


// Automation methods to get/put FolderItem objects from FolderIcon
STDMETHODIMP CWebViewFolderIcon::get_item(FolderItem ** ppFolderItem)
{   
    HRESULT hr;
    if (S_OK != _IsSafe())
    {
        // We don't trust this host, so we are going to not carry
        // out the action.  We are going to return E_ACCESSDENIED so they can't
        // determine if the path exists or not.
        hr = E_ACCESSDENIED;
    }
    else
    {
        LPITEMIDLIST pidlFull;

        *ppFolderItem = NULL;
        hr = _GetFullPidl(&pidlFull);
        if ((hr == S_OK) && pidlFull)
        {
            IShellDispatch * psd;

            hr = CoCreateInstance(CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellDispatch, &psd));
            if (SUCCEEDED(hr))
            {
                IObjectSafety * pos;

                hr = psd->QueryInterface(IID_PPV_ARG(IObjectSafety, &pos));
                if (SUCCEEDED(hr))
                {
                    // Simulate what trident does.
                    hr = pos->SetInterfaceSafetyOptions(IID_IDispatch, INTERFACESAFE_FOR_UNTRUSTED_CALLER, INTERFACESAFE_FOR_UNTRUSTED_CALLER);

                    if (SUCCEEDED(hr))
                    {
                        VARIANT varDir;

                        hr = InitVariantFromIDList(&varDir, pidlFull);
                        if (SUCCEEDED(hr))
                        {
                            IObjectWithSite * pows;

                            hr = psd->QueryInterface(IID_PPV_ARG(IObjectWithSite, &pows));
                            if (SUCCEEDED(hr))
                            {
                                Folder *psdf;
                            
                                // If we call ::SetSite(), they will display UI to ask the user if they want to allow this.
                                // This is annoying because Trident will always call our get_item() when they load our object
                                // tag.
                                pows->SetSite(m_spClientSite);
                                hr = psd->NameSpace(varDir, &psdf);
                                if (S_OK == hr)
                                {
                                    Folder2 *psdf2;

                                    hr = psdf->QueryInterface(IID_PPV_ARG(Folder2, &psdf2));
                                    if (S_OK == hr)
                                    {
                                        hr = psdf2->get_Self(ppFolderItem);
                                        psdf2->Release();
                                    }

                                    psdf->Release();
                                }

                                pows->SetSite(NULL);
                                pows->Release();
                            }

                            VariantClear(&varDir);
                        }
                    }
                    pos->Release();
                }

                psd->Release();
            }

            ILFree(pidlFull);
        }
        
        // Automation method can't fail or hard script error.  We do want a hard
        // script error on access denied, however.
        if (FAILED(hr) && (hr != E_ACCESSDENIED))
        {
            hr = S_FALSE;
        }
    }
    return hr;
}


STDMETHODIMP CWebViewFolderIcon::put_item(FolderItem * pFolderItem)
{
    HRESULT hr;
    if (S_OK != _IsSafe())
    {
        // We don't trust this host, so we are going to not carry
        // out the action.  We are going to return E_ACCESSDENIED so they can't
        // determine if the path exists or not.
        hr = E_ACCESSDENIED;
    }
    else
    {
        hr = S_FALSE;
        
        LPITEMIDLIST pidlNew;
        if (S_OK == SHGetIDListFromUnk(pFolderItem, &pidlNew))
        {
            ATOMICRELEASE(m_pDropTargetCache);      // We will want another IDropTarget for this new pidl.
            ILFree(m_pidl);
            m_pidl = pidlNew;

            hr = OnImageChanged();
            if (FAILED(hr))
            {
                hr = S_FALSE;
            }
        }
    }
    return hr;
}

STDMETHODIMP CWebViewFolderIcon::get_clickStyle(LONG *plClickStyle)
{
    if (S_OK != _IsSafe())
    {
        return E_ACCESSDENIED;
    }
    else
    {
        *plClickStyle = m_clickStyle;
        return S_OK;
    }
}

STDMETHODIMP CWebViewFolderIcon::put_clickStyle(LONG lClickStyle)
{
    if (S_OK != _IsSafe())
    {
        return E_ACCESSDENIED;
    }
    else
    {
        switch (lClickStyle)
        {
        case 1:         /* oneclick - weblike */
        case 2:         /* twoclick - explorer-like */
            m_clickStyle = lClickStyle;
            break;

        default:        /* Ignore invalid arguments to keep script happy */
            break;

        }

        return S_OK;
    }
}

STDMETHODIMP CWebViewFolderIcon::get_labelGap(LONG *plLabelGap)
{
    if (S_OK != _IsSafe())
    {
        return E_ACCESSDENIED;
    }
    else
    {
        *plLabelGap = m_cxLabelGap;
        return S_OK;
    }
}

STDMETHODIMP CWebViewFolderIcon::put_labelGap(LONG lLabelGap)
{
    if (S_OK != _IsSafe())
    {
        return E_ACCESSDENIED;
    }
    else
    {
        if (m_cxLabelGap != lLabelGap)
        {
            m_cxLabelGap = lLabelGap;
            UpdateSize();
        }
        return S_OK;
    }
}


STDMETHODIMP CWebViewFolderIcon::setSlice(int index, VARIANT varHiBytes, VARIANT varLoBytes, VARIANT varColorref)
{
    HRESULT     hr = S_FALSE;
    PieSlice_S  pieSlice;

    if ((varHiBytes.vt == VT_I4) && (varLoBytes.vt == VT_I4))
        pieSlice.MemSize = GetUllMemFromVars(&varHiBytes, &varLoBytes);
 
    // Passed a COLORREF
    if (varColorref.vt == VT_I4) 
    {
        pieSlice.Color = (COLORREF)varColorref.lVal;
    }
    // Passed a string
    else if (varColorref.vt == VT_BSTR)
        pieSlice.Color = ColorRefFromHTMLColorStrW(varColorref.bstrVal);
    else
        return hr;

    if (DSA_SetItem(m_hdsaSlices, index, &pieSlice))
    {
        if (index > (m_highestIndexSlice - 1))
            m_highestIndexSlice = (index + 1);
        hr = OnImageChanged();
    }

    return hr;
}

/////////////////////////////////////////////////////////////////////////////
// IObjectSafetyImpl overrides

STDMETHODIMP CWebViewFolderIcon::SetInterfaceSafetyOptions(REFIID riid, 
                                                           DWORD dwOptionSetMask, 
                                                           DWORD dwEnabledOptions)
{
    // If we're being asked to set our safe for scripting option then oblige
    if (riid == IID_IDispatch || riid == IID_IPersistPropertyBag)
    {
        // Store our current safety level to return in GetInterfaceSafetyOptions
        m_dwCurrentSafety = dwEnabledOptions & dwOptionSetMask;
        return S_OK;
    }
    return E_NOINTERFACE;
}


// Handle Window messages for the thumbnail bitmap
LRESULT CALLBACK CWebViewFolderIcon::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    CWebViewFolderIcon *ptc = (CWebViewFolderIcon *)::GetWindowLongPtr(hwnd, GWLP_USERDATA);

    switch(uMsg)
    {
    case WM_CREATE:
        {
            ptc = (CWebViewFolderIcon *)((CREATESTRUCT *)lParam)->lpCreateParams;
            ::SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM)ptc);
        }
        break;

    // NOTE: do not need to check to see that the bitmap coming through is the one you want since each control has its own
    // message wnd.
    case WM_HTML_BITMAP:
        // check that ptc is still alive and that you have an HBITMAP
        if (ptc && (ptc->m_dwThumbnailID == wParam))
        {
            if (ptc->m_hbm != NULL)
            {
                DeleteObject(ptc->m_hbm);
            }

            ptc->m_hbm = (HBITMAP)lParam;
            ptc->_InvokeOnThumbnailReady();
            ptc->ForceRedraw();
        }
        else if (lParam)
        {
            DeleteObject((HBITMAP)lParam);
        }
        break;

    case WM_MEASUREITEM:
    case WM_DRAWITEM:
    case WM_INITMENUPOPUP:
        if (ptc && ptc->m_pcm3)
            ptc->m_pcm3->HandleMenuMsg(uMsg, wParam, lParam);
        break;

    case WM_DESTROY:
        // ignore late messages
        if (ptc)
        {
            MSG msg;

            while(PeekMessage(&msg, hwnd, WM_HTML_BITMAP, WM_HTML_BITMAP, PM_REMOVE))
            {
                if (msg.lParam)
                {
                    DeleteObject((HBITMAP)msg.lParam);
                }
            }
            ::SetWindowLongPtr(hwnd, GWLP_USERDATA, NULL);
        }
        break;
     
    default:
        return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
    }

    return 0;
}


//  Pie chart functions

HRESULT CWebViewFolderIcon::ComputeFreeSpace(LPCWSTR pszFileName)
{
    return _ComputeFreeSpace(pszFileName, m_ullFreeSpace,
        m_ullUsedSpace, m_ullTotalSpace);
}

// Draw3dPie draws the pie chart with the used slice and the additional slices in m_hdsaSlices
// Look in drawpie.c for the majority of the code (including member functions called within this one)
HRESULT CWebViewFolderIcon::Draw3dPie(HDC hdc, LPRECT lprc, DWORD dwPercent1000, const COLORREF *pColors)
{
    LONG ShadowDepth;

    ASSERT(lprc != NULL && pColors != NULL);

    const LONG c_ShadowScale = 6;       // ratio of shadow depth to height
    const LONG c_AspectRatio = 2;      // ratio of width : height of ellipse

    ScalePieRect(c_ShadowScale, c_AspectRatio, lprc);

    // Compute a shadow depth based on height of the image
    ShadowDepth = (lprc->bottom - lprc->top) / c_ShadowScale;

    // Check dwPercent1000 to ensure within bounds.  Shouldn't be but check anyway.
    // dwPercent1000 is the percentage of used space based out of 1000.
    if (dwPercent1000 > 1000)
        dwPercent1000 = 1000;

    // Now the drawing portion

    RECT rcItem;
    int     cx, cy;             // Center of the pie
    int     rx, ry;             // Center of the rectangle
    int     x, y;               // Radial intersection of the slices
    int     FirstQuadPercent1000;

    // Set up the pie rectangle
    rcItem = *lprc;
    rcItem.left = lprc->left;
    rcItem.top = lprc->top;
    rcItem.right = lprc->right - rcItem.left;
    rcItem.bottom = lprc->bottom - rcItem.top - ShadowDepth;

    SetUpPiePts(&cx, &cy, &rx, &ry, rcItem);

    if ((rx <= 10) || (ry <= 10))
    {
        return S_FALSE;
    }

    // Make the rectangle a little more accurate
    rcItem.right = (2 * rx) + rcItem.left;
    rcItem.bottom = (2 * ry) + rcItem.top;

    // Translate the used percentage to first quadrant
    FirstQuadPercent1000 = (dwPercent1000 % 500) - 250;

    if (FirstQuadPercent1000 < 0)
    {
        FirstQuadPercent1000 = -FirstQuadPercent1000;
    }    

    // Find the slice intersection for the used slice
    CalcSlicePoint(&x, &y, rx, ry, cx, cy, FirstQuadPercent1000, dwPercent1000);

    DrawEllipse(hdc, rcItem, x, y, cx, cy, dwPercent1000, pColors);

    // Used pie slice.
    DrawSlice(hdc, rcItem, dwPercent1000, rx, ry, cx, cy, pColors[COLOR_UP]);

    // Iterate through and draw the slices in m_hdsaSlices.
    PieSlice_S  pieSlice;          
    ULONGLONG   ullMemTotal = 0;    // Keep track of memory in the m_hdsaSlices slices        
    DWORD       dwPercentTotal;     // 1000 Percentage of memory in slices
    for (int i=0; i < m_highestIndexSlice; i++)
    {
        if (DSA_GetItemPtr(m_hdsaSlices, i) != NULL)
        {
            DSA_GetItem(m_hdsaSlices, i, &pieSlice);
            ullMemTotal += pieSlice.MemSize;
        }
    }

    ComputeSlicePct(ullMemTotal, &dwPercentTotal);

    if (m_highestIndexSlice)
    {
        for (i = (m_highestIndexSlice - 1); i >= 0; i--)
        {
            if (DSA_GetItemPtr(m_hdsaSlices, i))
            {
                DSA_GetItem(m_hdsaSlices, i, &pieSlice);
                DrawSlice(hdc, rcItem, dwPercentTotal, rx, ry, cx, cy, pieSlice.Color); 
                ullMemTotal -= pieSlice.MemSize;
                ComputeSlicePct(ullMemTotal, &dwPercentTotal);
            }
        }
    }

    DrawShadowRegions(hdc, rcItem, lprc, x, cy, ShadowDepth, dwPercent1000, pColors);

    DrawPieDepth(hdc, rcItem, x, y, cy, dwPercent1000, ShadowDepth);

    // Redraw the bottom line of the pie because it has been painted over
    Arc(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom,
        rcItem.left, cy, rcItem.right, cy);

    return S_OK;    // Everything worked fine
} 


void CWebViewFolderIcon::ScalePieRect(LONG ShadowScale, LONG AspectRatio, LPRECT lprc)
{
    LONG rectHeight;
    LONG rectWidth;
    LONG TargetHeight;
    LONG TargetWidth;

    // We make sure that the aspect ratio of the pie-chart is always preserved 
    // regardless of the shape of the given rectangle

    // Stabilize the aspect ratio
    rectHeight = lprc->bottom - lprc->top;
    rectWidth = lprc->right - lprc->left;
   
    if ((rectHeight * AspectRatio) <= rectWidth)
        TargetHeight = rectHeight;
    else
        TargetHeight = rectWidth / AspectRatio;
    
    TargetWidth = TargetHeight * AspectRatio;

    // Shrink the rectangle to the correct size
    lprc->top += (rectHeight - TargetHeight) / 2;
    lprc->bottom = lprc->top + TargetHeight;
    lprc->left += (rectWidth - TargetWidth) / 2;
    lprc->right = lprc->left + TargetWidth;
}

// Calculate center of rectangle and center of pie points
void CWebViewFolderIcon::SetUpPiePts(int *pcx, int *pcy, int *prx, int *pry, RECT rect)
{
    *prx = rect.right / 2;
    *pcx = rect.left + *prx - 1;
    *pry = rect.bottom / 2;
    *pcy = rect.top + *pry - 1;
}

void CWebViewFolderIcon::DrawShadowRegions(HDC hdc, RECT rect, LPRECT lprc, int UsedArc_x, int center_y,  
                                           LONG ShadowDepth, DWORD dwPercent1000, const COLORREF *pColors) 
{
    HBRUSH  hBrush;

    HRGN hEllipticRgn = CreateEllipticRgnIndirect(&rect);
    HRGN hEllRect = CreateRectRgn(rect.left, center_y, rect.right, center_y + ShadowDepth);
    HRGN hRectRgn = CreateRectRgn(0, 0, 0, 0);

    //  Move the ellipse up so it doesn't run into the shadow
    OffsetRgn(hEllipticRgn, 0, ShadowDepth);

    // Union the Ellipse and the Ellipse rect together into hRectRegn
    CombineRgn(hRectRgn, hEllipticRgn, hEllRect, RGN_OR);
    OffsetRgn(hEllipticRgn, 0, -(int)ShadowDepth);
    CombineRgn(hEllRect, hRectRgn, hEllipticRgn, RGN_DIFF);

    // Always draw the whole area in the free shadow
    hBrush = CreateSolidBrush(pColors[COLOR_DNSHADOW]);
    if (hBrush)
    {
        FillRgn(hdc, hEllRect, hBrush);
        DeleteObject(hBrush);
    }

    // Draw a shadow for the used section only if the disk is at least half used
    hBrush = CreateSolidBrush(pColors[COLOR_UPSHADOW]);
    if ((dwPercent1000 > 500) && hBrush)
    {
        DeleteObject(hRectRgn);
        hRectRgn = CreateRectRgn(UsedArc_x, center_y, rect.right, lprc->bottom);
        CombineRgn(hEllipticRgn, hEllRect, hRectRgn, RGN_AND);
        FillRgn(hdc, hEllipticRgn, hBrush);
        DeleteObject(hBrush);
    }

    DeleteObject(hRectRgn);
    DeleteObject(hEllipticRgn);
    DeleteObject(hEllRect);
}

void CWebViewFolderIcon::CalcSlicePoint(int *x, int *y, int rx, int ry, int cx, int cy, int FirstQuadPercent1000, DWORD dwPercent1000)
{
    // Use a triangle area approximation based on the ellipse's rect to calculate the point since
    // an exact calculation of the area of the slice and percentage of the pie would be costly and
    // a hassle.

    // The approximation is better this way if FirstQuadPercent1000 is in the first half of the quadrant.  Use 120 as the
    // halfway point (instead of 125) because it looks better that way on an ellipse. 

    if (FirstQuadPercent1000 < 120)
    {
        *x = IntSqrt(((DWORD)rx*(DWORD)rx*(DWORD)FirstQuadPercent1000*(DWORD)FirstQuadPercent1000)
            /((DWORD)FirstQuadPercent1000*(DWORD)FirstQuadPercent1000+(250L-(DWORD)FirstQuadPercent1000)
            *(250L-(DWORD)FirstQuadPercent1000)));

        *y = IntSqrt(((DWORD)rx*(DWORD)rx-(DWORD)(*x)*(DWORD)(*x))*(DWORD)ry*(DWORD)ry/((DWORD)rx*(DWORD)rx));
    }
    else
    {
        *y = IntSqrt((DWORD)ry*(DWORD)ry*(250L-(DWORD)FirstQuadPercent1000)*(250L-(DWORD)FirstQuadPercent1000)
            /((DWORD)FirstQuadPercent1000*(DWORD)FirstQuadPercent1000+(250L-(DWORD)FirstQuadPercent1000)
            *(250L-(DWORD)FirstQuadPercent1000)));

        *x = IntSqrt(((DWORD)ry*(DWORD)ry-(DWORD)(*y)*(DWORD)(*y))*(DWORD)rx*(DWORD)rx/((DWORD)ry*(DWORD)ry));
    }

    // Adjust for the actual quadrant (These aren't quadrants like in the real Cartesian coordinate system.
    switch (dwPercent1000 / 250)
    {
    case 1:         // First Quadrant
        *y = -(*y); 
        break;

    case 2:         // Second Quadrant 
        break;

    case 3:         // Third Quadrant
        *x = -(*x);
        break;

    default:        // Fourth Quadrant
        *x = -(*x);
        *y = -(*y);
        break;
    }

    // Now adjust for the center.
    *x += cx;
    *y += cy;
}

void CWebViewFolderIcon::ComputeSlicePct(ULONGLONG ullMemSize, DWORD *pdwPercent1000)
{
    // some special cases require interesting treatment
    if ((ullMemSize == 0) || (m_ullFreeSpace == m_ullTotalSpace))
    {
        *pdwPercent1000 = 0;
    }
    else if (ullMemSize == 0)
    {
        *pdwPercent1000 = 1000;
    }
    else
    {
        // not completely full or empty
        *pdwPercent1000 = (DWORD)(ullMemSize * 1000 / m_ullTotalSpace);

        // if pdwPercent1000 is especially big or small and rounds incorrectly, you still want
        // to see a little slice.
        if (*pdwPercent1000 == 0)
        {
            *pdwPercent1000 = 1;
        }
        else if (*pdwPercent1000 == 1000)
        {
            *pdwPercent1000 = 999;
        }
    }
}

void CWebViewFolderIcon::DrawPieDepth(HDC hdc, RECT rect, int x, int y, int cy, DWORD dwPercent1000, LONG ShadowDepth)
{
    HPEN hPen, hOldPen;

    hPen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_WINDOWFRAME));
    hOldPen = (HPEN__*) SelectObject(hdc, hPen);

    Arc(hdc, rect.left, rect.top + ShadowDepth, rect.right, rect.bottom + ShadowDepth,
        rect.left, cy + ShadowDepth, rect.right, cy + ShadowDepth - 1);
    MoveToEx(hdc, rect.left, cy, NULL);
    LineTo(hdc, rect.left, cy + ShadowDepth);
    MoveToEx(hdc, rect.right - 1, cy, NULL);
    LineTo(hdc, rect.right - 1, cy + ShadowDepth);

    if ((dwPercent1000 > 500) && (dwPercent1000 < 1000))
    {
        MoveToEx(hdc, x, y, NULL);
        LineTo(hdc, x, y + ShadowDepth);
    }

    SelectObject(hdc, hOldPen);
    DeleteObject(hPen);
}

// Draw a pie slice.  One side is always from the middle of the pie horizontally to the left.  The other
// slice is defined by x and y.
void CWebViewFolderIcon::DrawSlice(HDC hdc, RECT rect, DWORD dwPercent1000, int rx, int ry, int cx, int cy, /*int *px, int *py,*/
                                   COLORREF Color)
{
    HBRUSH  hBrush, hOldBrush;
    HPEN    hPen, hOldPen;
    int     FirstQuadPercent1000;   // slice percentage based out of 1000 in the first quadrant
    int     x, y;                   // intersection with the ellipse

    // Translate to first quadrant
    FirstQuadPercent1000 = (dwPercent1000 % 500) - 250;

    if (FirstQuadPercent1000 < 0)
    {
        FirstQuadPercent1000 = -FirstQuadPercent1000;
    }
    
    CalcSlicePoint(&x, &y, rx, ry, cx, cy, FirstQuadPercent1000, dwPercent1000);

    hPen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_WINDOWFRAME));
    hOldPen = (HPEN__*) SelectObject(hdc, hPen);

    if ((dwPercent1000 != 0) && (dwPercent1000 != 1000))
    {
        // display small sub-section of ellipse for smaller part
        hBrush = CreateSolidBrush(Color);
        hOldBrush = (HBRUSH__*) SelectObject(hdc, hBrush);

        //  Make sure it colors correctly
        if (cy == y)
        {
            if (dwPercent1000 < 500)
                y--;
            else
                y++;
        }

        Pie(hdc, rect.left, rect.top, rect.right, rect.bottom,
            x, y, rect.left, cy);
        SelectObject(hdc, hOldBrush);
        DeleteObject(hBrush);
    }

    SelectObject(hdc, hOldPen);
    DeleteObject(hPen);
}

void CWebViewFolderIcon::DrawEllipse(HDC hdc, RECT rect, int x, int y, int cx, int cy, DWORD dwPercent1000, const COLORREF *pColors)
{
    HBRUSH  hBrush, hOldBrush;

    HPEN hPen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_WINDOWFRAME));
    HPEN hOldPen = (HPEN__*) SelectObject(hdc, hPen);

    // In this case the slice is miniscule
    if ((dwPercent1000 < 500) && (y == cy) && (x < cx))
    {
        hBrush = CreateSolidBrush(pColors[COLOR_UP]);
    }
    else
    {
        hBrush = CreateSolidBrush(pColors[COLOR_DN]);
    }

    hOldBrush = (HBRUSH__*) SelectObject(hdc, hBrush);

    Ellipse(hdc, rect.left, rect.top, rect.right, rect.bottom);

    SelectObject(hdc, hOldBrush);
    DeleteObject(hBrush);

    SelectObject(hdc, hOldPen);
    DeleteObject(hPen);
}
