/*
 * INSOBJ.C
 *
 * Implements the OleUIInsertObject function which invokes the complete
 * Insert Object dialog.  Makes use of the OleChangeIcon function in
 * ICON.C.
 *
 * Copyright (c)1993 Microsoft Corporation, All Rights Reserved
 */

#define STRICT  1
#include "ole2ui.h"
#include <commdlg.h>
#include <memory.h>
#include <direct.h>
#include <malloc.h>
#include <dos.h>
#include "common.h"
#include "utility.h"
#include "icon.h"
#include "insobj.h"
#include "resimage.h"
#include "iconbox.h"
#include "geticon.h"

#define IS_FILENAME_DELIM(c)    ( (c) == '\\' || (c) == '/' || (c) == ':' )

/*
 * OleUIInsertObject
 *
 * Purpose:
 *  Invokes the standard OLE Insert Object dialog box allowing the
 *  user to select an object source and classname as well as the option
 *  to display the object as itself or as an icon.
 *
 * Parameters:
 *  lpIO            LPOLEUIINSERTOBJECT 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) OleUIInsertObject(LPOLEUIINSERTOBJECT lpIO)
	{
	UINT        uRet;
	HGLOBAL     hMemDlg=NULL;
	HRESULT     hrErr;

	uRet=UStandardValidation((LPOLEUISTANDARD)lpIO, sizeof(OLEUIINSERTOBJECT)
							 , &hMemDlg);

	if (OLEUI_SUCCESS!=uRet)
		return uRet;

	//Now we can do Insert Object specific validation.


	// NULL is NOT valid for lpszFile
	if (   (NULL == lpIO->lpszFile)
		|| (IsBadReadPtr(lpIO->lpszFile, lpIO->cchFile))
		|| (IsBadWritePtr(lpIO->lpszFile, lpIO->cchFile)) )
	 uRet=OLEUI_IOERR_LPSZFILEINVALID;

	if (NULL != lpIO->lpszFile
		&& (lpIO->cchFile <= 0 || lpIO->cchFile > OLEUI_CCHPATHMAX))
	 uRet=OLEUI_IOERR_CCHFILEINVALID;

	if (0!=lpIO->cClsidExclude)
		{
		if (NULL!=lpIO->lpClsidExclude && IsBadReadPtr(lpIO->lpClsidExclude
			, lpIO->cClsidExclude*sizeof(CLSID)))
		uRet=OLEUI_IOERR_LPCLSIDEXCLUDEINVALID;
		}

	//If we have flags to create any object, validate necessary data.
	if (lpIO->dwFlags & (IOF_CREATENEWOBJECT | IOF_CREATEFILEOBJECT | IOF_CREATELINKOBJECT))
		{
		if (NULL!=lpIO->lpFormatEtc
			&& IsBadReadPtr(lpIO->lpFormatEtc, sizeof(FORMATETC)))
			uRet=OLEUI_IOERR_LPFORMATETCINVALID;

		if (NULL!=lpIO->ppvObj && IsBadWritePtr(lpIO->ppvObj, sizeof(LPVOID)))
			uRet=OLEUI_IOERR_PPVOBJINVALID;

		if (NULL!=lpIO->lpIOleClientSite
			&& IsBadReadPtr(lpIO->lpIOleClientSite->lpVtbl, sizeof(IOleClientSiteVtbl)))
			uRet=OLEUI_IOERR_LPIOLECLIENTSITEINVALID;

		if (NULL!=lpIO->lpIStorage
			&& IsBadReadPtr(lpIO->lpIStorage->lpVtbl, sizeof(IStorageVtbl)))
			uRet=OLEUI_IOERR_LPISTORAGEINVALID;
		}

	if (OLEUI_ERR_STANDARDMIN <= uRet)
		{
		if (NULL!=hMemDlg)
			FreeResource(hMemDlg);

		return uRet;
		}

	//Now that we've validated everything, we can invoke the dialog.
	uRet=UStandardInvocation(InsertObjectDialogProc, (LPOLEUISTANDARD)lpIO
							 , hMemDlg, MAKEINTRESOURCE(IDD_INSERTOBJECT));


	//Stop here if we cancelled or had an error.
	if (OLEUI_SUCCESS !=uRet && OLEUI_OK!=uRet)
		return uRet;


	/*
	 * If any of the flags specify that we're to create objects on return
	 * from this dialog, then do so.  If we encounter an error in this
	 * processing, we return OLEUI_IOERR_SCODEHASERROR.  Since the
	 * three select flags are mutually exclusive, we don't have to
	 * if...else here, just if each case (keeps things cleaner that way).
	 */

	lpIO->sc=S_OK;

	//Check if Create New was selected and we have IOF_CREATENEWOBJECT
	if ((lpIO->dwFlags & IOF_SELECTCREATENEW) && (lpIO->dwFlags & IOF_CREATENEWOBJECT))
		{
		hrErr=OleCreate(&lpIO->clsid, &lpIO->iid, lpIO->oleRender
			, lpIO->lpFormatEtc, lpIO->lpIOleClientSite, lpIO->lpIStorage
			, lpIO->ppvObj);
		lpIO->sc = GetScode(hrErr);
		}

	//Try Create From File
	if ((lpIO->dwFlags & IOF_SELECTCREATEFROMFILE))
		{
		if (!(lpIO->dwFlags & IOF_CHECKLINK) && (lpIO->dwFlags & IOF_CREATEFILEOBJECT))
			{
			hrErr=OleCreateFromFile(&CLSID_NULL, lpIO->lpszFile, &lpIO->iid
				, lpIO->oleRender, lpIO->lpFormatEtc, lpIO->lpIOleClientSite
				, lpIO->lpIStorage, lpIO->ppvObj);
			lpIO->sc = GetScode(hrErr);
			}

		if ((lpIO->dwFlags & IOF_CHECKLINK) && (lpIO->dwFlags & IOF_CREATELINKOBJECT))
			{
			hrErr=OleCreateLinkToFile(lpIO->lpszFile, &lpIO->iid
				, lpIO->oleRender, lpIO->lpFormatEtc, lpIO->lpIOleClientSite
				, lpIO->lpIStorage, lpIO->ppvObj);
			lpIO->sc = GetScode(hrErr);
			}
		}

	//If we tried but failed a create option, then return the appropriate error
	if (S_OK!=lpIO->sc)
		uRet=OLEUI_IOERR_SCODEHASERROR;

	return uRet;
	}





/* wGetFileTitle
** -------------
**    Dynamically link to COMMDLG.DLL to call the GetFileTitle API
*/
static int wGetFileTitle(LPCSTR lpszFile, LPSTR lpszTitle, UINT cbBuf)
{
#if !defined( LINK_COMMDLG )
	HINSTANCE hinstCommDlg = NULL;
	typedef int (WINAPI* LPFNGETFILETITLE) (LPCSTR, LPSTR, UINT);
	LPFNGETFILETITLE lpfnGetFileTitle;
	int iResult = -1;

	// Load the COMMDLG.DLL library module
	hinstCommDlg = LoadLibrary("COMMDLG.DLL");
	if (hinstCommDlg > HINSTANCE_ERROR) {  /* loaded successfully */
		// Retrieve the address of the GetFileTitle function
		lpfnGetFileTitle = (LPFNGETFILETITLE)
				GetProcAddress(hinstCommDlg, "GetFileTitle");
		if (lpfnGetFileTitle != NULL) {
			// Call the GetFileTitle function
			iResult = (*lpfnGetFileTitle) ((LPCSTR)lpszFile,
					(LPSTR)lpszTitle, cbBuf);
		}
		FreeLibrary(hinstCommDlg);
		return iResult;
	}
#else
	return GetFileTitle((LPCSTR)lpszFile, (LPSTR)lpszTitle, cbBuf);
#endif
}



/*
 * InsertObjectDialogProc
 *
 * Purpose:
 *  Implements the OLE Insert Object dialog as invoked through the
 *  OleUIInsertObject function.
 */

BOOL CALLBACK EXPORT InsertObjectDialogProc(HWND hDlg, UINT iMsg
	, WPARAM wParam, LPARAM lParam)
	{
	LPOLEUIINSERTOBJECT     lpOIO;
	LPINSERTOBJECT          lpIO;
	OLEUICHANGEICON         ci;
	UINT                    i;
	BOOL                    fCheck=FALSE;
	UINT                    uRet=0;

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

	//This will fail under WM_INITDIALOG, where we allocate it.
	lpIO=(LPINSERTOBJECT)LpvStandardEntry(hDlg, iMsg, wParam, lParam, &uRet);

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

	//Process help message from Change Icon
	if (iMsg==uMsgHelp)
		{
		PostMessage(lpIO->lpOIO->hWndOwner, uMsgHelp, wParam, lParam);
		return FALSE;
		}

	//Process the temination message
	if (iMsg==uMsgEndDialog)
		{
		InsertObjectCleanup(hDlg);
		StandardCleanup(lpIO, hDlg);
		EndDialog(hDlg, wParam);
		return TRUE;
		}

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

		case WM_COMMAND:
			switch (wID)
				{
				case ID_IO_CREATENEW:
					FToggleObjectSource(hDlg, lpIO, IOF_SELECTCREATENEW);
					break;

				case ID_IO_CREATEFROMFILE:
					FToggleObjectSource(hDlg, lpIO, IOF_SELECTCREATEFROMFILE);
					break;

				case ID_IO_LINKFILE:
					fCheck=IsDlgButtonChecked(hDlg, wID);

					if (fCheck)
						lpIO->dwFlags |=IOF_CHECKLINK;
					else
						lpIO->dwFlags &=~IOF_CHECKLINK;

					//Results change here, so be sure to update it.
					SetInsertObjectResults(hDlg, lpIO);
					UpdateClassIcon(hDlg, lpIO, NULL);
					break;

				case ID_IO_OBJECTTYPELIST:
					switch (wCode)
						{
						case LBN_SELCHANGE:
							UpdateClassIcon(hDlg, lpIO, hWndMsg);
							SetInsertObjectResults(hDlg, lpIO);
							break;

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


				case ID_IO_FILEDISPLAY:
					//If there are characters, enable OK and Display As Icon
					if (EN_CHANGE==wCode)
					{
						lpIO->fFileDirty = TRUE;
						lpIO->fFileValid = FALSE;

						lpIO->fFileSelected=
							(0L!=SendMessage(hWndMsg, EM_LINELENGTH, 0, 0L));
						EnableWindow(GetDlgItem(hDlg, ID_IO_LINKFILE), lpIO->fFileSelected);
						EnableWindow(GetDlgItem(hDlg, ID_IO_DISPLAYASICON), lpIO->fFileSelected);
						EnableWindow(GetDlgItem(hDlg, ID_IO_CHANGEICON), lpIO->fFileSelected);
						EnableWindow(GetDlgItem(hDlg, IDOK), lpIO->fFileSelected);
					}

					if (EN_KILLFOCUS==wCode && NULL!=lpIO)
					{
						if (FValidateInsertFile(hDlg,FALSE,&lpIO->nErrCode)) {
							lpIO->fFileDirty = FALSE;
							lpIO->fFileValid = TRUE;
							UpdateClassIcon(hDlg, lpIO, NULL);
							UpdateClassType(hDlg, lpIO, TRUE);
						} else {
							lpIO->fFileDirty = FALSE;
							lpIO->fFileValid = FALSE;
							UpdateClassType(hDlg, lpIO, FALSE);
						}
					}
					break;


				case ID_IO_DISPLAYASICON:
					fCheck=IsDlgButtonChecked(hDlg, wID);
					EnableWindow(GetDlgItem(hDlg, ID_IO_CHANGEICON), fCheck);

					if (fCheck)
						lpIO->dwFlags |=IOF_CHECKDISPLAYASICON;
					else
						lpIO->dwFlags &=~IOF_CHECKDISPLAYASICON;

					//Update the internal flag based on this checking
					if (lpIO->dwFlags & IOF_SELECTCREATENEW)
						lpIO->fAsIconNew=fCheck;
					else
						lpIO->fAsIconFile=fCheck;

					//Re-read the class icon on Display checked
					if (fCheck)
					{
						if (lpIO->dwFlags & IOF_SELECTCREATEFROMFILE)
						{
						  if (FValidateInsertFile(hDlg, TRUE,&lpIO->nErrCode))
						  {
							lpIO->fFileDirty = FALSE;
							lpIO->fFileValid = TRUE;
							UpdateClassIcon(hDlg, lpIO,
											GetDlgItem(hDlg, ID_IO_OBJECTTYPELIST));

							UpdateClassType(hDlg, lpIO, TRUE);
						  }

						  else
						  {
							HWND hWndEC;

							lpIO->fAsIconFile= FALSE;
							lpIO->fFileDirty = FALSE;
							lpIO->fFileValid = FALSE;
							SendDlgItemMessage(hDlg, ID_IO_ICONDISPLAY, IBXM_IMAGESET, 0, 0L);
							UpdateClassType(hDlg, lpIO, FALSE);

							lpIO->dwFlags &=~IOF_CHECKDISPLAYASICON;
							CheckDlgButton(hDlg, ID_IO_DISPLAYASICON, 0);

							hWndEC = GetDlgItem(hDlg, ID_IO_FILEDISPLAY);
							SetFocus(hWndEC);
							SendMessage(hWndEC, EM_SETSEL, 0, MAKELPARAM(0, (WORD)-1));
							return TRUE;
						  }
						}
						else
						  UpdateClassIcon(hDlg, lpIO,
										  GetDlgItem(hDlg, ID_IO_OBJECTTYPELIST));
					}


					//Results change here, so be sure to update it.
					SetInsertObjectResults(hDlg, lpIO);


					/*
					 * Show or hide controls as appropriate.  Do the icon
					 * display last because it will take some time to repaint.
					 * If we do it first then the dialog looks too sluggish.
					 */
					i=(fCheck) ? SW_SHOWNORMAL : SW_HIDE;
					StandardShowDlgItem(hDlg, ID_IO_CHANGEICON, i);
					StandardShowDlgItem(hDlg, ID_IO_ICONDISPLAY, i);

					break;


				case ID_IO_CHANGEICON:
				{

					LPMALLOC  pIMalloc;
					HWND      hList;
					LPSTR     pszString, pszCLSID;

					int       iCurSel;

					// if we're in SELECTCREATEFROMFILE mode, then we need to Validate
					// the contents of the edit control first.

					if (lpIO->dwFlags & IOF_SELECTCREATEFROMFILE)
					{
					   if (   lpIO->fFileDirty
						   && !FValidateInsertFile(hDlg, TRUE, &lpIO->nErrCode) )
					   {
						  HWND hWndEC;

						  lpIO->fFileDirty = TRUE;
						  hWndEC = GetDlgItem(hDlg, ID_IO_FILEDISPLAY);
						  SetFocus(hWndEC);
						  SendMessage(hWndEC, EM_SETSEL, 0, MAKELPARAM(0, (WORD)-1));
						  return TRUE;
					   }
					   else
						  lpIO->fFileDirty = FALSE;
					}



					//Initialize the structure for the hook.
					_fmemset((LPOLEUICHANGEICON)&ci, 0, sizeof(ci));

					ci.hMetaPict=(HGLOBAL)SendDlgItemMessage(hDlg
						, ID_IO_ICONDISPLAY, IBXM_IMAGEGET, 0, 0L);

					ci.cbStruct =sizeof(ci);
					ci.hWndOwner=hDlg;
					ci.dwFlags  =CIF_SELECTCURRENT;

					if (lpIO->dwFlags & IOF_SHOWHELP)
						ci.dwFlags |= CIF_SHOWHELP;




					if (lpIO->dwFlags & IOF_SELECTCREATENEW)
					{
					   // Initialize clsid...
					   if (NOERROR != CoGetMalloc(MEMCTX_TASK, &pIMalloc))
						 return FALSE;

					   pszString = (LPSTR)pIMalloc->lpVtbl->Alloc(pIMalloc, OLEUI_CCHKEYMAX + OLEUI_CCHCLSIDSTRING);


					   hList = GetDlgItem(hDlg, ID_IO_OBJECTTYPELIST);
					   iCurSel = (int)SendMessage(hList, LB_GETCURSEL, 0, 0L);
					   SendMessage(hList, LB_GETTEXT, iCurSel, (LONG)pszString);

					   pszCLSID = PointerToNthField(pszString, 2, '\t');

					   CLSIDFromString((LPSTR)pszCLSID, (LPCLSID)&(ci.clsid));

					   pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)pszString);
					   pIMalloc->lpVtbl->Release(pIMalloc);
					}
					else  // IOF_SELECTCREATEFROMFILE
					{

					   char  szFileName[OLEUI_CCHPATHMAX];

					   GetDlgItemText(hDlg, ID_IO_FILEDISPLAY, (LPSTR)szFileName, OLEUI_CCHPATHMAX);

					   if (NOERROR != GetClassFile((LPSTR)szFileName, (LPCLSID)&(ci.clsid)))
					   {
						  LPSTR lpszExtension;
						  int   istrlen;

						  istrlen = lstrlen(szFileName);

						  lpszExtension = (LPSTR)szFileName + istrlen -1;

						  while ( (lpszExtension > szFileName) &&
								  (*lpszExtension != '.') )
							lpszExtension--;

						  GetAssociatedExecutable(lpszExtension, (LPSTR)ci.szIconExe);
						  ci.cchIconExe = lstrlen(ci.szIconExe);
						  ci.dwFlags |= CIF_USEICONEXE;

					   }
					}


					//Let the hook in to customize Change Icon if desired.
					uRet=UStandardHook(lpIO, hDlg, uMsgChangeIcon
						, 0, (LONG)(LPSTR)&ci);

					if (0==uRet)
						uRet=(UINT)(OLEUI_OK==OleUIChangeIcon(&ci));

					//Update the display and itemdata if necessary.
					if (0!=uRet)
					{

						/*
						 * OleUIChangeIcon will have already freed our
						 * current hMetaPict that we passed in when OK is
						 * pressed in that dialog.  So we use 0L as lParam
						 * here so the IconBox doesn't try to free the
						 * metafilepict again.
						 */
						SendDlgItemMessage(hDlg, ID_IO_ICONDISPLAY, IBXM_IMAGESET
							, (WPARAM)ci.hMetaPict, 0L);

						if (lpIO->dwFlags & IOF_SELECTCREATENEW)
						  SendMessage(hList, LB_SETITEMDATA, iCurSel, MAKELPARAM(ci.hMetaPict, 0));
					}
				}
					break;


				case ID_IO_FILE:
					{
					/*
					 * 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_IO_BROWSE to customize the dialog and from
					 * trying to figure out what we do after we have the name.
					 */

					char    szTemp[OLEUI_CCHPATHMAX];
					char    szInitialDir[OLEUI_CCHPATHMAX];
					DWORD   dwOfnFlags;
					int     nChars;
					BOOL    fUseInitialDir = FALSE;


					nChars = GetDlgItemText(hDlg, ID_IO_FILEDISPLAY, (LPSTR)szTemp, OLEUI_CCHPATHMAX);

					if (FValidateInsertFile(hDlg, FALSE, &lpIO->nErrCode))
					{

						int istrlen;

						wGetFileTitle((LPSTR)szTemp, lpIO->szFile, OLEUI_CCHPATHMAX);

						istrlen = lstrlen(lpIO->szFile);

						LSTRCPYN((LPSTR)szInitialDir, szTemp, nChars - istrlen);
						fUseInitialDir = TRUE;

					}
					else  // file name isn't valid...lop off end of szTemp to get a
						  // valid directory
					{
#if defined( WIN32 )
						char szBuffer[OLEUI_CCHPATHMAX];
						DWORD Attribs;

						LSTRCPYN(szBuffer, szTemp, sizeof(szBuffer)-1);
						szBuffer[sizeof(szBuffer)-1] = '\0';

						if ('\\' == szBuffer[nChars-1])
						   szBuffer[nChars-1] = '\0';

						Attribs = GetFileAttributes(szBuffer);
						if (Attribs != 0xffffffff &&
						   (Attribs & FILE_ATTRIBUTE_DIRECTORY) )
						{
						   lstrcpy(szInitialDir, (LPSTR)szBuffer);
						   fUseInitialDir = TRUE;
						}
#else
						static char szBuffer[OLEUI_CCHPATHMAX];
						static int  attrib ;

						LSTRCPYN(szBuffer, szTemp, sizeof(szBuffer)-1);
						szBuffer[sizeof(szBuffer)-1] = '\0';

						AnsiToOem(szBuffer, szBuffer);
#if defined( OBSOLETE )     // fix bug# 3575
						if ('\\' == szBuffer[nChars-1])
						   szBuffer[nChars-1] = '\0';

						if(0 == _dos_getfileattr(szBuffer, &attrib))
#endif  // OBSOLETE
						{
						   lstrcpy(szInitialDir, (LPSTR)szBuffer);
						   fUseInitialDir = TRUE;
						}
#endif
						*lpIO->szFile = '\0';
					}

					uRet=UStandardHook(lpIO, hDlg, uMsgBrowse
						, OLEUI_CCHPATHMAX, (LPARAM)(LPSTR)lpIO->szFile);

					dwOfnFlags = OFN_FILEMUSTEXIST;

					if (lpIO->lpOIO->dwFlags & IOF_SHOWHELP)
					   dwOfnFlags |= OFN_SHOWHELP;

					if (0==uRet)
						uRet=(UINT)Browse(hDlg,
										  lpIO->szFile,
										  fUseInitialDir ? (LPSTR)szInitialDir : NULL,
										  OLEUI_CCHPATHMAX,
										  (UINT)IDS_FILTERS,
										  dwOfnFlags);

					//Only update if the file changed.
					if (0!=uRet && 0!=lstrcmpi(szTemp, lpIO->szFile))
					{
						SetDlgItemText(hDlg, ID_IO_FILEDISPLAY, lpIO->szFile);
						lpIO->fFileSelected=TRUE;

						if (FValidateInsertFile(hDlg, TRUE, &lpIO->nErrCode))
						{
						  lpIO->fFileDirty = FALSE;
						  lpIO->fFileValid = TRUE;
						  UpdateClassIcon(hDlg, lpIO, NULL);
						  UpdateClassType(hDlg, lpIO, TRUE);
						  // auto set OK to be default button if valid file
						  SendMessage(hDlg, DM_SETDEFID,
								  (WPARAM)GetDlgItem(hDlg, IDOK), 0L);
						  SetFocus(GetDlgItem(hDlg, IDOK));
						}
						else  // filename is invalid - set focus back to ec
						{
						  HWND hWnd;

						  lpIO->fFileDirty = FALSE;
						  lpIO->fFileValid = FALSE;
						  hWnd = GetDlgItem(hDlg, ID_IO_FILEDISPLAY);
						  SetFocus(hWnd);
						  SendMessage(hWnd, EM_SETSEL, 0, MAKELPARAM(0, (WORD)-1));
						}

						//Once we have a file, Display As Icon is always enabled
						EnableWindow(GetDlgItem(hDlg, ID_IO_DISPLAYASICON), TRUE);

						//As well as OK
						EnableWindow(GetDlgItem(hDlg, IDOK), TRUE);

					}
				}
				break;


				case IDOK:
				{
					HWND    hListBox;
					WORD    iCurSel;
					char    szBuffer[OLEUI_CCHKEYMAX + OLEUI_CCHCLSIDSTRING];
					LPSTR   lpszCLSID;

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



					// If the file name is clean (already validated), or
					// if Create New is selected, then we can skip this part.

					if (  (lpIO->dwFlags & IOF_SELECTCREATEFROMFILE)
					   && (TRUE == lpIO->fFileDirty) )
					{

						if (FValidateInsertFile(hDlg, TRUE, &lpIO->nErrCode))
						{
						  lpIO->fFileDirty = FALSE;
						  lpIO->fFileValid = TRUE;
						  UpdateClassIcon(hDlg, lpIO, NULL);
						  UpdateClassType(hDlg, lpIO, TRUE);
						}
						else  // filename is invalid - set focus back to ec
						{
						  HWND hWnd;

						  lpIO->fFileDirty = FALSE;
						  lpIO->fFileValid = FALSE;
						  hWnd = GetDlgItem(hDlg, ID_IO_FILEDISPLAY);
						  SetFocus(hWnd);
						  SendMessage(hWnd, EM_SETSEL, 0, MAKELPARAM(0, (WORD)-1));
						  UpdateClassType(hDlg, lpIO, FALSE);
						}

						return TRUE;  // eat this message
					}
					else if (  (lpIO->dwFlags & IOF_SELECTCREATEFROMFILE)
					   && (FALSE == lpIO->fFileValid) )
					{
						// filename is invalid - set focus back to ec
						HWND hWnd;
						char        szFile[OLEUI_CCHPATHMAX];

						if (0!=GetDlgItemText(hDlg, ID_IO_FILEDISPLAY,
											szFile, sizeof(szFile)))
						{
							OpenFileError(hDlg, lpIO->nErrCode, szFile);
						}
						lpIO->fFileDirty = FALSE;
						lpIO->fFileValid = FALSE;
						hWnd = GetDlgItem(hDlg, ID_IO_FILEDISPLAY);
						SetFocus(hWnd);
						SendMessage(hWnd, EM_SETSEL, 0, MAKELPARAM(0, (WORD)-1));
						UpdateClassType(hDlg, lpIO, FALSE);
						return TRUE;  // eat this message
					}

					//Copy the necessary information back to the original struct
					lpOIO=lpIO->lpOIO;
					lpOIO->dwFlags=lpIO->dwFlags;

					if (lpIO->dwFlags & IOF_SELECTCREATENEW)
					{
					   hListBox=GetDlgItem(hDlg, ID_IO_OBJECTTYPELIST);
					   iCurSel=(WORD)SendMessage(hListBox, LB_GETCURSEL, 0, 0);

					   if (lpIO->dwFlags & IOF_CHECKDISPLAYASICON)
					   {
						   lpOIO->hMetaPict=(HGLOBAL)SendMessage(hListBox,
							   LB_GETITEMDATA, iCurSel, 0L);

						   /*
							* Set the item data to 0 here so that the cleanup
							* code doesn't delete the metafile.
							*/
						   SendMessage(hListBox, LB_SETITEMDATA, iCurSel, 0L);
					   }
					   else
						   lpOIO->hMetaPict = (HGLOBAL)NULL;

					   SendMessage(hListBox, LB_GETTEXT, iCurSel
						   , (LPARAM)(LPSTR)szBuffer);

					   lpszCLSID=PointerToNthField((LPSTR)szBuffer, 2, '\t');
					   CLSIDFromString(lpszCLSID, &lpOIO->clsid);

					}
					else  // IOF_SELECTCREATEFROMFILE
					{
					   if (lpIO->dwFlags & IOF_CHECKDISPLAYASICON)
					   {
							 // get metafile here
						  lpOIO->hMetaPict = (HGLOBAL)SendDlgItemMessage(hDlg,
																		 ID_IO_ICONDISPLAY,
																		 IBXM_IMAGEGET,
																		 0, 0L);


					   }
					   else
						 lpOIO->hMetaPict = (HGLOBAL)NULL;

					}

					   GetDlgItemText(hDlg, ID_IO_FILEDISPLAY,
									  lpIO->szFile, lpOIO->cchFile);

					   LSTRCPYN(lpOIO->lpszFile, lpIO->szFile, lpOIO->cchFile);

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

				case IDCANCEL:
					SendMessage(hDlg, uMsgEndDialog, OLEUI_CANCEL, 0L);
					break;

				case ID_OLEUIHELP:
					PostMessage(lpIO->lpOIO->hWndOwner, uMsgHelp
								, (WPARAM)hDlg, MAKELPARAM(IDD_INSERTOBJECT, 0));
					break;
				}
			break;

		default:
		{
			if (lpIO && iMsg == lpIO->nBrowseHelpID) {
				PostMessage(lpIO->lpOIO->hWndOwner, uMsgHelp,
						(WPARAM)hDlg, MAKELPARAM(IDD_INSERTFILEBROWSE, 0));
			}
		}
		break;
		}

	return FALSE;
	}


/*
 * FInsertObjectInit
 *
 * Purpose:
 *  WM_INITIDIALOG handler for the Insert Object 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 FInsertObjectInit(HWND hDlg, WPARAM wParam, LPARAM lParam)
	{
	LPOLEUIINSERTOBJECT     lpOIO;
	LPINSERTOBJECT          lpIO;
	RECT                    rc;
	DWORD                   dw;
	HFONT                   hFont;
	HWND                    hList;
	UINT                    u;
	BOOL                    fCheck;
	char                   *pch;

	//1.  Copy the structure at lParam into our instance memory.
	lpIO=(LPINSERTOBJECT)LpvStandardInit(hDlg, sizeof(INSERTOBJECT), TRUE, &hFont);

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

	lpOIO=(LPOLEUIINSERTOBJECT)lParam;

	//2.  Save the original pointer and copy necessary information.
	lpIO->lpOIO  =lpOIO;
	lpIO->dwFlags=lpOIO->dwFlags;
	lpIO->clsid  =lpOIO->clsid;

	if ( (lpOIO->lpszFile) && ('\0' != *lpOIO->lpszFile) )
		LSTRCPYN((LPSTR)lpIO->szFile, lpOIO->lpszFile, OLEUI_CCHPATHMAX);
	else
		*(lpIO->szFile) = '\0';

	lpIO->hMetaPictFile = (HGLOBAL)NULL;

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


	//4.  Fill the Object Type listbox with entries from the reg DB.
	hList=GetDlgItem(hDlg, ID_IO_OBJECTTYPELIST);
	UFillClassList(hList, lpOIO->cClsidExclude, lpOIO->lpClsidExclude
		, (BOOL)(lpOIO->dwFlags & IOF_VERIFYSERVERSEXIST));

	//Set the tab width in the list to push all the tabs off the side.
	GetClientRect(hList, &rc);
	dw=GetDialogBaseUnits();
	rc.right =(8*rc.right)/LOWORD(dw);  //Convert pixels to 2x dlg units.
	SendMessage(hList, LB_SETTABSTOPS, 1, (LPARAM)(LPINT)&rc.right);


	//5. Initilize the file name display to cwd if we don't have any name.
	if ('\0' == *(lpIO->szFile))
	{
		 if ((pch=_getcwd(NULL, OLEUI_CCHPATHMAX)) != NULL) {

			 if (*(pch+lstrlen(pch)-1) != '\\')
				 lstrcat(pch, "\\");  // put slash on end of cwd
			 SetDlgItemText(hDlg, ID_IO_FILEDISPLAY, pch);
			 lpIO->fFileDirty = TRUE;  // cwd is not a valid filename
#ifndef __TURBOC__
			 free(pch);
#endif
		 }else{
			 OutputDebugString("*** Please install VC++ Patch #1 ***\n\r");
		 }
	}
	else
	{
		SetDlgItemText(hDlg, ID_IO_FILEDISPLAY, lpIO->szFile);

		if (FValidateInsertFile(hDlg, FALSE, &lpIO->nErrCode))
		  lpIO->fFileDirty = FALSE;
		else
		  lpIO->fFileDirty = TRUE;
	}


	//6.  Initialize the selected type radiobutton.
	if (lpIO->dwFlags & IOF_SELECTCREATENEW)
	{
		StandardShowDlgItem(hDlg, ID_IO_FILETEXT, SW_HIDE);
		StandardShowDlgItem(hDlg, ID_IO_FILETYPE, SW_HIDE);
		StandardShowDlgItem(hDlg, ID_IO_FILEDISPLAY, SW_HIDE);
		StandardShowDlgItem(hDlg, ID_IO_FILE, SW_HIDE);
		StandardShowDlgItem(hDlg, ID_IO_LINKFILE, SW_HIDE);

		CheckRadioButton(hDlg, ID_IO_CREATENEW, ID_IO_CREATEFROMFILE, ID_IO_CREATENEW);

		lpIO->fAsIconNew=(0L!=(lpIO->dwFlags & IOF_CHECKDISPLAYASICON));
		SetFocus(hList);
	}
	else
	{
		/*
		 * Use pszType as the initial File.  If there's no initial
		 * file then we have to remove any check from Display As
		 * Icon.  We also check Link if so indicated for this option.
		 */
		StandardShowDlgItem(hDlg, ID_IO_OBJECTTYPELIST, SW_HIDE);
		StandardShowDlgItem(hDlg, ID_IO_OBJECTTYPETEXT, SW_HIDE);

		// Don't preselect display as icon if the filename isn't valid
		if (TRUE == lpIO->fFileDirty)
			lpIO->dwFlags &= ~(IOF_CHECKDISPLAYASICON);

		if (IOF_DISABLELINK & lpIO->dwFlags)
			StandardShowDlgItem(hDlg, ID_IO_LINKFILE, SW_HIDE);
		else
		{
			CheckDlgButton(hDlg, ID_IO_LINKFILE
				, (BOOL)(0L!=(lpIO->dwFlags & IOF_CHECKLINK)));
		}

		CheckRadioButton(hDlg, ID_IO_CREATENEW, ID_IO_CREATEFROMFILE, ID_IO_CREATEFROMFILE);

		lpIO->fAsIconFile=(0L!=(lpIO->dwFlags & IOF_CHECKDISPLAYASICON));
		SetFocus(GetDlgItem(hDlg, ID_IO_FILEDISPLAY));
	}


	//7.  Initialize the Display as Icon state
	fCheck=(BOOL)(lpIO->dwFlags & IOF_CHECKDISPLAYASICON);
	u=fCheck ? SW_SHOWNORMAL : SW_HIDE;

	StandardShowDlgItem(hDlg, ID_IO_CHANGEICON, u);
	StandardShowDlgItem(hDlg, ID_IO_ICONDISPLAY, u);

	CheckDlgButton(hDlg, ID_IO_DISPLAYASICON, fCheck);


	//8.  Show or hide the help button
	if (!(lpIO->dwFlags & IOF_SHOWHELP))
		StandardShowDlgItem(hDlg, ID_OLEUIHELP, SW_HIDE);


	//9.  Initialize the result display
	UpdateClassIcon(hDlg, lpIO, GetDlgItem(hDlg, ID_IO_OBJECTTYPELIST));
	SetInsertObjectResults(hDlg, lpIO);

	//10.  Change the caption
	if (NULL!=lpOIO->lpszCaption)
		SetWindowText(hDlg, lpOIO->lpszCaption);

	//11. Hide all DisplayAsIcon related controls if it should be disabled
	if ( lpIO->dwFlags & IOF_DISABLEDISPLAYASICON ) {
		  StandardShowDlgItem(hDlg, ID_IO_DISPLAYASICON, SW_HIDE);
		  StandardShowDlgItem(hDlg, ID_IO_CHANGEICON, SW_HIDE);
		  StandardShowDlgItem(hDlg, ID_IO_ICONDISPLAY, SW_HIDE);
	}

	lpIO->nBrowseHelpID = RegisterWindowMessage(HELPMSGSTRING);

	//All Done:  call the hook with lCustData
	UStandardHook(lpIO, hDlg, WM_INITDIALOG, wParam, lpOIO->lCustData);

	/*
	 * We either set focus to the listbox or the edit control.  In either
	 * case we don't want Windows to do any SetFocus, so we return FALSE.
	 */
	return FALSE;
	}






/*
 * UFillClassList
 *
 * Purpose:
 *  Enumerates available OLE object classes from the registration
 *  database and fills a listbox with those names.
 *
 *  Note that this function removes any prior contents of the listbox.
 *
 * Parameters:
 *  hList           HWND to the listbox to fill.
 *  cIDEx           UINT number of CLSIDs to exclude in lpIDEx
 *  lpIDEx          LPCLSID to CLSIDs to leave out of the listbox.
 *  fVerify         BOOL indicating if we are to validate existence of
 *                  servers before putting them in the list.
 *
 * Return Value:
 *  UINT            Number of strings added to the listbox, -1 on failure.
 */

UINT UFillClassList(HWND hList, UINT cIDEx, LPCLSID lpIDEx, BOOL fVerify)
	{
	DWORD       dw;
	UINT        cStrings=0;
	UINT        i;
	UINT        cch;
	HKEY        hKey;
	LONG        lRet;
	HFILE       hFile;
	OFSTRUCT    of;
	BOOL        fExclude;
	LPMALLOC    pIMalloc;
	LPSTR       pszExec;
	LPSTR       pszClass;
	LPSTR       pszKey;
	LPSTR       pszID = NULL;
	CLSID       clsid;

	//Get some work buffers
	if (NOERROR!=CoGetMalloc(MEMCTX_TASK, &pIMalloc))
		return (UINT)-1;

	pszExec=(LPSTR)pIMalloc->lpVtbl->Alloc(pIMalloc, OLEUI_CCHKEYMAX*3);

	if (NULL==pszExec)
		{
		pIMalloc->lpVtbl->Release(pIMalloc);
		return (UINT)-1;
		}

	pszClass=pszExec+OLEUI_CCHKEYMAX;
	pszKey=pszClass+OLEUI_CCHKEYMAX;

	//Open up the root key.
	lRet=RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey);

	if ((LONG)ERROR_SUCCESS!=lRet)
		{
		pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)pszExec);
		pIMalloc->lpVtbl->Release(pIMalloc);
		return (UINT)-1;
		}

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

	cStrings=0;

	while (TRUE)
		{

		if (NULL!=pszID)
			{
			pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)pszID);
			pszID = NULL;
			}

		lRet=RegEnumKey(hKey, cStrings++, pszClass, OLEUI_CCHKEYMAX);

		if ((LONG)ERROR_SUCCESS!=lRet)
			break;

		//Cheat on lstrcat by using lstrcpy after this string, saving time
		cch=lstrlen(pszClass);

		// Check for \NotInsertable. if this is found then this overrides
		// all other keys; this class will NOT be added to the InsertObject
		// list.

		lstrcpy(pszClass+cch, "\\NotInsertable");

		dw=OLEUI_CCHKEYMAX;
		lRet=RegQueryValue(hKey, pszClass, pszKey, &dw);

		if ((LONG)ERROR_SUCCESS==lRet)
			continue;   // NotInsertable IS found--skip this class

		//Check for a \protocol\StdFileEditing\server entry.
		lstrcpy(pszClass+cch, "\\protocol\\StdFileEditing\\server");

		dw=OLEUI_CCHKEYMAX;
		lRet=RegQueryValue(hKey, pszClass, pszKey, &dw);

		if ((LONG)ERROR_SUCCESS==lRet)
			{
			/*
			* Check if the EXE actually exists.  By default we don't do this
			* to bring up the dialog faster.  If an application wants to be
			* stringent, they can provide IOF_VERIFYSERVERSEXIST.
			*/

			hFile = !HFILE_ERROR;

			if (fVerify)
				hFile=DoesFileExist(pszKey, &of);

			if (HFILE_ERROR!=hFile)
				{
				dw=OLEUI_CCHKEYMAX;
				*(pszClass+cch)=0;  // set back to rootkey
				// Get full user type name
				lRet=RegQueryValue(hKey, pszClass, pszKey, &dw);

				if ((LONG)ERROR_SUCCESS!=lRet)
					continue;   // error getting type name--skip this class
				}
			}
		else
			{
			/*
			 * No \protocol\StdFileEditing\server entry.  Look to see if
			 * there's an Insertable entry.  If there is, then use the
			 * Clsid to look at CLSID\clsid\LocalServer and \InprocServer
			 */

			lstrcpy(pszClass+cch, "\\Insertable");

			dw=OLEUI_CCHKEYMAX;
			lRet=RegQueryValue(hKey, pszClass, pszKey, &dw);

			if ((LONG)ERROR_SUCCESS!=lRet)
				continue;   // Insertable NOT found--skip this class

			//Get memory for pszID
			pszID=pIMalloc->lpVtbl->Alloc(pIMalloc, OLEUI_CCHKEYMAX);

			if (NULL==pszID)
				continue;

			*(pszClass+cch)=0;  // set back to rootkey
			lstrcat(pszClass+cch, "\\CLSID");

			dw=OLEUI_CCHKEYMAX;
			lRet=RegQueryValue(hKey, pszClass, pszID, &dw);

			if ((LONG)ERROR_SUCCESS!=lRet)
				continue;   // CLSID subkey not found

			lstrcpy(pszExec, "CLSID\\");
			lstrcat(pszExec, pszID);

			//CLSID\ is 6, dw contains pszID length.
			cch=6+(UINT)dw;

			lstrcpy(pszExec+cch, "\\LocalServer");
			dw=OLEUI_CCHKEYMAX;
			lRet=RegQueryValue(hKey, pszExec, pszKey, &dw);

			if ((LONG)ERROR_SUCCESS!=lRet)
				{
				//Try InprocServer
				lstrcpy(pszExec+cch, "\\InProcServer");
				dw=OLEUI_CCHKEYMAX;
				lRet=RegQueryValue(hKey, pszExec, pszKey, &dw);

				if ((LONG)ERROR_SUCCESS!=lRet)
					continue;
				}

			if (fVerify)
				{
				if (HFILE_ERROR==DoesFileExist(pszKey, &of))
					continue;
				}

			dw=OLEUI_CCHKEYMAX;
			lRet=RegQueryValue(hKey, pszExec, pszKey, &dw);
			*(pszExec+cch)=0;   //Remove \\*Server

			if ((LONG)ERROR_SUCCESS!=lRet)
				continue;
			}

		//Get CLSID to add to listbox.
		if (NULL==pszID)
			{
			CLSIDFromProgID(pszClass, &clsid);
			StringFromCLSID(&clsid, &pszID);
			}
		else
			CLSIDFromString(pszID, &clsid);

		if (NULL==pszID || IsEqualCLSID(&clsid, &CLSID_NULL))
			continue;

		//Check if this CLSID is in the exclusion list.
		fExclude=FALSE;

		for (i=0; i < cIDEx; i++)
			{
			if (IsEqualCLSID(&clsid, (LPCLSID)(lpIDEx+i)))
				{
				fExclude=TRUE;
				break;
				}
			}

		if (fExclude)
			continue;

		//We go through all the conditions, add the string.
		lstrcat(pszKey, "\t");

		// only add to listbox if not a duplicate
		if (LB_ERR==SendMessage(hList,LB_FINDSTRING,0,(LPARAM)pszKey))
			{
			lstrcat(pszKey, pszID);
			SendMessage(hList, LB_ADDSTRING, 0, (LPARAM)pszKey);
			}
		}

	if (NULL!=pszID)
		{
		pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)pszID);
		pszID = NULL;
		}

	//Select the first item by default
	SendMessage(hList, LB_SETCURSEL, 0, 0L);
	RegCloseKey(hKey);

	pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)pszExec);
	pIMalloc->lpVtbl->Release(pIMalloc);

	return cStrings;
	}





/*
 * FToggleObjectSource
 *
 * Purpose:
 *  Handles enabling, disabling, showing, and flag manipulation when the
 *  user changes between Create New, Insert File, and Link File in the
 *  Insert Object dialog.
 *
 * Parameters:
 *  hDlg            HWND of the dialog
 *  lpIO            LPINSERTOBJECT pointing to the dialog structure
 *  dwOption        DWORD flag indicating the option just selected:
 *                  IOF_SELECTCREATENEW or IOF_SELECTCREATEFROMFILE
 *
 * Return Value:
 *  BOOL            TRUE if the option was already selected, FALSE otherwise.
 */

BOOL FToggleObjectSource(HWND hDlg, LPINSERTOBJECT lpIO, DWORD dwOption)
	{
	BOOL        fTemp;
	UINT        uTemp;
	DWORD       dwTemp;
	int         i;

	//Skip all of this if we're already selected.
	if (lpIO->dwFlags & dwOption)
		return TRUE;


	// if we're switching from "from file" to "create new" and we've got
	// an icon for "from file", then we need to save it so that we can
	// show it if the user reselects "from file".

	if ( (IOF_SELECTCREATENEW == dwOption) &&
		 (lpIO->dwFlags & IOF_CHECKDISPLAYASICON) )
	  lpIO->hMetaPictFile = (HGLOBAL)SendDlgItemMessage(hDlg, ID_IO_ICONDISPLAY, IBXM_IMAGEGET, 0, 0L);

	/*
	 * 1.  Change the Display As Icon checked state to reflect the
	 *     selection for this option, stored in the fAsIcon* flags.
	 */
	fTemp=(IOF_SELECTCREATENEW==dwOption) ? lpIO->fAsIconNew : lpIO->fAsIconFile;

	if (fTemp)
		lpIO->dwFlags |=IOF_CHECKDISPLAYASICON;
	else
		lpIO->dwFlags &=~IOF_CHECKDISPLAYASICON;

	CheckDlgButton(hDlg, ID_IO_DISPLAYASICON
		 , (BOOL)(0L!=(lpIO->dwFlags & IOF_CHECKDISPLAYASICON)));

	EnableWindow(GetDlgItem(hDlg, ID_IO_CHANGEICON), fTemp);

	/*
	 * 2.  Display Icon:  Enabled on Create New or on Create from File if
	 *     there is a selected file.
	 */
	fTemp=(IOF_SELECTCREATENEW==dwOption) ? TRUE : lpIO->fFileSelected;
	EnableWindow(GetDlgItem(hDlg, ID_IO_DISPLAYASICON), fTemp);

	//OK and Link follow the same enabling as Display As Icon.
	EnableWindow(GetDlgItem(hDlg, IDOK), fTemp);
	EnableWindow(GetDlgItem(hDlg, ID_IO_LINKFILE), fTemp);

	//3.  Enable Browse... when Create from File is selected.
	fTemp=(IOF_SELECTCREATENEW==dwOption);
	EnableWindow(GetDlgItem(hDlg, ID_IO_FILE),        !fTemp);
	EnableWindow(GetDlgItem(hDlg, ID_IO_FILEDISPLAY), !fTemp);

	/*
	 * 4.  Switch between Object Type listbox on Create New and
	 *     file buttons on others.
	 */
	uTemp=(fTemp) ? SW_SHOWNORMAL : SW_HIDE;
	StandardShowDlgItem(hDlg, ID_IO_OBJECTTYPELIST, uTemp);
	StandardShowDlgItem(hDlg, ID_IO_OBJECTTYPETEXT, uTemp);

	uTemp=(fTemp) ? SW_HIDE : SW_SHOWNORMAL;
	StandardShowDlgItem(hDlg, ID_IO_FILETEXT, uTemp);
	StandardShowDlgItem(hDlg, ID_IO_FILETYPE, uTemp);
	StandardShowDlgItem(hDlg, ID_IO_FILEDISPLAY, uTemp);
	StandardShowDlgItem(hDlg, ID_IO_FILE, uTemp);

	//Link is always hidden if IOF_DISABLELINK is set.
	if (IOF_DISABLELINK & lpIO->dwFlags)
		uTemp=SW_HIDE;

	StandardShowDlgItem(hDlg, ID_IO_LINKFILE, uTemp);  //last use of uTemp


	//5.  Clear out existing any flags selection and set the new one
	dwTemp=IOF_SELECTCREATENEW | IOF_SELECTCREATEFROMFILE;
	lpIO->dwFlags=(lpIO->dwFlags & ~dwTemp) | dwOption;


	/*
	 * Show or hide controls as appropriate.  Do the icon
	 * display last because it will take some time to repaint.
	 * If we do it first then the dialog looks too sluggish.
	 */

	i=(lpIO->dwFlags & IOF_CHECKDISPLAYASICON) ? SW_SHOWNORMAL : SW_HIDE;
	StandardShowDlgItem(hDlg, ID_IO_CHANGEICON, i);
	StandardShowDlgItem(hDlg, ID_IO_ICONDISPLAY, i);


	//6.Change result display
	SetInsertObjectResults(hDlg, lpIO);

	/*
	 * 7.  For Create New, twiddle the listbox to think we selected it
	 *     so it updates the icon from the object type. set the focus
	 *     to the list box.
	 *
	 *     For Insert or Link file, set the focus to the filename button
	 *     and update the icon if necessary.
	 */
	if (fTemp) {
		UpdateClassIcon(hDlg, lpIO, GetDlgItem(hDlg, ID_IO_OBJECTTYPELIST));
		SetFocus(GetDlgItem(hDlg, ID_IO_OBJECTTYPELIST));
	}
	else
	{
		if (lpIO->fAsIconFile && (NULL != lpIO->hMetaPictFile) )
		{
		   SendDlgItemMessage(hDlg, ID_IO_ICONDISPLAY, IBXM_IMAGESET, (WPARAM)lpIO->hMetaPictFile, 0L);
		   lpIO->hMetaPictFile = 0;
		}
		else
		   UpdateClassIcon(hDlg, lpIO, NULL);

		SetFocus(GetDlgItem(hDlg, ID_IO_FILE));
	}

	return FALSE;
	}


/*
 * UpdateClassType
 *
 * Purpose:
 *  Updates static text control to reflect current file type.  Assumes
 *  a valid filename.
 *
 * Parameters
 *  hDlg            HWND of the dialog box.
 *  lpIO            LPINSERTOBJECT pointing to the dialog structure
 *  fSet            TRUE to set the text, FALSE to explicitly clear it
 *
 * Return Value:
 *  None
 */

void UpdateClassType(HWND hDlg, LPINSERTOBJECT lpIO, BOOL fSet)
{

   CLSID clsid;
   char  szFileName[OLEUI_CCHPATHMAX];
   char  szFileType[OLEUI_CCHLABELMAX];

   *szFileType = '\0';

   if (fSet)
   {
	  GetDlgItemText(hDlg, ID_IO_FILEDISPLAY, (LPSTR)szFileName, OLEUI_CCHPATHMAX);

	  if (NOERROR == GetClassFile((LPSTR)szFileName, &clsid) )
		OleStdGetUserTypeOfClass(&clsid, szFileType, OLEUI_CCHLABELMAX, NULL);

   }

   SetDlgItemText(hDlg, ID_IO_FILETYPE, (LPSTR)szFileType);

   return;
}


/*
 * UpdateClassIcon
 *
 * Purpose:
 *  Handles LBN_SELCHANGE for the Object Type listbox.  On a selection
 *  change, we extract an icon from the server handling the currently
 *  selected object type using the utility function HIconFromClass.
 *  Note that we depend on the behavior of FillClassList to stuff the
 *  object class after a tab in the listbox string that we hide from
 *  view (see WM_INITDIALOG).
 *
 * Parameters
 *  hDlg            HWND of the dialog box.
 *  lpIO            LPINSERTOBJECT pointing to the dialog structure
 *  hList           HWND of the Object Type listbox.
 *
 * Return Value:
 *  None
 */

void UpdateClassIcon(HWND hDlg, LPINSERTOBJECT lpIO, HWND hList)
	{
	UINT        iSel;
	DWORD       cb;
	LPMALLOC    pIMalloc;
	LPSTR       pszName, pszCLSID, pszTemp;
	HGLOBAL     hMetaPict;

	LRESULT     dwRet;


	//If Display as Icon is not selected, exit
	if (!(lpIO->dwFlags & IOF_CHECKDISPLAYASICON))
		return;

	/*
	 * When we change object type selection, get the new icon for that
	 * type into our structure and update it in the display.  We use the
	 * class in the listbox when Create New is selected or the association
	 * with the extension in Create From File.
	 */

	if (lpIO->dwFlags & IOF_SELECTCREATENEW)
		{
		iSel=(UINT)SendMessage(hList, LB_GETCURSEL, 0, 0L);

		if (LB_ERR==(int)iSel)
			return;

		//Check to see if we've already got the hMetaPict for this item
		dwRet=SendMessage(hList, LB_GETITEMDATA, (WPARAM)iSel, 0L);

		hMetaPict=(HGLOBAL)(UINT)dwRet;

		if (hMetaPict)
			{
			//Yep, we've already got it, so just display it and return.
			SendDlgItemMessage(hDlg, ID_IO_ICONDISPLAY, IBXM_IMAGESET, (WPARAM)hMetaPict, 0L);
			return;
			}

		iSel=(UINT)SendMessage(hList, LB_GETCURSEL, 0, 0L);

		if (LB_ERR==(int)iSel)
			return;

		//Allocate a string to hold the entire listbox string
		cb=SendMessage(hList, LB_GETTEXTLEN, iSel, 0L);
		}
	else
		cb=OLEUI_CCHPATHMAX;

	if (NOERROR!=CoGetMalloc(MEMCTX_TASK, &pIMalloc))
		return;

	pszName=(LPSTR)pIMalloc->lpVtbl->Alloc(pIMalloc, cb+1);

	if (NULL==pszName)
		{
		pIMalloc->lpVtbl->Release(pIMalloc);
		return;
		}

	*pszName=0;

	//Get the clsid we want.
	if (lpIO->dwFlags & IOF_SELECTCREATENEW)
	{
		//Grab the classname string from the list
		SendMessage(hList, LB_GETTEXT, iSel, (LONG)pszName);

		//Set pointer to CLSID (string)
		pszCLSID=PointerToNthField(pszName, 2, '\t');

		//Null terminate pszName string
		pszTemp=AnsiPrev(pszName, pszCLSID);

		*pszTemp='\0';
		CLSIDFromString(pszCLSID, &lpIO->clsid);

		hMetaPict = GetIconOfClass(ghInst, &lpIO->clsid, NULL, TRUE);
	}

	else
	{
		CLSID clsid;

		//Get the class from the filename
		GetDlgItemText(hDlg, ID_IO_FILEDISPLAY, pszName, OLEUI_CCHPATHMAX);

		if (lpIO->dwFlags & IOF_CHECKLINK ||
			NOERROR != GetClassFile((LPSTR)pszName, &clsid) ) {

			// get icon using filename as label (if creating a link)
			hMetaPict = GetIconOfFile(ghInst,
					pszName, lpIO->dwFlags & IOF_CHECKLINK ? TRUE : FALSE);
		} else {
			// not creating a link and we can get CLSID from the filename,
			// therefore generate an icon with short type name as label
			hMetaPict = GetIconOfClass(ghInst, &clsid, NULL, TRUE);
		}
	}


	//Replace the current display with this new one.
	SendDlgItemMessage(hDlg, ID_IO_ICONDISPLAY, IBXM_IMAGESET, (WPARAM)hMetaPict, 0L);

	//Enable or disable "Change Icon" button depending on whether
	//we've got a valid filename or not.
	EnableWindow(GetDlgItem(hDlg, ID_IO_CHANGEICON), hMetaPict ? TRUE : FALSE);

	//Save the hMetaPict so that we won't have to re-create
	if (lpIO->dwFlags & IOF_SELECTCREATENEW)
		SendMessage(hList, LB_SETITEMDATA, (WPARAM)iSel, MAKELPARAM(hMetaPict,0));

	pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)pszName);
	pIMalloc->lpVtbl->Release(pIMalloc);
	return;
	}




/*
 * SetInsertObjectResults
 *
 * Purpose:
 *  Centralizes setting of the Result and icon displays in the Insert Object
 *  dialog.  Handles loading the appropriate string from the module's
 *  resources and setting the text, displaying the proper result picture,
 *  and showing the proper icon.
 *
 * Parameters:
 *  hDlg            HWND of the dialog box so we can access controls.
 *  lpIO            LPINSERTOBJECT in which we assume that the
 *                  current radiobutton and Display as Icon selections
 *                  are set.  We use the state of those variables to
 *                  determine which string we use.
 *
 * Return Value:
 *  None
 */

void SetInsertObjectResults(HWND hDlg, LPINSERTOBJECT lpIO)
	{
	LPSTR       pszT, psz1, psz2, psz3, psz4, pszTemp;
	UINT        i, iString1, iString2, iImage, cch;
	LPMALLOC    pIMalloc;
	BOOL        fAsIcon;

	/*
	 * We need scratch memory for loading the stringtable string, loading
	 * the object type from the listbox, and constructing the final string.
	 * We therefore allocate three buffers as large as the maximum message
	 * length (512) plus the object type, guaranteeing that we have enough
	 * in all cases.
	 */
	i=(UINT)SendDlgItemMessage(hDlg, ID_IO_OBJECTTYPELIST, LB_GETCURSEL, 0, 0L);
	cch=512+(UINT)SendDlgItemMessage(hDlg, ID_IO_OBJECTTYPELIST, LB_GETTEXTLEN, i, 0L);

	if (NOERROR!=CoGetMalloc(MEMCTX_TASK, &pIMalloc))
		return;

	pszTemp=(LPSTR)pIMalloc->lpVtbl->Alloc(pIMalloc, (DWORD)(4*cch));

	if (NULL==pszTemp)
		{
		pIMalloc->lpVtbl->Release(pIMalloc);
		return;
		}

	psz1=pszTemp;
	psz2=psz1+cch;
	psz3=psz2+cch;
	psz4=psz3+cch;

	fAsIcon=(0L!=(lpIO->dwFlags & IOF_CHECKDISPLAYASICON));

	if (lpIO->dwFlags & IOF_SELECTCREATENEW)
		{
		iString1 = (UINT)(fAsIcon ? IDS_IORESULTNEWICON : IDS_IORESULTNEW);
		iString2 = (UINT)0;
		iImage   = (UINT)(fAsIcon ? RESULTIMAGE_EMBEDICON : RESULTIMAGE_EMBED);
		}

	if (lpIO->dwFlags & IOF_SELECTCREATEFROMFILE)
		{
		//Pay attention to Link checkbox
		if (lpIO->dwFlags & IOF_CHECKLINK)
			{
			iString1 = (UINT)(fAsIcon ? IDS_IORESULTLINKFILEICON1 : IDS_IORESULTLINKFILE1);
			iString2 = (UINT)(fAsIcon ? IDS_IORESULTLINKFILEICON2 : IDS_IORESULTLINKFILE2);
			iImage = (UINT)(fAsIcon ? RESULTIMAGE_LINKICON : RESULTIMAGE_LINK);
			}
		else
			{
			iString1 = (UINT)IDS_IORESULTFROMFILE1;
			iString2 = (UINT)(fAsIcon ? IDS_IORESULTFROMFILEICON2 : IDS_IORESULTFROMFILE2);
			iImage = (UINT)(fAsIcon ? RESULTIMAGE_EMBEDICON : RESULTIMAGE_EMBED);
			}
		}

	//Default is an empty string.
	*psz1=0;

	if (0!=LoadString(ghInst, iString1, psz1, cch))
	{

		   // Load second string, if necessary
		if (   (0 != iString2)
			&& (0 != LoadString(ghInst, iString2, psz4, cch)) )
		{
		  lstrcat(psz1, psz4);  // concatenate strings together.
		}



		//In Create New, do the extra step of inserting the object type string
		if (lpIO->dwFlags & IOF_SELECTCREATENEW)
		{
			SendDlgItemMessage(hDlg, ID_IO_OBJECTTYPELIST, LB_GETTEXT
							  , i, (LONG)psz2);

			//Null terminate at any tab (before the classname)
			pszT=psz2;
			while ('\t'!=*pszT && 0!=*pszT)
				pszT++;
			*pszT=0;

			//Build the string and point psz1 to it.
			wsprintf(psz3, psz1, psz2);
			psz1=psz3;
		}
	}

	//If LoadString failed, we simply clear out the results (*psz1=0 above)
	SetDlgItemText(hDlg, ID_IO_RESULTTEXT, psz1);

	//Go change the image and Presto!  There you have it.
	SendDlgItemMessage(hDlg, ID_IO_RESULTIMAGE, RIM_IMAGESET, iImage, 0L);

	pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)pszTemp);
	pIMalloc->lpVtbl->Release(pIMalloc);
	return;
	}



/*
 * FValidateInsertFile
 *
 * Purpose:
 *  Given a possibly partial pathname from the file edit control,
 *  attempt to locate the file and if found, store the full path
 *  in the edit control ID_IO_FILEDISPLAY.
 *
 * Parameters:
 *  hDlg            HWND of the dialog box.
 *  fTellUser       BOOL TRUE if function should tell user, FALSE if
 *                   function should validate silently.
 *
 * Return Value:
 *  BOOL            TRUE if the file is acceptable, FALSE otherwise.
 */

BOOL FValidateInsertFile(HWND hDlg, BOOL fTellUser, UINT FAR* lpnErrCode)
	{
	OFSTRUCT    of;
	HFILE       hFile;
	char        szFile[OLEUI_CCHPATHMAX];

	*lpnErrCode = 0;
	/*
	 * To validate we attempt OpenFile on the string.  If OpenFile
	 * fails then we display an error.  If not, OpenFile will store
	 * the complete path to that file in the OFSTRUCT which we can
	 * then stuff in the edit control.
	 */

	if (0==GetDlgItemText(hDlg, ID_IO_FILEDISPLAY, szFile, sizeof(szFile)))
		return FALSE;   // #4569 : return FALSE when there is no text in ctl

	hFile=DoesFileExist(szFile, &of);

	// if file is currently open (ie. sharing violation) OleCreateFromFile
	// and OleCreateLinkToFile can still succeed; do not consider it an
	// error.
	if (HFILE_ERROR==hFile && 0x0020/*sharing violation*/!=of.nErrCode)
	{
	   *lpnErrCode = of.nErrCode;
	   if (fTellUser)
		   OpenFileError(hDlg, of.nErrCode, szFile);
	   return FALSE;
	}

	//OFSTRUCT contains an OEM name, not ANSI as we need for the edit box.
	OemToAnsi(of.szPathName, of.szPathName);
	SetDlgItemText(hDlg, ID_IO_FILEDISPLAY, of.szPathName);
	return TRUE;
	}


/*
 * InsertObjectCleanup
 *
 * Purpose:
 *  Clears cached icon metafiles from those stored in the listbox.
 *
 * Parameters:
 *  hDlg            HWND of the dialog.
 *
 * Return Value:
 *  None
 */

void InsertObjectCleanup(HWND hDlg)
	{
	HWND      hList;
	UINT      iItems;
	HGLOBAL   hMetaPict;
	LRESULT   dwRet;
	UINT      i;

	hList=GetDlgItem(hDlg, ID_IO_OBJECTTYPELIST);
	iItems=(UINT)SendMessage(hList, LB_GETCOUNT, 0, 0L);

	for (i=0; i < iItems; i++)
		{
		dwRet=SendMessage(hList, LB_GETITEMDATA, (WPARAM)i, 0L);

		//Cast of LRESULT to UINT to HGLOBAL portable to Win32.
		hMetaPict=(HGLOBAL)(UINT)dwRet;

		if (hMetaPict)
			OleUIMetafilePictIconFree(hMetaPict);
		}

	return;
	}
