//*******************************************************************************************
//
// Filename : XIcon.cpp
//	
//				Implementation file for CIconTemp and CXIcon
//
// Copyright (c) 1994 - 1996 Microsoft Corporation. All rights reserved
//
//*******************************************************************************************

#include "Pch.H"

#include "ThisDll.H"

#include "Unknown.H"
#include "XIcon.H"

class CIconTemp : public CObjTemp
{
public:
	CIconTemp() : CObjTemp() {}
	CIconTemp(HICON hi) : CObjTemp() {Attach(hi);}
	~CIconTemp() {if (m_hObj) DestroyIcon(Detach());}

	operator HICON() const {return((HICON)m_hObj);}

	HICON Attach(HICON hObjNew) {return((HICON)CObjTemp::Attach((HANDLE)hObjNew));}
	HICON Detach() {return((HICON)CObjTemp::Detach());}
} ;


BOOL CXIcon::Init(HWND hwndLB, UINT idiDef)
{
	m_hwndLB = hwndLB;

	m_cimlLg.Create(GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), 8);
	m_cimlSm.Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 8);

	HICON hIcon = LoadIcon(g_ThisDll.GetInstance(), MAKEINTRESOURCE(idiDef));

	return(m_cimlLg && m_cimlSm && AddIcon(hIcon)>=0);
}


UINT CXIcon::GetIDString(LPTSTR pszIDString, UINT uIDLen,
	LPCTSTR szIconFile, int iIndex, UINT wFlags)
{
	static const TCHAR szIDFmt[] = TEXT("\"%s\" %d %08x");
	TCHAR szIDString[MAX_PATH + 2*ARRAYSIZE(szIDFmt)];

	int iRet = wsprintf(szIDString, szIDFmt, szIconFile, iIndex, wFlags);
	lstrcpyn(pszIDString, szIDString, uIDLen);

	return(iRet + 1);
}


int CXIcon::GetCachedIndex(LPCTSTR szIconFile, int iIndex, UINT wFlags)
{
	TCHAR szIDString[MAX_PATH*2];
	GetIDString(szIDString, ARRAYSIZE(szIDString), szIconFile, iIndex, wFlags);
	int iLB = ListBox_FindStringExact(m_hwndLB, -1, szIDString);

	if (iLB < 0)
	{
		return(-1);
	}

	return (int)((INT_PTR)ListBox_GetItemData(m_hwndLB, iLB));
}


int CXIcon::CacheIcons(HICON hiLarge, HICON hiSmall,
	LPCTSTR szIconFile, int iIndex, UINT wFlags)
{
	CIconTemp ciLarge(hiLarge);
	CIconTemp ciSmall(hiSmall);

	if (!hiLarge || !hiSmall)
	{
		return(-1);
	}

	TCHAR szIDString[MAX_PATH*2];
	GetIDString(szIDString, ARRAYSIZE(szIDString), szIconFile, iIndex, wFlags);
	int iLB = ListBox_AddString(m_hwndLB, szIDString);

	if (iLB < 0)
	{
		return(-1);
	}

	int iLarge = AddIcon(ciLarge, AI_LARGE);
	if (iLarge >= 0)
	{
		int iSmall = AddIcon(ciSmall, AI_SMALL);
		if (iSmall >= 0)
		{
			if (iLarge == iSmall)
			{
				// Should always happen;
				ListBox_SetItemData(m_hwndLB, iLB, iLarge);
				return(iLarge);
			}

			ImageList_Remove(m_cimlSm, iSmall);
		}

		ImageList_Remove(m_cimlLg, iLarge);
	}


	ListBox_DeleteString(m_hwndLB, iLB);
	return(-1);
}


HRESULT CXIcon::ExtractIcon(LPCTSTR szIconFile, int iIndex, UINT wFlags,
	HICON *phiconLarge, HICON *phiconSmall, DWORD dwSizes)
{
	return(E_NOTIMPL);
}


int CXIcon::GetIcon(IShellFolder *psf, LPCITEMIDLIST pidl)
{
	int iImage = -1;

	IExtractIcon *pxi;
	HRESULT hres = psf->GetUIObjectOf(NULL, 1, &pidl, IID_IExtractIcon, NULL, (LPVOID *)&pxi);

	if (FAILED(hres))
	{
		return(0);
	}
	CEnsureRelease erExtractIcon(pxi);

    TCHAR szIconFile[MAX_PATH];
    int iIndex;
    UINT wFlags = 0;

    hres = pxi->GetIconLocation(GIL_FORSHELL,
		szIconFile, ARRAYSIZE(szIconFile), &iIndex, &wFlags);
    if (FAILED(hres))
    {
		return(0);
	}

    //
    // if GIL_DONTCACHE was returned by the icon handler, dont
    // lookup the previous icon, assume a cache miss.
    //
    if (!(wFlags & GIL_DONTCACHE))
	{
        iImage = GetCachedIndex(szIconFile, iIndex, wFlags);
	}

    // if we miss our cache...
    if (iImage == -1)
    {
		HICON hiconLarge = NULL;
		HICON hiconSmall = NULL;

		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cxSmIcon = GetSystemMetrics(SM_CXSMICON);

        // try getting it from the Extract member fuction
        hres = pxi->Extract(szIconFile, iIndex, &hiconLarge, &hiconSmall,
        	MAKELONG(cxIcon, cxSmIcon));

		// S_FALSE means can you please do it
		if (hres == S_FALSE)
		{
			hres = ExtractIcon(szIconFile, iIndex, wFlags,
				&hiconLarge, &hiconSmall, MAKELONG(cxIcon, cxSmIcon));
		}
		if (SUCCEEDED(hres))
		{
			// Let CacheIcons check and destroy the hicon's
			iImage = CacheIcons(hiconLarge, hiconSmall, szIconFile, iIndex, wFlags);
		}

		// if we failed in any way pick a default icon
        if (iImage == -1)
        {
            if (wFlags & GIL_SIMULATEDOC)
			{
                iImage = 0; // II_DOCUMENT;
			}
            else if ((wFlags & GIL_PERINSTANCE) && PathIsExe(szIconFile))
			{
                iImage = 0; // II_APPLICATION;
			}
            else
			{
                iImage = 0; // II_DOCNOASSOC;
			}
		}
	}

    if (iImage < 0)
	{
        iImage = 0; // II_DOCNOASSOC;
	}

	return(iImage);
}