/*
 * ICON.C
 *
 * Implements the OleUIChangeIcon function which invokes the complete
 * Change Icon dialog.
 *
 * Copyright (c)1992 Microsoft Corporation, All Right Reserved
 */

#define STRICT  1
#include "ole2ui.h"
#include "common.h"
#include "utility.h"
#include "icon.h"
#include "geticon.h"

/*
 * OleUIChangeIcon
 *
 * Purpose:
 *  Invokes the standard OLE Change Icon dialog box allowing the user
 *  to select an icon from an icon file, executable, or DLL.
 *
 * Parameters:
 *  lpCI            LPOLEUIChangeIcon pointing to the in-out structure
 *                  for this dialog.
 *
 * Return Value:
 *  UINT            OLEUI_SUCCESS or OLEUI_OK if all is well, otherwise
 *                  an error value.
 */

STDAPI_(UINT) OleUIChangeIcon(LPOLEUICHANGEICON lpCI)
	{
	UINT        uRet;
	HGLOBAL     hMemDlg=NULL;

	uRet=UStandardValidation((LPOLEUISTANDARD)lpCI, sizeof(OLEUICHANGEICON)
							 , &hMemDlg);

	if (OLEUI_SUCCESS!=uRet)
		return uRet;

#if defined( OBSOLETE )
	if (NULL==lpCI->hMetaPict)
		uRet=OLEUI_CIERR_MUSTHAVECURRENTMETAFILE;
#endif

	if (lpCI->dwFlags & CIF_USEICONEXE)
	{
	  if (   (NULL == lpCI->szIconExe)
		  || (IsBadReadPtr(lpCI->szIconExe, lpCI->cchIconExe))
		  || (IsBadWritePtr(lpCI->szIconExe, lpCI->cchIconExe)) )
		 uRet = OLEUI_CIERR_SZICONEXEINVALID;

	}

 // REVIEW: how do we validate the CLSID?
/*
	if ('\0'==*((LPSTR)&lpCI->clsid))
		uRet=OLEUI_CIERR_MUSTHAVECLSID;
*/
	if (OLEUI_ERR_STANDARDMIN <= uRet)
		{
		if (NULL!=hMemDlg)
			FreeResource(hMemDlg);

		return uRet;
		}

	//Now that we've validated everything, we can invoke the dialog.
	return UStandardInvocation(ChangeIconDialogProc, (LPOLEUISTANDARD)lpCI
							   , hMemDlg, MAKEINTRESOURCE(IDD_CHANGEICON));
	}





/*
 * ChangeIconDialogProc
 *
 * Purpose:
 *  Implements the OLE Change Icon dialog as invoked through the
 *  OleUIChangeIcon function.
 *
 * Parameters:
 *  Standard
 *
 * Return Value:
 *  Standard
 */

BOOL CALLBACK EXPORT ChangeIconDialogProc(HWND hDlg, UINT iMsg
									 , WPARAM wParam, LPARAM lParam)
	{
	LPCHANGEICON            lpCI;
	HICON                   hIcon;
	HGLOBAL                 hMetaPict;
	BOOL                    fOK=FALSE;
	UINT                    uRet=0;
	LPSTR                   psz;
	char                    szTemp[OLEUI_CCHPATHMAX];

	//Declare Win16/Win32 compatible WM_COMMAND parameters.
	COMMANDPARAMS(wID, wCode, hWndMsg);

	lpCI=(LPCHANGEICON)LpvStandardEntry(hDlg, iMsg, wParam, lParam, &uRet);

	//If the hook processed the message, we're done.
	if (0!=uRet)
		return uRet;

	//Process the temination message
	if (iMsg==uMsgEndDialog)
		{
		//Insure that icons are properly destroyed.
		SendDlgItemMessage(hDlg, ID_ICONLIST, LB_RESETCONTENT, 0, 0L);

		StandardCleanup(lpCI, hDlg);
		EndDialog(hDlg, wParam);
		return TRUE;
		}

	switch (iMsg)
		{
		case WM_INITDIALOG:
			FChangeIconInit(hDlg, wParam, lParam);
			return TRUE;


		case WM_MEASUREITEM:
			{
			LPMEASUREITEMSTRUCT     lpMI=(LPMEASUREITEMSTRUCT)lParam;

			//All icons are system metric+padding in width and height
			lpMI->itemWidth =GetSystemMetrics(SM_CXICON)+CXICONPAD;
			lpMI->itemHeight=GetSystemMetrics(SM_CYICON)+CYICONPAD;
			}
			break;


		case WM_DRAWITEM:
			return FDrawListIcon((LPDRAWITEMSTRUCT)lParam);


		case WM_DELETEITEM:
			//Free the GDI object for the item
			DestroyIcon((HICON)LOWORD(((LPDELETEITEMSTRUCT)lParam)->itemData));
			break;


		case WM_COMMAND:
			switch (wID)
				{
				case ID_CURRENT:
				case ID_DEFAULT:
				case ID_FROMFILE:
					UpdateResultIcon(lpCI, hDlg, wID);
					break;

				case ID_LABELEDIT:
					//When the edit loses focus, update the result display
					if (EN_KILLFOCUS==wCode)
						{
						GetDlgItemText(hDlg, ID_LABELEDIT, szTemp, sizeof(szTemp));
						SetDlgItemText(hDlg, ID_RESULTLABEL, szTemp);
						}
					break;

				case ID_FROMFILEEDIT:
					//If the text changed, remove any selection in the list.
					GetDlgItemText(hDlg, ID_FROMFILEEDIT, szTemp, sizeof(szTemp));

					if (lpCI && lstrcmpi(szTemp, lpCI->szFile))
						{
						SendDlgItemMessage(hDlg, ID_ICONLIST, LB_SETCURSEL
										   , (WPARAM)-1, 0);

						//Also force selection of ID_FROMFILE
						CheckRadioButton(hDlg, ID_CURRENT, ID_FROMFILE, ID_FROMFILE);
						}
					break;


				case ID_ICONLIST:
					switch (wCode)
						{
						case LBN_SETFOCUS:
							//If we got the focus, see about updating.
							GetDlgItemText(hDlg, ID_FROMFILEEDIT, szTemp
										   , sizeof(szTemp));

							//Check if file changed and update the list if so
							if (lpCI && 0!=lstrcmpi(szTemp, lpCI->szFile))
								{
								lstrcpy(lpCI->szFile, szTemp);
								UFillIconList(hDlg, ID_ICONLIST, lpCI->szFile);
								UpdateResultIcon(lpCI, hDlg, ID_FROMFILE);
								}
							break;

						case LBN_SELCHANGE:
							UpdateResultIcon(lpCI, hDlg, ID_FROMFILE);
							break;

						case LBN_DBLCLK:
							//Same as pressing OK.
							SendCommand(hDlg, IDOK, BN_CLICKED, hWndMsg);
							break;
						}
					break;


				case ID_BROWSE:
				{
					DWORD dwOfnFlags;

					/*
					 * To allow the hook to customize the browse dialog, we
					 * send OLEUI_MSG_BROWSE.  If the hook returns FALSE
					 * we use the default, otherwise we trust that it retrieved
					 * a filename for us.  This mechanism prevents hooks from
					 * trapping ID_BROWSE to customize the dialog and from
					 * trying to figure out what we do after we have the name.
					 */

					//Copy for reference
					LSTRCPYN(szTemp, lpCI->szFile, sizeof(szTemp));

					uRet=UStandardHook(lpCI, hDlg, uMsgBrowse, OLEUI_CCHPATHMAX
									   , (LONG)(LPSTR)lpCI->szFile);

					dwOfnFlags = OFN_FILEMUSTEXIST;
					if (lpCI->lpOCI->dwFlags & CIF_SHOWHELP)
					   dwOfnFlags |= OFN_SHOWHELP;

					if (0==uRet)
						uRet=(BOOL)Browse(hDlg, lpCI->szFile, NULL, OLEUI_CCHPATHMAX, (UINT)IDS_ICONFILTERS, (UINT)IDS_BROWSE, dwOfnFlags);

					/*
					 * Only reinitialize if the file changed, so if we got
					 * TRUE from the hook but the user hit Cancel, we don't
					 * spend time unecessarily refilling the list.
					 */
					if (0!=uRet && 0!=lstrcmpi(szTemp, lpCI->szFile))
					{
						CheckRadioButton(hDlg, ID_CURRENT, ID_FROMFILE, ID_FROMFILE);
						SetDlgItemText(hDlg, ID_FROMFILEEDIT, lpCI->szFile);
						UFillIconList(hDlg, ID_ICONLIST, lpCI->szFile);
						UpdateResultIcon(lpCI, hDlg, ID_FROMFILE);
					}
				}
				break;


				case IDOK:
					/*
					 * If the user pressed enter, compare the current file
					 * and the one we have stored.  If they match, then
					 * refill the listbox instead of closing down.  This is
					 * so the user can press Enter in the edit control as
					 * they would expect to be able to do.
					 */
					GetDlgItemText(hDlg, ID_FROMFILEEDIT, szTemp, sizeof(szTemp));

					//Check if the file changed at all.
					if (0!=lstrcmpi(szTemp, lpCI->szFile))
						{
						lstrcpy(lpCI->szFile, szTemp);
						UFillIconList(hDlg, ID_ICONLIST, lpCI->szFile);
						UpdateResultIcon(lpCI, hDlg, ID_FROMFILE);

						//Eat this message to prevent focus change.
						return TRUE;
						}

					// Check if the file name is valid
					//  (if FromFile is enabled)
					if (ID_FROMFILE & lpCI->dwFlags)
						{
						OFSTRUCT    of;
						HWND hWnd;
						if (HFILE_ERROR==DoesFileExist(lpCI->szFile, &of))
							{
							OpenFileError(hDlg, of.nErrCode, lpCI->szFile);
							hWnd = GetDlgItem(hDlg, ID_FROMFILEEDIT);
							SetFocus(hWnd);
							SendMessage(hWnd, EM_SETSEL, 0, MAKELPARAM(0, (WORD)-1));
							return TRUE;  // eat this message
							}
						}

					if ((HWND)LOWORD(lParam) != GetFocus())
					   SetFocus((HWND)LOWORD(lParam));

					/*
					 * On closing, create a new metafilepict with the
					 * current icon and label, destroying the old structure.
					 *
					 * Since we make a copy of the icon by placing it into
					 * the metafile, we have to make sure we delete the
					 * icon in the current field.  When the listbox is
					 * destroyed WM_DELETEITEMs will clean it up appropriately.
					 */

					hIcon=(HICON)SendDlgItemMessage(hDlg, ID_RESULTICON
													, STM_GETICON, 0, 0L);

					/*
					 * If default is selected then we get the source
					 * information from registrion database for the
					 * current class to put in the metafile.  If current
					 * is selected the we just retrieve the original file
					 * again and recreate the metafile.  If from file is
					 * selected we use the current filename from the
					 * control and the current listbox selection.
					 */

					psz=lpCI->szFile;

					if (lpCI->dwFlags & CIF_SELECTDEFAULT)
						{
						psz=lpCI->szDefIconFile;
						lpCI->iIcon=lpCI->iDefIcon;
						hIcon=lpCI->hDefIcon;
						}

					if (lpCI->dwFlags & CIF_SELECTCURRENT)
						{
						//Go get the current icon source back.
						OleUIMetafilePictExtractIconSource(lpCI->lpOCI->hMetaPict
							, psz, &lpCI->iIcon);
						}

					if (lpCI->dwFlags & CIF_SELECTFROMFILE)
						{
						GetDlgItemText(hDlg, ID_FROMFILEEDIT, psz, OLEUI_CCHPATHMAX);

						lpCI->iIcon=(UINT)SendDlgItemMessage(hDlg
							, ID_ICONLIST, LB_GETCURSEL, 0, 0L);
						}


					//Get the label and go create the metafile
					GetDlgItemText(hDlg, ID_LABELEDIT, szTemp, sizeof(szTemp));

					//If psz is NULL (default) we get no source comments.
					hMetaPict=OleUIMetafilePictFromIconAndLabel(hIcon
						, szTemp, psz, lpCI->iIcon);

					//Clean up the current icon that we extracted.
					hIcon=(HICON)SendDlgItemMessage(hDlg, ID_CURRENTICON
													, STM_GETICON, 0, 0L);
					DestroyIcon(hIcon);

					//Clean up the default icon
					DestroyIcon(lpCI->hDefIcon);

					// Remove the prop set on our parent
					RemoveProp(lpCI->lpOCI->hWndOwner, PROP_HWND_CHGICONDLG);

					if (NULL==hMetaPict)
						SendMessage(hDlg, uMsgEndDialog, OLEUI_FALSE, 0L);

					OleUIMetafilePictIconFree(lpCI->lpOCI->hMetaPict);
					lpCI->lpOCI->hMetaPict=hMetaPict;

					lpCI->lpOCI->dwFlags = lpCI->dwFlags;

					SendMessage(hDlg, uMsgEndDialog, OLEUI_OK, 0L);
					break;


				case IDCANCEL:
					//Clean up the current icon that we extracted.
					hIcon=(HICON)SendDlgItemMessage(hDlg, ID_CURRENTICON
													, STM_GETICON, 0, 0L);
					DestroyIcon(hIcon);

					//Clean up the default icon
					DestroyIcon(lpCI->hDefIcon);

					// Remove the prop set on our parent
					RemoveProp(lpCI->lpOCI->hWndOwner, PROP_HWND_CHGICONDLG);

					//We leave hMetaPict intact on Cancel; caller's responsibility
					SendMessage(hDlg, uMsgEndDialog, OLEUI_CANCEL, 0L);
					break;


				case ID_OLEUIHELP:
					PostMessage(lpCI->lpOCI->hWndOwner, uMsgHelp,
								(WPARAM)hDlg, MAKELPARAM(IDD_CHANGEICON, 0));
					break;
				}
			break;

		default:
		{
			if (lpCI && iMsg == lpCI->nBrowseHelpID) {
				PostMessage(lpCI->lpOCI->hWndOwner, uMsgHelp,
						(WPARAM)hDlg, MAKELPARAM(IDD_CHANGEICONBROWSE, 0));
			}
		}
		break;
		}
	return FALSE;
	}




/*
 * FChangeIconInit
 *
 * Purpose:
 *  WM_INITIDIALOG handler for the Change Icon dialog box.
 *
 * Parameters:
 *  hDlg            HWND of the dialog
 *  wParam          WPARAM of the message
 *  lParam          LPARAM of the message
 *
 * Return Value:
 *  BOOL            Value to return for WM_INITDIALOG.
 */

BOOL FChangeIconInit(HWND hDlg, WPARAM wParam, LPARAM lParam)
	{
	LPCHANGEICON            lpCI;
	LPOLEUICHANGEICON       lpOCI;
	HFONT                   hFont;
	HWND                    hList;
	UINT                    cyList;
	RECT                    rc, rcG;
	UINT                    uID;

	//1.  Copy the structure at lParam into our instance memory.
	lpCI=(LPCHANGEICON)LpvStandardInit(hDlg, sizeof(CHANGEICON), TRUE, &hFont);

	//PvStandardInit send a termination to us already.
	if (NULL==lpCI)
		return FALSE;

	//Save the original pointer and copy necessary information.
	lpOCI=(LPOLEUICHANGEICON)lParam;

	lpCI->lpOCI  =lpOCI;
	lpCI->dwFlags=lpOCI->dwFlags;

	//Go extract the icon source from the metafile.
	OleUIMetafilePictExtractIconSource(lpOCI->hMetaPict, lpCI->szFile, &lpCI->iIcon);

	//Go extract the icon and the label from the metafile
	OleUIMetafilePictExtractLabel(lpOCI->hMetaPict, lpCI->szLabel, OLEUI_CCHLABELMAX, NULL);
	lpCI->hCurIcon=OleUIMetafilePictExtractIcon(lpOCI->hMetaPict);

	//2.  If we got a font, send it to the necessary controls.
	if (NULL!=hFont)
		{
		SendDlgItemMessage(hDlg, ID_RESULTLABEL, WM_SETFONT
						   , (WPARAM)hFont, 0L);
		}


	//3.  Show or hide the help button
	if (!(lpCI->dwFlags & CIF_SHOWHELP))
		StandardShowDlgItem(hDlg, ID_OLEUIHELP, SW_HIDE);


	/*
	 * 4.  Set text limits and initial control values.  If we're given
	 *     an intial label we set it in the edit and static controls.
	 *     If we don't, then we copy the default contents of the static
	 *     control into the edit control, meaning that only the default
	 *     static control string need be localized.
	 */

	SendDlgItemMessage(hDlg, ID_LABELEDIT, EM_LIMITTEXT, OLEUI_CCHLABELMAX, 0L);
	SendDlgItemMessage(hDlg, ID_FROMFILEEDIT, EM_LIMITTEXT, OLEUI_CCHPATHMAX,  0L);
	SetDlgItemText(hDlg, ID_FROMFILEEDIT, lpCI->szFile);

	//Copy the label text into the edit and static controls.
	SetDlgItemText(hDlg, ID_LABELEDIT,   lpCI->szLabel);
	SetDlgItemText(hDlg, ID_RESULTLABEL, lpCI->szLabel);


	lpCI->hDefIcon = NULL;

	if (lpCI->dwFlags & CIF_USEICONEXE)
	{
	   lpCI->hDefIcon = ExtractIcon(ghInst, lpCI->lpOCI->szIconExe, 0);

	   if (NULL != lpCI->hDefIcon)
	   {
		 lstrcpy(lpCI->szDefIconFile, lpCI->lpOCI->szIconExe);
		 lpCI->iDefIcon = 0;
	   }
	}


	if (NULL == lpCI->hDefIcon)
	{
	   HGLOBAL hMetaPict;

	   hMetaPict = GetIconOfClass(ghInst,
								  &lpCI->lpOCI->clsid,
								  NULL,
								  TRUE);

	   lpCI->hDefIcon = OleUIMetafilePictExtractIcon(hMetaPict);

	   OleUIMetafilePictExtractIconSource(hMetaPict,
										  lpCI->szDefIconFile,
										  &lpCI->iDefIcon);

	   OleUIMetafilePictIconFree(hMetaPict);
	}


	//Initialize all the icon displays.
	SendDlgItemMessage(hDlg, ID_CURRENTICON, STM_SETICON
		, (WPARAM)lpCI->hCurIcon, 0L);
	SendDlgItemMessage(hDlg, ID_DEFAULTICON, STM_SETICON
		, (WPARAM)lpCI->hDefIcon, 0L);
	SendDlgItemMessage(hDlg, ID_RESULTICON,  STM_SETICON
		, (WPARAM)lpCI->hCurIcon, 0L);


	/*
	 * 5.  Since we cannot predict the size of icons on any display,
	 *     we have to resize the icon listbox to the size of an icon
	 *     (plus padding), a scrollbar, and two borders (top & bottom).
	 */
	cyList=GetSystemMetrics(SM_CYICON)+GetSystemMetrics(SM_CYHSCROLL)
		   +GetSystemMetrics(SM_CYBORDER)*2+CYICONPAD;

	hList=GetDlgItem(hDlg, ID_ICONLIST);
	GetClientRect(hList, &rc);
	SetWindowPos(hList, NULL, 0, 0, rc.right, cyList
				 , SWP_NOMOVE | SWP_NOZORDER);

	//Set the columns in this multi-column listbox to hold one icon
	SendMessage(hList, LB_SETCOLUMNWIDTH
				, GetSystemMetrics(SM_CXICON)+CXICONPAD,0L);

	/*
	 * 5a.  If the listbox expanded below the group box, then size
	 *      the groupbox down, move the label static and exit controls
	 *      down, and expand the entire dialog appropriately.
	 */

	GetWindowRect(hList, &rc);
	GetWindowRect(GetDlgItem(hDlg, ID_GROUP), &rcG);

	if (rc.bottom > rcG.bottom)
		{
		//Calculate amount to move things down.
		cyList=(rcG.bottom-rcG.top)-(rc.bottom-rc.top-cyList);

		//Expand the group box.
		rcG.right -=rcG.left;
		rcG.bottom-=rcG.top;
		SetWindowPos(GetDlgItem(hDlg, ID_GROUP), NULL, 0, 0
					 , rcG.right, rcG.bottom+cyList
					 , SWP_NOMOVE | SWP_NOZORDER);

		//Expand the dialog box.
		GetClientRect(hDlg, &rc);
		SetWindowPos(hDlg, NULL, 0, 0, rc.right, rc.bottom+cyList
					 , SWP_NOMOVE | SWP_NOZORDER);

		//Move the label and edit controls down.
		GetClientRect(GetDlgItem(hDlg, ID_LABEL), &rc);
		SetWindowPos(GetDlgItem(hDlg, ID_LABEL), NULL, 0, cyList
					 , rc.right, rc.bottom, SWP_NOSIZE | SWP_NOZORDER);

		GetClientRect(GetDlgItem(hDlg, ID_LABELEDIT), &rc);
		SetWindowPos(GetDlgItem(hDlg, ID_LABELEDIT), NULL, 0, cyList
					 , rc.right, rc.bottom, SWP_NOSIZE | SWP_NOZORDER);
		}


	/*
	 * 6.  Select Current, Default, or From File radiobuttons appropriately.
	 *     The CheckRadioButton call sends WM_COMMANDs which handle
	 *     other actions.  Note that if we check From File, which
	 *     takes an icon from the list, we better fill the list.
	 *     This will also fill the list even if default is selected.
	 */

	if (0!=UFillIconList(hDlg, ID_ICONLIST, lpCI->szFile))
		{
		//If szFile worked, then select the source icon in the listbox.
		SendDlgItemMessage(hDlg, ID_ICONLIST, LB_SETCURSEL, lpCI->iIcon, 0L);
		}


	if (lpCI->dwFlags & CIF_SELECTCURRENT)
		CheckRadioButton(hDlg, ID_CURRENT, ID_FROMFILE, ID_CURRENT);
	else
		{
		uID=(lpCI->dwFlags & CIF_SELECTFROMFILE) ? ID_FROMFILE : ID_DEFAULT;
		CheckRadioButton(hDlg, ID_CURRENT, ID_FROMFILE, uID);
		}

	//7.  Give our parent window access to our hDlg (via a special SetProp).
	//    The PasteSpecial dialog may need to force our dialog down if the
	//    clipboard contents change underneath it. if so it will send
	//    us a IDCANCEL command.
	SetProp(lpCI->lpOCI->hWndOwner, PROP_HWND_CHGICONDLG, hDlg);

	lpCI->nBrowseHelpID = RegisterWindowMessage(HELPMSGSTRING);

	//8.  Call the hook with lCustData in lParam
	UStandardHook(lpCI, hDlg, WM_INITDIALOG, wParam, lpOCI->lCustData);
	return TRUE;
	}





/*
 * UFillIconList
 *
 * Purpose:
 *  Given a listbox and a filename, attempts to open that file and
 *  read all the icons that exist therein, adding them to the listbox
 *  hList as owner-draw items.  If the file does not exist or has no
 *  icons, then you get no icons and an appropriate warning message.
 *
 * Parameters:
 *  hDlg            HWND of the dialog containing the listbox.
 *  idList          UINT identifier of the listbox to fill.
 *  pszFile         LPSTR of the file from which to extract icons.
 *
 * Return Value:
 *  UINT            Number of items added to the listbox.  0 on failure.
 */

UINT UFillIconList(HWND hDlg, UINT idList, LPSTR pszFile)
	{
	HWND        hList;
	UINT        i;
	UINT        cIcons=0;
	HCURSOR     hCur;
	HICON       hIcon;
	OFSTRUCT    of;

	if (NULL==hDlg || !IsWindow(hDlg) || NULL==pszFile)
		return 0;

	hList=GetDlgItem(hDlg, idList);

	if (NULL==hList)
		return 0;

	//Clean out the listbox.
	SendMessage(hList, LB_RESETCONTENT, 0, 0L);

	//If we have an empty string, just exit leaving the listbox empty as well
	if (0==lstrlen(pszFile))
		return 0;

	//Turn on the hourglass
	hCur=HourGlassOn();

	//Check if the file is valid.
	if (HFILE_ERROR!=DoesFileExist(pszFile, &of))
		{
	   #ifdef EXTRACTICONWORKS
		//Get the icon count for this file.
		cIcons=(UINT)ExtractIcon(ghInst, pszFile, (UINT)-1);
	   #else
		/*
		 * ExtractIcon in Windows 3.1 with -1 eats a selector, leaving an
		 * extra global memory object around for this applciation.  Since
		 * changing icons may happen very often with all OLE apps in
		 * the system, we have to work around it.  So we'll say we
		 * have lots of icons and just call ExtractIcon until it
		 * fails.  We check if there's any around by trying to get
		 * the first one.
		 */
		cIcons=0xFFFF;

		hIcon=ExtractIcon(ghInst, pszFile, 0);

		//Fake a failure with cIcons=0, or cleanup hIcon from this test.
		if (32 > (UINT)hIcon)
			cIcons=0;
		else
			DestroyIcon(hIcon);
	   #endif

		if (0!=cIcons)
			{
			SendMessage(hList, WM_SETREDRAW, FALSE, 0L);

			for (i=0; i<cIcons; i++)
				{
				hIcon=ExtractIcon(ghInst, pszFile, i);

				if (32 < (UINT)hIcon)
					SendMessage(hList, LB_ADDSTRING, 0, (LONG)(UINT)hIcon);
			   #ifndef EXTRACTICONWORKS
				else
					{
					//ExtractIcon failed, so let's leave now.
					break;
					}
			   #endif
				}

			//Force complete repaint
			SendMessage(hList, WM_SETREDRAW, TRUE, 0L);
			InvalidateRect(hList, NULL, TRUE);

			//Select an icon
			SendMessage(hList, LB_SETCURSEL, 0, 0L);
			}
		else
			ErrorWithFile(hDlg, ghInst, (UINT)IDS_CINOICONSINFILE, pszFile, MB_OK);
		}
	else
		OpenFileError(hDlg, of.nErrCode, pszFile);

	HourGlassOff(hCur);
	return cIcons;
	}




/*
 * FDrawListIcon
 *
 * Purpose:
 *  Handles WM_DRAWITEM for the icon listbox.
 *
 * Parameters:
 *  lpDI            LPDRAWITEMSTRUCT from WM_DRAWITEM
 *
 * Return Value:
 *  BOOL            TRUE if we did anything, FALSE if there are no items
 *                  in the list.
 */

BOOL FDrawListIcon(LPDRAWITEMSTRUCT lpDI)
	{
	COLORREF        cr;

	/*
	 * If there are no items in the list, then itemID is negative according
	 * to the Win3.1 SDK.  Unfortunately DRAWITEMSTRUCT has an unsigned int
	 * for this field, so we need the typecast to do a signed comparison.
	 */
	if ((int)lpDI->itemID < 0)
		return FALSE;

	/*
	 * For selection or draw entire case we just draw the entire item all
	 * over again.  For focus cases, we only call DrawFocusRect.
	 */

	if (lpDI->itemAction & (ODA_SELECT | ODA_DRAWENTIRE))
		{
		//Clear background and draw the icon.
		if (lpDI->itemState & ODS_SELECTED)
			cr=SetBkColor(lpDI->hDC, GetSysColor(COLOR_HIGHLIGHT));
		else
			cr=SetBkColor(lpDI->hDC, GetSysColor(COLOR_WINDOW));

		//Draw a cheap rectangle.
		ExtTextOut(lpDI->hDC, 0, 0, ETO_OPAQUE, &lpDI->rcItem
				   , NULL, 0, NULL);

		DrawIcon(lpDI->hDC, lpDI->rcItem.left+(CXICONPAD/2)
				 , lpDI->rcItem.top+(CYICONPAD/2)
				 , (HICON)LOWORD(lpDI->itemData));

		//Restore original background for DrawFocusRect
		SetBkColor(lpDI->hDC, cr);
		}

	//Always change focus on the focus action.
	if (lpDI->itemAction & ODA_FOCUS || lpDI->itemState & ODS_FOCUS)
		DrawFocusRect(lpDI->hDC, &lpDI->rcItem);

	return TRUE;
	}





/*
 * UpdateResultIcon
 *
 * Purpose:
 *  Updates the result icon using the current icon in the default display
 *  or the icon listbox depending on fFromDefault.
 *
 * Parameters:
 *  lpCI            LPCHANGEICON containing dialog flags.
 *  hDlg            HWND of the dialog
 *  uID             UINT identifying the radiobutton selected.
 *
 * Return Value:
 *  None
 */

void UpdateResultIcon(LPCHANGEICON lpCI, HWND hDlg, UINT uID)
	{
	UINT        iSel;
	LONG        lTemp=LB_ERR;

	lpCI->dwFlags &= ~(CIF_SELECTCURRENT | CIF_SELECTDEFAULT | CIF_SELECTFROMFILE);

	switch (uID)
		{
		case ID_CURRENT:
			lTemp=SendDlgItemMessage(hDlg, ID_CURRENTICON, STM_GETICON, 0, 0L);
			lpCI->dwFlags |= CIF_SELECTCURRENT;
			break;

		case ID_DEFAULT:
			lTemp=SendDlgItemMessage(hDlg, ID_DEFAULTICON, STM_GETICON, 0, 0L);
			lpCI->dwFlags |= CIF_SELECTDEFAULT;
			break;

		case ID_FROMFILE:
			//Get the selected icon from the list and place it in the result
			lpCI->dwFlags |= CIF_SELECTFROMFILE;

			iSel=(UINT)SendDlgItemMessage(hDlg, ID_ICONLIST, LB_GETCURSEL, 0, 0L);
			if ((UINT)LB_ERR==iSel)
				lTemp=SendDlgItemMessage(hDlg, ID_DEFAULTICON, STM_GETICON, 0, 0L);
			else
				SendDlgItemMessage(hDlg, ID_ICONLIST, LB_GETTEXT, iSel
							   , (LPARAM)(LPLONG)&lTemp);

			break;
		}

	if ((LONG)LB_ERR!=lTemp)
		SendDlgItemMessage(hDlg, ID_RESULTICON, STM_SETICON, LOWORD(lTemp), 0L);
	return;
	}
