/*
 * isexicon.cpp - IExtractIcon implementation for URL class.
 */


#include "priv.h"
#include "htregmng.h"
#include "ishcut.h"
#include "resource.h"


// We still have to use url.dll as the source of the internet shortcut
// icons because the icons need to still be valid on uninstall.

#ifndef UNIX
#define c_szIntshcutDefaultIcon     TEXT("url.dll")
#else
// IEUNIX(perf) : use unixstyle dll name
#ifdef ux10 
#define c_szIntshcutDefaultIcon     TEXT("liburl.sl")
#else
#define c_szIntshcutDefaultIcon     TEXT("liburl.so")
#endif
#endif

#define IDEFICON_NORMAL             0

#define II_OVERLAY_UPDATED          1

typedef struct
    {
    HIMAGELIST himl;          
    HIMAGELIST himlSm;
    } URLIMAGES;

HRESULT
URLGetLocalFileName(
    LPCTSTR pszURL,
    LPTSTR szLocalFile,
    int cch,
    FILETIME* pftLastMod);


/*----------------------------------------------------------
Purpose: Initializes the images lists used by the URL icon  
         handler.

         There are just two icons placed in each imagelist:
         the given hicon and an overlay for the updated
         asterisk.

Returns: 
Cond:    --
*/
STDMETHODIMP
InitURLImageLists(
    IN URLIMAGES * pui,
    IN HICON       hicon,
    IN HICON       hiconSm)
    {
    HRESULT hres = E_OUTOFMEMORY;

    LoadCommonIcons();
    _InitSysImageLists();

    pui->himl = ImageList_Create(g_cxIcon, g_cyIcon, ILC_MASK, 2, 2);
    
    if (pui->himl)
    {
        pui->himlSm = ImageList_Create(g_cxSmIcon, g_cySmIcon, ILC_MASK, 2, 2);
        
        if ( !pui->himlSm ) 
            ImageList_Destroy(pui->himl);
        else
        {
            ImageList_SetBkColor(pui->himl, GetSysColor(COLOR_WINDOW));
            ImageList_SetBkColor(pui->himlSm, GetSysColor(COLOR_WINDOW));
         
            // Add the given icons
            ImageList_ReplaceIcon(pui->himl, -1, hicon);
            ImageList_ReplaceIcon(pui->himlSm, -1, hiconSm);

            // Add the overlay icon to the list
            ASSERT(IS_VALID_HANDLE(g_hiconSplat, ICON));
            ASSERT(IS_VALID_HANDLE(g_hiconSplatSm, ICON));

            if (g_hiconSplat)
            {
                int iOverlay = ImageList_ReplaceIcon(pui->himl, -1, g_hiconSplat);
                ImageList_ReplaceIcon(pui->himlSm, -1, g_hiconSplatSm);

                ImageList_SetOverlayImage(pui->himl, iOverlay, II_OVERLAY_UPDATED);
                ImageList_SetOverlayImage(pui->himlSm, iOverlay, II_OVERLAY_UPDATED);
            }
            
            hres = S_OK;
        }
    }

    return hres;
    }


/*----------------------------------------------------------
Purpose: Destroys the url image lists

Returns: 
Cond:    --
*/
STDMETHODIMP
DestroyURLImageLists(
    IN URLIMAGES * pui)
{
    if (pui->himl)       
    {
        ImageList_Destroy(pui->himl);
        pui->himl = NULL;
    }

    if (pui->himlSm)       
    {
        ImageList_Destroy(pui->himlSm);
        pui->himlSm = NULL;
    }

    return S_OK;
}



/*----------------------------------------------------------
Purpose: Gets the icon location (filename and index) from the registry
         of the given key.

Returns: 
Cond:    --
*/
HRESULT 
GetURLIcon(
    IN  HKEY    hkey, 
    IN  LPCTSTR pcszKey, 
    IN  LPTSTR  pszIconFile,
    IN  UINT    cchIconFile, 
    OUT PINT    pniIcon)
{
    HRESULT hres = S_FALSE;
    DWORD dwSize = CbFromCch(cchIconFile);

    ASSERT(IS_VALID_HANDLE(hkey, KEY));
    ASSERT(IS_VALID_STRING_PTR(pcszKey, -1));
    ASSERT(IS_VALID_WRITE_BUFFER(pszIconFile, TCHAR, cchIconFile));
    ASSERT(IS_VALID_WRITE_PTR(pniIcon, INT));

    if (NO_ERROR == SHGetValue(hkey, pcszKey, NULL, NULL, pszIconFile, &dwSize))
    {
        *pniIcon = PathParseIconLocation(pszIconFile);
        hres = S_OK;
    }

    ASSERT(IsValidIconIndex(hres, pszIconFile, cchIconFile, *pniIcon));

    return hres;
}


/*
** GetFallBackGenericURLIcon()
**
**
**
** Arguments:
**
** Returns:       S_OK if fallback generic icon information retrieved
**                successfully.
**                E_FAIL if not.
**
** Side Effects:  none
*/
HRESULT 
GetFallBackGenericURLIcon(
    LPTSTR pszIconFile,
    UINT cchIconFile,
    PINT pniIcon)
{
    HRESULT hr;

    ASSERT(IS_VALID_WRITE_BUFFER(pszIconFile, TCHAR, cchIconFile));
    ASSERT(IS_VALID_WRITE_PTR(pniIcon, INT));

    // Fall back to first icon in this module.

    StrCpyN(pszIconFile, c_szIntshcutDefaultIcon, cchIconFile);
    *pniIcon = IDEFICON_NORMAL;

    hr = S_OK;

    TraceMsg(TF_INTSHCUT, "GetFallBackGenericURLIcon(): Using generic URL icon file %s, index %d.",
              pszIconFile, *pniIcon);

    ASSERT(IsValidIconIndex(hr, pszIconFile, cchIconFile, *pniIcon));

    return(hr);
}


/*
** GetGenericURLIcon()
**
**
**
** Arguments:
**
** Returns:       S_OK if generic icon information retrieved successfully.
**                Otherwise error.
**
** Side Effects:  none
*/
HRESULT 
GetGenericURLIcon(
    LPTSTR pszIconFile,
    UINT cchIconFile, 
    PINT pniIcon)
{
    HRESULT hr;

    ASSERT(IS_VALID_WRITE_BUFFER(pszIconFile, TCHAR, cchIconFile));
    ASSERT(IS_VALID_WRITE_PTR(pniIcon, INT));

    hr = GetURLIcon(HKEY_CLASSES_ROOT, TEXT("InternetShortcut\\DefaultIcon"), pszIconFile,
                    cchIconFile, pniIcon);

    if (hr == S_FALSE)
        hr = GetFallBackGenericURLIcon(pszIconFile, cchIconFile, pniIcon);

    ASSERT(IsValidIconIndex(hr, pszIconFile, cchIconFile, *pniIcon));

    return(hr);
}


/****************************** Public Functions *****************************/


/*----------------------------------------------------------
Purpose: Given a full URL path, this function returns the 
         registry path to the associated protocol (plus the
         subkey path).

         pszBuf must be MAX_PATH.

Returns: 
Cond:    --
*/
HRESULT 
GetURLKey(
    LPCTSTR pcszURL, 
    LPCTSTR pszSubKey, 
    LPTSTR  pszBuf,
    int cchBuf)
{
    HRESULT hres;
    PTSTR pszProtocol;

    ASSERT(IS_VALID_STRING_PTR(pcszURL, -1));
    ASSERT(IS_VALID_STRING_PTR(pszSubKey, -1));
    ASSERT(IS_VALID_WRITE_BUFFER(pszBuf, TCHAR, MAX_PATH));

    *pszBuf = '\0';

    hres = CopyURLProtocol(pcszURL, &pszProtocol, NULL);

    if (hres == S_OK)
    {
        StrCpyN(pszBuf, pszProtocol, cchBuf);
        PathAppend(pszBuf, pszSubKey);

        LocalFree(pszProtocol);
        pszProtocol = NULL;
    }

    return hres;
}


/********************************** Methods **********************************/

/*----------------------------------------------------------
Purpose : To help determine if the file to which this shortcut
          is persisted is in the favorites hierarchy
          
Returns : Returns TRUE if this shortcut is in the favorites 
         folder
*/


BOOL Intshcut::_IsInFavoritesFolder()
{
    BOOL fRet = FALSE;

    if(m_pszFile)
    {
        TCHAR szPath[MAX_PATH];
        if(SHGetSpecialFolderPath(NULL, szPath, CSIDL_FAVORITES, TRUE))
        {
            // Is szPath (i.e. the favorites dir) a prefix of the file associated with this
            // shortcut ?
            fRet = PathIsPrefix(szPath, m_pszFile);
        }
    }

    return fRet;
    
}
         
/*----------------------------------------------------------
Purpose: Get the icon location of the given url.

Returns: S_FALSE if the location is default for the type
         S_OK if the location is custom

         The way this extracticon stuff works is very strange and not
         well-documented.  In particular, there are multiple levels of
         name munging going on, and it's not clear how information is
         passed between IExtractIcon::GetIconLocation and
         IExtractIcon::Extract.  (In particular, it seems that we maintain
         state in our object in order to do secret communication between
         the two methods, which is out of spec.  The shell is allowed to
         instantiate you, call GetIconLocation, then destroy you.  Then
         the next day, it can instantiate you and call Extract with the
         result from yesterday's GetIconLocation.)

         I'm not going to try to fix it; I'm just
         pointing it out in case somebody has to go debugging into this
         code and wonders what is going on.

Cond:    --
*/
STDMETHODIMP
Intshcut::GetURLIconLocation(
    IN  UINT    uInFlags,
    IN  LPTSTR  pszBuf,
    IN  UINT    cchBuf,
    OUT int *   pniIcon,
    BOOL fRecentlyChanged,
    OUT PUINT  puOutFlags)
{
    // Call the IShellLink::GetIconLocation method
    HRESULT hres = _GetIconLocationWithURLHelper(pszBuf, cchBuf, pniIcon, NULL, 0, fRecentlyChanged);
    BOOL fNeedQualify = TRUE;
    hres = S_FALSE;
    if (*pszBuf)
    {
        if(puOutFlags && (FALSE == PathFileExists(pszBuf)))
            SetFlag(*puOutFlags, GIL_NOTFILENAME);
    }
    else
    {
        
        if(FALSE == _IsInFavoritesFolder() || (IsIEDefaultBrowserQuick()))
        {
            // This shortcut is not in the favorites folder as far as we know 
            TCHAR szURL[INTERNET_MAX_URL_LENGTH];

            *szURL = 0;

            hres = InitProp();
            if (SUCCEEDED(hres))
                m_pprop->GetProp(PID_IS_URL, szURL, SIZECHARS(szURL));

            if (*szURL)
            {
                TCHAR szT[MAX_PATH];

                hres = E_FAIL;

                // If it's a file:// URL, then default to the icon from
                // the file target.  Must use IExtractIconA in case we're
                // on Win95.
                IExtractIconA *pxi;
                if (_TryLink(IID_IExtractIconA, (void **)&pxi))
                {
                    uInFlags |= GIL_FORSHORTCUT;                        // to help break recursion
                    // S_FALSE means "I don't know what icon to use",
                    // so treat only S_OK as successful icon extraction.
                    if (IExtractIcon_GetIconLocation(pxi, uInFlags, pszBuf, cchBuf, pniIcon, puOutFlags) == S_OK)
                    {
                        hres = S_OK;
                        fNeedQualify = FALSE;
                    }

                    pxi->Release();
                }

                // If couldn't get target icon or not a file:// URL, then
                // go get some default icon based on the URL scheme.
                if (FAILED(hres))
                {
                    // Look up URL icon based on protocol handler.

                    hres = GetURLKey(szURL, TEXT("DefaultIcon"), szT, ARRAYSIZE(szT));

                    if (hres == S_OK)
                    {
                        hres = GetURLIcon(HKEY_CLASSES_ROOT, szT, pszBuf, 
                                          cchBuf, pniIcon);
                    }
                }
            }
        }
        
        if (hres == S_FALSE)
        {
            // Use generic URL icon.

            hres = GetFallBackGenericURLIcon(pszBuf, cchBuf, pniIcon); // Make sure we have the E icon and 
                                                                       // Not any of netscape's icons

            if (hres == S_OK)
                TraceMsg(TF_INTSHCUT, "Intshcut::GetIconLocation(): Using generic URL icon.");
        }

        if (hres == S_OK && fNeedQualify)
        {
            TCHAR szFullPath[MAX_PATH];

            if (PathSearchAndQualify(pszBuf, szFullPath, SIZECHARS(szFullPath)))
            {
                hres = S_OK;

                if ((UINT)lstrlen(szFullPath) < cchBuf)
                    StrCpyN(pszBuf, szFullPath, cchBuf);
                else
                    hres = E_FAIL;
            }
            else
                hres = E_FILE_NOT_FOUND;
        }
    }

    return hres;
}


/*----------------------------------------------------------
Purpose: Helper function that determines the icon location based
         on the flags property of the internet site property set.

Returns: 
Cond:    --
*/
STDMETHODIMP
Intshcut::GetIconLocationFromFlags(
    IN  UINT   uInFlags,
    OUT LPTSTR pszIconFile,
    IN  UINT   cchIconFile,
    OUT PINT   pniIcon,
    OUT PUINT  puOutFlags,
    IN  DWORD  dwPropFlags)
{
    HRESULT hres = S_FALSE;

    *puOutFlags = 0;

    ClearFlag(m_dwFlags, ISF_SPECIALICON);

    // Normally, the icon is the standard icon that is retrieved.
    // If the url has been updated, though, we want to add the
    // overlay, in which case we return GIL_NOTFILENAME so the
    // Extract method will be called.

    hres = GetURLIconLocation(uInFlags, pszIconFile, cchIconFile, pniIcon,
                                IsFlagSet(dwPropFlags, PIDISF_RECENTLYCHANGED), puOutFlags);
    if (SUCCEEDED(hres))
    {
        // (scotth): we don't support red splats on browser
        //                  only because it requires new SHELL32 APIs.

        // Has this item been updated since last viewed? 
        
        if (IsFlagSet(dwPropFlags, PIDISF_RECENTLYCHANGED) && 
                    (FALSE == (*puOutFlags & GIL_NOTFILENAME)))
        {
            // Yes; cache the item as a non-file so we get the
            // dynamically created icon 
            SetFlag(*puOutFlags, GIL_NOTFILENAME);

            // Add the icon index at the end of the filename, so
            // it will be hashed differently from the filename 
            // instance.
            wnsprintf(&pszIconFile[lstrlen(pszIconFile)], cchIconFile - lstrlen(pszIconFile),
                      TEXT(",%d"), *pniIcon);

            // cdturner
            // this is done for browser only mode to stop the shell hacking the path
            // down to the dll and not calling us
            
            // remove the dot from the string
            LPTSTR pszDot = StrRChr( pszIconFile, NULL, TCHAR('.'));
            if ( pszDot )
            {
                *pszDot = TCHAR('*');  // should be DBCS safe as it is in the lower 7 bits ASCII
            }
            
            SetFlag(m_dwFlags, ISF_SPECIALICON);
        }

    }
    else
    {
        // Init to default values
        *pniIcon = IDEFICON_NORMAL;
        if (cchIconFile > 0)
            StrCpyN(pszIconFile, c_szIntshcutDefaultIcon, cchIconFile);
    }

    return S_OK;
}


/*----------------------------------------------------------
Purpose: IExtractIcon::GetIconLocation handler for Intshcut

Returns: 
Cond:    --
*/
// This is the real one for the platform...
HRESULT
Intshcut::_GetIconLocation(
    IN  UINT   uInFlags,
    OUT LPWSTR pszIconFile,
    IN  UINT   cchIconFile,
    OUT PINT   pniIcon,
    OUT PUINT  puOutFlags)
{
    HRESULT hres;

    if (uInFlags & (GIL_ASYNC | GIL_FORSHORTCUT))
    {
        hres = GetGenericURLIcon(pszIconFile, cchIconFile, pniIcon);

        if (uInFlags & GIL_ASYNC)
            return ((SUCCEEDED(hres)) ? E_PENDING : hres);
        else
            return hres;
    }

    hres = LoadFromAsyncFileNow();
    if(FAILED(hres))
        return hres;

    hres = S_FALSE;

    // We also use this method to perform the mirroring
    // of the values between the internet shortcut file and
    // the central database.  IExtractIcon is a good interface
    // to do this because it is virtually guaranteed to be 
    // called for a URL.
    MirrorProperties();

    // Init to default values
    *puOutFlags = 0;
    *pniIcon = 0;
    if (cchIconFile > 0)
        *pszIconFile = TEXT('\0');


    DWORD dwVal = 0;

    if (m_psiteprop)
        m_psiteprop->GetProp(PID_INTSITE_FLAGS, &dwVal);

    hres = GetIconLocationFromFlags(uInFlags, pszIconFile, cchIconFile, pniIcon,
                                    puOutFlags, dwVal);


    ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));

    return hres;
}

HRESULT Intshcut::_CreateShellLink(LPCTSTR pszPath, IUnknown **ppunk)
{
    IUnknown *punk;
    HRESULT hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)&punk);
    
    if (SUCCEEDED(hr))
    {
        if (g_fRunningOnNT)
        {
            IShellLink *psl;
            hr = punk->QueryInterface(IID_IShellLink, (void **)&psl);
            if (SUCCEEDED(hr))
            {
                hr = psl->SetPath(pszPath);
                psl->Release();
            }
        }
        else
        {
            IShellLinkA *psl;
            hr = punk->QueryInterface(IID_IShellLinkA, (void **)&psl);
            if (SUCCEEDED(hr))
            {
                CHAR sz[MAX_PATH];
                SHTCharToAnsi(pszPath, sz, SIZECHARS(sz));
                hr = psl->SetPath(sz);
                psl->Release();
            }
        }

        if (SUCCEEDED(hr))
        {
            *ppunk = punk;
        }
        else
            punk->Release();
    }

    return hr;
}
    
HRESULT
Intshcut::GetIconLocation(
    IN  UINT   uInFlags,
    OUT LPTSTR pszIconFile,
    IN  UINT   cchIconFile,
    OUT PINT   pniIcon,
    OUT PUINT  puOutFlags)
{
    HRESULT hr = E_FAIL;
    ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
    ASSERT(IS_VALID_WRITE_BUFFER(pszIconFile, TCHAR, cchIconFile));
    ASSERT(IS_VALID_WRITE_PTR(pniIcon, INT));
    ASSERT(IS_VALID_WRITE_PTR(puOutFlags, UINT));

    if (FAILED(hr))
    {
        hr = _GetIconLocation(uInFlags, pszIconFile, cchIconFile, pniIcon, puOutFlags);
    }

    return hr;
}

//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\
//
// *** URLGetLocalFileName ***
//
//
// Description:
//
//
// Parameters:
//
//
// Return:
//
//
// Comments:
//
//
///////////////////////////////////////////////////////////////////////////////

HRESULT
URLGetLocalFileName(
    LPCTSTR pszURL,
    LPTSTR szLocalFile,
    int cch,
    FILETIME* pftLastMod
)
{
    ASSERT(pszURL);
    ASSERT(szLocalFile || 0 == cch);

    HRESULT hr = E_FAIL;

    if (pftLastMod)
    {
        pftLastMod->dwLowDateTime  = 0;
        pftLastMod->dwHighDateTime = 0;
    }

    // by using the internal shlwapi function, we avoid loading WININET 
    // unless we really really need it...
    DWORD scheme = GetUrlScheme(pszURL);
    if (scheme != URL_SCHEME_INVALID)
    {
        switch(scheme)
        {
        case URL_SCHEME_HTTP:
        case URL_SCHEME_FTP:
        case URL_SCHEME_GOPHER:
            {
                ULONG cbSize  = MAX_CACHE_ENTRY_INFO_SIZE;

                INTERNET_CACHE_ENTRY_INFO* piceiAlloced = 
                (INTERNET_CACHE_ENTRY_INFO*) new BYTE[cbSize];

                if (piceiAlloced)
                {
                    piceiAlloced->dwStructSize =
                                      sizeof(INTERNET_CACHE_ENTRY_INFO);

                    if (GetUrlCacheEntryInfoEx(pszURL, piceiAlloced,
                                               &cbSize, NULL, NULL,
                                               NULL, 0))
                    {
                        if (StrCpyN(szLocalFile,
                                    piceiAlloced->lpszLocalFileName, cch))
                        {
                            if (pftLastMod)
                            {
                                *pftLastMod = piceiAlloced->LastModifiedTime;
                            }

                            hr = S_OK;
                        }
                    }

                    delete [] piceiAlloced;
                }
            }
            break;

        case URL_SCHEME_FILE:
            hr = PathCreateFromUrl(pszURL, szLocalFile, (LPDWORD)&cch, 0);
            break;

        }
    }
    else
    {
        if (StrCpyN(szLocalFile, pszURL, cch))
            hr = S_OK;
    }

    return hr;
}


BOOL
PretendFileIsICONFileAndLoad(
    IN LPTSTR lpszTempBuf,
    OUT HICON * phiconLarge,
    OUT HICON * phiconSmall,
    IN  UINT    ucIconSize)
{
    WORD wSizeSmall = HIWORD(ucIconSize);
    WORD wSizeLarge = LOWORD(ucIconSize);

    BOOL fRet = FALSE;
    // Pretend that the file is a .ico file and load it

    ASSERT(phiconLarge);
    ASSERT(phiconSmall);
    
    *phiconSmall = (HICON)LoadImage(NULL, lpszTempBuf, IMAGE_ICON, wSizeSmall, wSizeSmall, LR_LOADFROMFILE);
    if(*phiconSmall)
    {
        fRet = TRUE;
        *phiconLarge = (HICON)LoadImage(NULL, lpszTempBuf, IMAGE_ICON, wSizeLarge, wSizeLarge, LR_LOADFROMFILE);
    }
                

    return fRet;
}




BOOL
Intshcut::ExtractIconFromWininetCache(
    IN  LPCTSTR pszIconString,
    IN  UINT    iIcon,
    OUT HICON * phiconLarge,
    OUT HICON * phiconSmall,
    IN  UINT    ucIconSize,
    BOOL *pfFoundUrl,
    DWORD dwPropFlags)
{
    IPropertyStorage *ppropstg = NULL;
    BOOL fRet = FALSE;
    INT iTempIconIndex;
    HRESULT hr;
    BOOL fFoundURL = FALSE;


    ASSERT(pfFoundUrl && (FALSE == *pfFoundUrl));
    ASSERT((lstrlen(pszIconString) + 1)<= MAX_PATH);
    
    TCHAR szTempBuf[MAX_URL_STRING + 1];
    *szTempBuf = TEXT('\0');
    TCHAR szTempIconBuf[MAX_PATH + 1];
    *szTempIconBuf = TEXT('\0');
      
    hr =  _GetIconLocationWithURLHelper(
                    szTempIconBuf, ARRAYSIZE(szTempIconBuf), &iTempIconIndex, 
                    szTempBuf, ARRAYSIZE(szTempBuf), IsFlagSet(dwPropFlags, PIDISF_RECENTLYCHANGED));
    
    if((S_OK == hr) && (*szTempIconBuf))
    {
        if((UINT)iTempIconIndex == iIcon)
        {
            if(0 == StrCmp(szTempIconBuf, pszIconString))
            {
                if(*szTempBuf)
                {
                    BOOL fUsesCache=FALSE;
                    DWORD dwBufSize=0;
                    CoInternetQueryInfo(szTempBuf, QUERY_USES_CACHE, 0,
                                     &fUsesCache, sizeof(fUsesCache), &dwBufSize, 0);

                    if(fUsesCache)
                    {
                        fFoundURL = TRUE;
                    }
                }
            }
        }
    }



    if(fFoundURL)
    {
        // Now szTempBuf has the URL of the ICON
        // now look and see if the shortcut file itself has the icon and if so
        // simply use it  --- TBD 
        
        
        // we need to grovel in the cache and see if we can get
        // it there and then convert it to an icon
        TCHAR szIconFile[MAX_PATH + 1];
        hr = URLGetLocalFileName(szTempBuf, szIconFile, ARRAYSIZE(szIconFile), NULL);

        if(S_OK == hr)
        {

            if(PretendFileIsICONFileAndLoad(szIconFile, phiconLarge, phiconSmall, ucIconSize))
            {
                fRet = TRUE;
            }

            // It's a bitmap, gif or a jpeg          
        }
    }
    

    if(pfFoundUrl)
        *pfFoundUrl = fFoundURL;
    return fRet;
}

/*----------------------------------------------------------
Purpose: IExtractIcon::Extract method for Intshcut

         Extract the icon.  This function really returns an icon
         that is dynamically created, based upon the properties
         of the URL (recently changed, etc).

         Expect that for normal cases, when the icon does not
         need to be munged (an overlay added), the GetIconLocation
         method should suffice.  Otherwise, this method will get
         called.

Returns: 
Cond:    --
*/
// This is the real one for the platform...
HRESULT
Intshcut::_Extract(
    IN  LPCTSTR pszIconFile,
    IN  UINT    iIcon,
    OUT HICON * phiconLarge,
    OUT HICON * phiconSmall,
    IN  UINT    ucIconSize)
{
    HRESULT hres;
    HICON hiconLarge = NULL;
    HICON hiconSmall = NULL;
    TCHAR szPath[MAX_PATH];
    int nIndex;
    BOOL fSpecialUrl = FALSE;
    *phiconLarge = NULL;
    *phiconSmall = NULL;
    DWORD dwPropFlags = 0;

    hres = LoadFromAsyncFileNow();
    if(FAILED(hres))
        return hres;

    hres = S_FALSE;    
    
    InitSiteProp();

    // Get the property Flags
    if (m_psiteprop)
            m_psiteprop->GetProp(PID_INTSITE_FLAGS, &dwPropFlags);
    
    // First check to see if this is a special icon
    // This function returns a usable value for fSpecialUrl even if it returns FALSE
    if(ExtractIconFromWininetCache(pszIconFile, iIcon, &hiconLarge, &hiconSmall, ucIconSize, &fSpecialUrl, dwPropFlags))
    {
        hres = S_OK;
    } 
    else 
    {
        if(TRUE == fSpecialUrl)
        {
            // The extract failed even though this was a special URL
            // we need to revert back to using the default IE icon
            hres = GetGenericURLIcon(szPath, MAX_PATH, (int *)(&iIcon));
            
            if (hres == S_OK)
            {
                fSpecialUrl = FALSE; // It's no longer a special URL
                hres = InitProp();
                if (SUCCEEDED(hres))
                {
                    hres = m_pprop->SetProp(PID_IS_ICONFILE, szPath);
                    if (SUCCEEDED(hres))
                    {
                        hres = m_pprop->SetProp(PID_IS_ICONINDEX, (INT)iIcon);
                    }
                }
            }
            
            if(S_OK != hres)
            {
                ASSERT(0);
                goto DefIcons;
            }
        } 
        else
        {
            StrCpyN(szPath, pszIconFile, ARRAYSIZE(szPath));
            // The path may be munged.  Get the icon index as appropriate.
            if (IsFlagSet(m_dwFlags, ISF_SPECIALICON) && (!fSpecialUrl) )
            {
                // Get the icon location from the munged path
                iIcon = PathParseIconLocation(szPath);

                // cdturner
                // now replace the '*' with the dot
                // this is done for browser only mode to stop the shell hacking the path
                // down to the dll and not calling us
                LPTSTR pszPlus = StrRChr( szPath, NULL, TCHAR('*'));
                if ( pszPlus )
                {
                    *pszPlus = TCHAR('.');
                }
                
                
            }
        }
        
        
        nIndex = iIcon;

        if(!fSpecialUrl)
        {
            if ( WhichPlatform() == PLATFORM_INTEGRATED )
            {
                // Extract the icons 
                CHAR szTempPath[MAX_PATH + 1];
                SHTCharToAnsi(szPath, szTempPath, ARRAYSIZE(szTempPath));
                hres = SHDefExtractIconA(szTempPath, nIndex, 0, &hiconLarge, &hiconSmall, 
                                        ucIconSize);
            }
            else
            {
                // cdturner
                // use a more hacky solution to support browser only mode..
                _InitSysImageLists();
                
                int iIndex = Shell_GetCachedImageIndex( szPath, nIndex, 0 );
                if ( iIndex > 0 )
                {
                    hiconLarge = ImageList_GetIcon( g_himlSysLarge, iIndex, 0 );
                    hiconSmall = ImageList_GetIcon( g_himlSysSmall, iIndex, 0 );

                    hres = NOERROR;
                }
                else 
                {
                    hiconLarge = hiconSmall = NULL;
                    
                    // it will get the windows icon if it should be gleamed, and 
                    // it will the normal icon otherwsie
                    hres = IsFlagSet(dwPropFlags, PIDISF_RECENTLYCHANGED) ? E_FAIL : S_FALSE;
                    goto DefIcons;
                }
            }
        }
    }

    

    if (SUCCEEDED(hres))
    {
        // Has this URL changed recently? 
        if (IsFlagSet(dwPropFlags, PIDISF_RECENTLYCHANGED))
        {
            // Yes 
            URLIMAGES ui;

            if (SUCCEEDED(InitURLImageLists(&ui, hiconLarge, hiconSmall)))
            {
                *phiconLarge = ImageList_GetIcon(ui.himl, 0, INDEXTOOVERLAYMASK(II_OVERLAY_UPDATED));
                *phiconSmall = ImageList_GetIcon(ui.himlSm, 0, INDEXTOOVERLAYMASK(II_OVERLAY_UPDATED));

                DestroyURLImageLists(&ui);

                // these were created, they are not global handles, so they must be cleanedup.
                DestroyIcon( hiconLarge );
                DestroyIcon( hiconSmall );
            }
            else
                goto DefIcons;
        }
        else
        {
            // No
DefIcons:
            *phiconLarge = hiconLarge;
            *phiconSmall = hiconSmall;
        }
    }

    return hres;
}

STDMETHODIMP
Intshcut::Extract(
    IN  LPCTSTR pszIconFile,
    IN  UINT    iIcon,
    OUT HICON * phiconLarge,
    OUT HICON * phiconSmall,
    IN  UINT    ucIconSize)
{
    if (URL_SCHEME_FILE == GetScheme() && _punkLink)
        return IExtractIcon_Extract(_punkLink, pszIconFile, iIcon, phiconLarge, phiconSmall, ucIconSize);
    else
        return _Extract(pszIconFile, iIcon, phiconLarge, phiconSmall, ucIconSize);
}

// Now handle the
// Unicode or Ansi one for the "Other" platform...

STDMETHODIMP
Intshcut::GetIconLocation(UINT uInFlags, LPSTR pszIconFile, UINT cchIconFile,
        PINT pniIcon, PUINT  puOutFlags)
{
    HRESULT hres;
    WCHAR   wszIconFile[MAX_PATH];

    // IconFile is output so...
    // Note, we will only handle up to MAXPATH
    if (cchIconFile > ARRAYSIZE(wszIconFile))
        cchIconFile = ARRAYSIZE(wszIconFile);

    ASSERT(IS_VALID_WRITE_BUFFER(pszIconFile, TCHAR, cchIconFile));
    hres = GetIconLocation(uInFlags, wszIconFile, cchIconFile, pniIcon, puOutFlags);

    if (cchIconFile > 0 && SUCCEEDED(hres))
    {
        WideCharToMultiByte(CP_ACP, 0, wszIconFile, -1, pszIconFile, cchIconFile, NULL, NULL);
    }
    return hres;
}


STDMETHODIMP Intshcut::Extract(IN  LPCSTR pszIconFile, IN  UINT    iIcon,
    OUT HICON * phiconLarge, OUT HICON * phiconSmall, IN  UINT    ucIconSize)
{
    WCHAR wszIconFile[MAX_PATH];

    // First convert the string...
    MultiByteToWideChar(CP_ACP, 0, pszIconFile, -1, wszIconFile, ARRAYSIZE(wszIconFile));

    return Extract(wszIconFile, iIcon, phiconLarge, phiconSmall, ucIconSize);
}
