/*
 * CONVERT.C
 *
 * Implements the OleUIConvert function which invokes the complete
 * Convert dialog.
 *
 * Copyright (c)1992 Microsoft Corporation, All Right Reserved
 */

#define STRICT  1
#include "ole2ui.h"
#include <stdlib.h>
#include "common.h"
#include "utility.h"
#include "geticon.h"
#include "regdb.h"
#include "convert.h"
#include "olestd.h"

#define CF_CLIPBOARDMIN   0xc000
#define CF_CLIPBOARDMAX   0xffff

#define AUXUSERTYPE_SHORTNAME  USERCLASSTYPE_SHORT  // short name

static char szOLE2DLL[] = "ole2.dll";   // name of OLE 2.0 library
static char szVanillaDocIcon[] = "DefIcon";

/*
 * OleUIConvert
 *
 * Purpose:
 *  Invokes the standard OLE Change Type dialog box allowing the user
 *  to change the type of the single specified object, or change the
 *  type of all OLE objects of a specified type.
 *
 * Parameters:
 *  lpCV            LPOLEUICONVERT pointing to the in-out structure
 *                  for this dialog.
 *
 * Return Value:
 *  UINT            One of the following codes, indicating success or error:
 *                      OLEUI_SUCCESS           Success
 *                      OLEUI_ERR_STRUCTSIZE    The dwStructSize value is wrong
 */

STDAPI_(UINT) OleUIConvert(LPOLEUICONVERT lpCV)
   {
   UINT        uRet;
   HGLOBAL     hMemDlg=NULL;

   uRet=UStandardValidation((LPOLEUISTANDARD)lpCV, sizeof(OLEUICONVERT)
                      , &hMemDlg);

   if (OLEUI_SUCCESS!=uRet)
      return uRet;

   // Validate structure members passed in.
#if defined( OBSOLETE )
   if (!IsValidClassID(lpCV->clsid))
      uRet = OLEUI_CTERR_CLASSIDINVALID;
#endif

   if ( (lpCV->dwFlags & CF_SETCONVERTDEFAULT)
       && (!IsValidClassID(lpCV->clsidConvertDefault)) )
      uRet = OLEUI_CTERR_CLASSIDINVALID;

   if ( (lpCV->dwFlags & CF_SETACTIVATEDEFAULT)
       && (!IsValidClassID(lpCV->clsidActivateDefault)) )
      uRet = OLEUI_CTERR_CLASSIDINVALID;

   if ( (lpCV->dvAspect != DVASPECT_ICON)
       && (lpCV->dvAspect != DVASPECT_CONTENT) )
      uRet = OLEUI_CTERR_DVASPECTINVALID;

   if ( (lpCV->wFormat >= CF_CLIPBOARDMIN)
       && (lpCV->wFormat <= CF_CLIPBOARDMAX) )
   {
       char szTemp[8];

       if (0 == GetClipboardFormatName(lpCV->wFormat, szTemp, 8))
         uRet = OLEUI_CTERR_CBFORMATINVALID;
   }


   if ( (NULL != lpCV->lpszUserType)
      && (IsBadReadPtr(lpCV->lpszUserType, 1)) )
      uRet = OLEUI_CTERR_STRINGINVALID;

   if ( (NULL != lpCV->lpszDefLabel)
      && (IsBadReadPtr(lpCV->lpszDefLabel, 1)) )
      uRet = OLEUI_CTERR_STRINGINVALID;

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


   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(ConvertDialogProc, (LPOLEUISTANDARD)lpCV,
                      hMemDlg, MAKEINTRESOURCE(IDD_CONVERT));

   return uRet;
   }





/*
 * ConvertDialogProc
 *
 * Purpose:
 *  Implements the OLE Convert dialog as invoked through the
 *  OleUIConvert function.
 *
 * Parameters:
 *  Standard
 *
 * Return Value:
 *  Standard
 *
 */

BOOL CALLBACK EXPORT ConvertDialogProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
   {
   LPCONVERT           lpCV;
   UINT                uRet = 0;
   OLEUICHANGEICON     ci;

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

   //This will fail under WM_INITDIALOG, where we allocate it.
   lpCV=(LPCONVERT)LpvStandardEntry(hDlg, iMsg, wParam, lParam, (UINT FAR *)&uRet);

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

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

   // Process help message from Change Icon
   if (iMsg == uMsgHelp)
   {

     PostMessage(lpCV->lpOCV->hWndOwner, uMsgHelp, wParam, lParam);
     return FALSE;

   }

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

      case WM_COMMAND:
         switch (wID)
         {
            case IDCV_ACTIVATELIST:
            case IDCV_CONVERTLIST:
               switch (wCode)
               {
                  case LBN_SELCHANGE:

                     // Change "Results" window to reflect current selection
                     SetConvertResults(hDlg, lpCV);

                     // Update the icon we display, if we are indeed
                     // displaying an icon.
                     if ( (lpCV->dwFlags & CF_SELECTCONVERTTO)
                         && (lpCV->dvAspect == DVASPECT_ICON)
                         && (!lpCV->fCustomIcon) )
                        UpdateCVClassIcon(hDlg, lpCV, hWndMsg);

                     break;

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

            case IDCV_CONVERTTO:
            case IDCV_ACTIVATEAS:
            {
               HWND    hList, hListInvisible;
               LRESULT lRetVal;
               BOOL    fState;

               hList = lpCV->hListVisible;
               hListInvisible = lpCV->hListInvisible;


               if (IDCV_CONVERTTO == wParam)
               {

                  // User just click on the button again - it was
                  // already selected.
                  if (lpCV->dwFlags & CF_SELECTCONVERTTO)
                    break;


                  // Turn painting updates off.
                  SendMessage(hDlg, WM_SETREDRAW, FALSE, 0L);


                  // If we're working with a linked object, don't
                  // add the activate list - just the object's
                  // class should appear in the listbox.

                  SwapWindows(hDlg,
                           hList,
                           hListInvisible);

                  lpCV->hListVisible = hListInvisible;
                  lpCV->hListInvisible = hList;

                  EnableWindow(lpCV->hListInvisible, FALSE);
                  EnableWindow(lpCV->hListVisible, TRUE);

                  // Update our flags.
                  lpCV->dwFlags &= ~CF_SELECTACTIVATEAS;
                  lpCV->dwFlags |= CF_SELECTCONVERTTO;

               }
               else
               {
                  if (lpCV->dwFlags & CF_SELECTACTIVATEAS)
                    break;

                  // Turn painting updates off.
                  SendMessage(hDlg, WM_SETREDRAW, FALSE, 0L);

                  SwapWindows(hDlg,
                           hList,
                           hListInvisible);

                  lpCV->hListVisible = hListInvisible;
                  lpCV->hListInvisible = hList;

                  EnableWindow(lpCV->hListInvisible, FALSE);
                  EnableWindow(lpCV->hListVisible, TRUE);


                  // Update our flags.
                  lpCV->dwFlags |= CF_SELECTACTIVATEAS;
                  lpCV->dwFlags &= ~CF_SELECTCONVERTTO;
               }


               if (lpCV->dwFlags & CF_SELECTCONVERTTO)
                  lRetVal = SendMessage(lpCV->hListVisible, LB_SELECTSTRING, (WPARAM)-1, (LPARAM)lpCV->lpszConvertDefault);

               else
                  lRetVal = SendMessage(lpCV->hListVisible, LB_SELECTSTRING, (WPARAM)-1, (LPARAM)lpCV->lpszActivateDefault);

               if (LB_ERR == lRetVal)
               {
                  char szCurrentObject[40];

                  GetDlgItemText(hDlg, IDCV_OBJECTTYPE, szCurrentObject, 40);
                  SendMessage(lpCV->hListVisible, LB_SELECTSTRING, (WPARAM)-1, (LPARAM)szCurrentObject);
               }

               // Turn updates back on.
               SendMessage(hDlg, WM_SETREDRAW, TRUE, 0L);

               InvalidateRect(lpCV->hListVisible, NULL, TRUE);
               UpdateWindow(lpCV->hListVisible);

               if ((lpCV->dvAspect & DVASPECT_ICON) && (lpCV->dwFlags & CF_SELECTCONVERTTO))
                 UpdateCVClassIcon(hDlg, lpCV, lpCV->hListVisible);

               // Hide the icon stuff when Activate is selected...show
               // it again when Convert is selected.

               fState = ((lpCV->dwFlags & CF_SELECTACTIVATEAS) ||
                       (lpCV->dwFlags & CF_DISABLEDISPLAYASICON)) ?
                       SW_HIDE : SW_SHOW;

               StandardShowDlgItem(hDlg, IDCV_DISPLAYASICON, fState);

               // Only display the icon if convert is selected AND
               // display as icon is checked.
               if ((SW_SHOW==fState) && (DVASPECT_ICON!=lpCV->dvAspect))
                  fState = SW_HIDE;

               StandardShowDlgItem(hDlg, IDCV_CHANGEICON, fState);
               StandardShowDlgItem(hDlg, IDCV_ICON, fState);
               StandardShowDlgItem(hDlg, IDCV_ICONLABEL1, fState);
               StandardShowDlgItem(hDlg, IDCV_ICONLABEL2, fState);

              SetConvertResults(hDlg, lpCV);

            }
            break;


            case IDOK:
            {

               WORD  iCurSel;
               OLECHAR lpszCLSID[256];
               LPSTR lpszAnsiCLSID;
               char  szBuffer[256];

               // Set OUT parameters

               //
               // Set output flags to current ones
               //
               lpCV->lpOCV->dwFlags = lpCV->dwFlags;


               // Update the dvAspect and fObjectsIconChanged members
               // as appropriate.
               //
               if (lpCV->dwFlags & CF_SELECTACTIVATEAS)
               {
                 // DON'T update aspect if activate as was selected.
                 lpCV->lpOCV->fObjectsIconChanged = FALSE;
               }
               else
                 lpCV->lpOCV->dvAspect = lpCV->dvAspect;


               //
               // Get the new clsid
               //
               iCurSel = (WORD)SendMessage(lpCV->hListVisible, LB_GETCURSEL, 0, 0);
               SendMessage(lpCV->hListVisible, LB_GETTEXT, iCurSel, (LPARAM)szBuffer);

               lpszAnsiCLSID = PointerToNthField(szBuffer, 2, '\t');

               A2W (lpszAnsiCLSID, lpszCLSID, 256);
               CLSIDFromString(lpszCLSID, (LPCLSID)(&(lpCV->lpOCV->clsidNew)));



               // Free the hMetaPict we got in.
               OleUIMetafilePictIconFree(lpCV->lpOCV->hMetaPict);

               //
               // Get the hMetaPict (if display as icon is checked)
               //
               if (DVASPECT_ICON == lpCV->dvAspect)
               {
                  HICON hIcon;
                  char  szLabel[OLEUI_CCHLABELMAX];
                  OLECHAR szUniLabel[OLEUI_CCHLABELMAX];
                  int   Index;


                  // Create the hMetaPict here from icon, label,
                  // index, and path

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

                  // the combined length of the 2 label lines won't ever be more than
                  // OLEUI_CCHLABELMAX.
                  Index = (int)SendDlgItemMessage(hDlg, IDCV_ICONLABEL1, WM_GETTEXT, OLEUI_CCHLABELMAX, (LPARAM)szLabel);

                  if (Index < OLEUI_CCHLABELMAX)
                  {
                    LPSTR lpszSecondLine = szLabel + Index;


                    SendDlgItemMessage(hDlg, IDCV_ICONLABEL2, WM_GETTEXT,
                                  OLEUI_CCHLABELMAX-Index,
                                  (LPARAM)lpszSecondLine);
                  }
                  A2W (szLabel, szUniLabel, OLEUI_CCHLABELMAX);
                  lpCV->lpOCV->hMetaPict =
                      OleUIMetafilePictFromIconAndLabel(hIcon,
                                                szUniLabel,
                                                lpCV->lpszIconSource,
                                                lpCV->IconIndex);

               }
               else
                  lpCV->lpOCV->hMetaPict = (HGLOBAL)NULL;


               //
               // End the dialog
               //
               SendMessage(hDlg, uMsgEndDialog, OLEUI_OK, 0L);
            }
            break;

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


            case ID_OLEUIHELP:
               PostMessage(lpCV->lpOCV->hWndOwner,
                        uMsgHelp, (WPARAM)hDlg, MAKELPARAM(IDD_CONVERT, 0));
               break;

            case IDCV_DISPLAYASICON:
            {

               int i;
               BOOL fCheck;

               fCheck=IsDlgButtonChecked(hDlg, wID);

               if (fCheck)
                  lpCV->dvAspect = DVASPECT_ICON;
               else
                  lpCV->dvAspect = DVASPECT_CONTENT;

               if (fCheck && (!lpCV->fCustomIcon))
                  UpdateCVClassIcon(hDlg, lpCV, lpCV->hListVisible);

               //Show or hide the icon depending on the check state.

               i=(fCheck) ? SW_SHOWNORMAL : SW_HIDE;

               StandardShowDlgItem(hDlg, IDCV_CHANGEICON, i);
               StandardShowDlgItem(hDlg, IDCV_ICON, i);
               StandardShowDlgItem(hDlg, IDCV_ICONLABEL1, i);
               StandardShowDlgItem(hDlg, IDCV_ICONLABEL2, i);

               SetConvertResults(hDlg, lpCV);

            }
            break;

            case IDCV_CHANGEICON:
            {
               LPMALLOC pIMalloc;
               LPSTR    pszString, pszCLSID;
               OLECHAR  pszUniCLSID[256];
               int      iSel;
               HICON    hIcon;
               char     szLabel[OLEUI_CCHLABELMAX];
               OLECHAR     szUniLabel[OLEUI_CCHLABELMAX];
               int      Index;


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


               // Create the hMetaPict here from icon, label,
               // index, and path

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

               // the combined length of the 2 label lines won't ever be more than
               // OLEUI_CCHLABELMAX.

               Index = (int)SendDlgItemMessage(hDlg, IDCV_ICONLABEL1, WM_GETTEXT, OLEUI_CCHLABELMAX, (LPARAM)szLabel);

               if (Index < OLEUI_CCHLABELMAX)
               {
                  LPSTR    lpszSecondLine;

                  lpszSecondLine = szLabel + Index;

                  SendDlgItemMessage(hDlg, IDCV_ICONLABEL2, WM_GETTEXT,
                                OLEUI_CCHLABELMAX-Index,
                                (LPARAM)lpszSecondLine);
               }
               A2W (szLabel, szUniLabel, OLEUI_CCHLABELMAX);
               ci.hMetaPict =
                    OleUIMetafilePictFromIconAndLabel(hIcon,
                                             szUniLabel,
                                             lpCV->lpszIconSource,
                                             lpCV->IconIndex);

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

               // Only show help if we're showing it for this dialog.
               if (lpCV->dwFlags & CF_SHOWHELPBUTTON)
                 ci.dwFlags  |= CIF_SHOWHELP;

               iSel = (int)SendMessage(lpCV->hListVisible, LB_GETCURSEL, 0, 0L);

               CoGetMalloc(MEMCTX_TASK, &pIMalloc);

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

               // Get whole string
               SendMessage(lpCV->hListVisible, LB_GETTEXT, iSel, (LONG)pszString);

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

               // Get the clsid to pass to change icon.
               A2W (pszCLSID, pszUniCLSID, 256);
               CLSIDFromString(pszUniCLSID, (LPCLSID)&(ci.clsid));

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

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

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

               //Update the display if necessary.
               if (0!=uRet)
               {
                  HICON hIcon;
                  char  szLabel[OLEUI_CCHLABELMAX];
                  OLECHAR szUniLabel[OLEUI_CCHLABELMAX];
                  DWORD dwWrapIndex;


                  hIcon = OleUIMetafilePictExtractIcon(ci.hMetaPict);

                  SendDlgItemMessage(hDlg, IDCV_ICON, STM_SETICON, (WPARAM)hIcon, 0L);

                  OleUIMetafilePictExtractIconSource(ci.hMetaPict, lpCV->lpszIconSource, &(lpCV->IconIndex));

                  OleUIMetafilePictExtractLabel(ci.hMetaPict, szUniLabel, OLEUI_CCHLABELMAX, &dwWrapIndex);
                  W2A (szUniLabel, szLabel, OLEUI_CCHLABELMAX);

                  if (0 == dwWrapIndex)  // no second line
                  {
                     SendDlgItemMessage(hDlg, IDCV_ICONLABEL1, WM_SETTEXT, 0, (LPARAM)szLabel);
                     SendDlgItemMessage(hDlg, IDCV_ICONLABEL2, WM_SETTEXT, 0, (LPARAM)"");
                  }
                  else
                  {

                     LPSTR lpszSecondLine;

                     lpszSecondLine = szLabel + dwWrapIndex;
                     SendDlgItemMessage(hDlg, IDCV_ICONLABEL2,
                                   WM_SETTEXT, 0, (LPARAM)lpszSecondLine);

                     *lpszSecondLine = '\0';
                     SendDlgItemMessage(hDlg, IDCV_ICONLABEL1,
                                   WM_SETTEXT, 0, (LPARAM)szLabel);
                  }


                  // Update our custom/default flag

                  if (ci.dwFlags & CIF_SELECTDEFAULT)
                     lpCV->fCustomIcon = FALSE;   // we're in default mode (icon changes on each LB selchange)
                  else if (ci.dwFlags & CIF_SELECTFROMFILE)
                     lpCV->fCustomIcon = TRUE;    // we're in custom mode (icon doesn't change)
                  // no change in fCustomIcon if user selected current


                  lpCV->lpOCV->fObjectsIconChanged = TRUE;
               }
            }
            break;

         }
         break;
      }
   return FALSE;
   }


/*
 * FConvertInit
 *
 * Purpose:
 *  WM_INITIDIALOG handler for the Convert 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 FConvertInit(HWND hDlg, WPARAM wParam, LPARAM lParam)
   {
   LPCONVERT              lpCV;
   LPOLEUICONVERT         lpOCV;
   LPMALLOC               pIMalloc;
   HFONT                  hFont;  // non-bold version of dialog's font
   RECT                   rc;
   DWORD                  dw;
   int                    cItemsActivate;
   HKEY                   hKey;
   LONG                   lRet;
   UINT                   nRet;
   char                   szAnsiStr[256];


   //Copy the structure at lParam into our instance memory.
   lpCV=(LPCONVERT)LpvStandardInit(hDlg, sizeof(CONVERT), TRUE, (HFONT FAR *)&hFont);

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

   lpOCV=(LPOLEUICONVERT)lParam;

   lpCV->lpOCV=lpOCV;

   lpCV->fCustomIcon = FALSE;

   //Copy other information from lpOCV that we might modify.
   lpCV->dwFlags = lpOCV->dwFlags;
   lpCV->clsid = lpOCV->clsid;
   lpCV->dvAspect = lpOCV->dvAspect;
   lpCV->hListVisible = GetDlgItem(hDlg, IDCV_ACTIVATELIST);
   lpCV->hListInvisible = GetDlgItem(hDlg, IDCV_CONVERTLIST);
   lpCV->lpszCurrentObject = lpOCV->lpszUserType;

   lpOCV->clsidNew = CLSID_NULL;

   lpOCV->fObjectsIconChanged = FALSE;

   //Allocate space for our strings
   if (NOERROR != CoGetMalloc(MEMCTX_TASK, &pIMalloc))
      return FALSE;

   lpCV->lpszConvertDefault = (LPOLESTR)pIMalloc->lpVtbl->Alloc(pIMalloc, OLEUI_CCHLABELMAX*sizeof(OLECHAR));
   lpCV->lpszActivateDefault = (LPOLESTR)pIMalloc->lpVtbl->Alloc(pIMalloc, OLEUI_CCHLABELMAX*sizeof(OLECHAR));
   lpCV->lpszIconSource = (LPOLESTR)pIMalloc->lpVtbl->Alloc(pIMalloc, OLEUI_CCHPATHMAX*sizeof(OLECHAR));

   lpCV->lpszConvertDefault[0]=0;
   lpCV->lpszActivateDefault[0]=0;
   lpCV->lpszIconSource[0]=0;

   pIMalloc->lpVtbl->Release(pIMalloc);

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

   //Hide the help button if necessary
   if (!(lpCV->dwFlags & CF_SHOWHELPBUTTON))
      StandardShowDlgItem(hDlg, ID_OLEUIHELP, SW_HIDE);

   //Fill the Object Type listbox with entries from the reg DB.
   nRet = FillClassList(lpOCV->clsid,
              lpCV->hListVisible,
              lpCV->hListInvisible,
              &(lpCV->lpszCurrentObject),
              lpOCV->fIsLinkedObject,
              lpOCV->wFormat,
              lpOCV->cClsidExclude,
              lpOCV->lpClsidExclude);

   if (nRet == -1) {
      // bring down dialog if error when filling list box
      PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_LOADSTRING, 0L);
   }

   // Set the name of the current object.
   W2A (lpCV->lpszCurrentObject, szAnsiStr, 256);
   SetDlgItemText(hDlg, IDCV_OBJECTTYPE, szAnsiStr);

   // Disable the "Activate As" button if the Activate list doesn't
   // have any objects in it.

   cItemsActivate = (int)SendMessage(lpCV->hListVisible, LB_GETCOUNT, 0, 0L);

   if (1 >= cItemsActivate || (lpCV->dwFlags & CF_DISABLEACTIVATEAS))
     EnableWindow(GetDlgItem(hDlg, IDCV_ACTIVATEAS), FALSE);

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


   // Make sure that either "Convert To" or "Activate As" is selected
   // and initialize listbox contents and selection accordingly
   if (lpCV->dwFlags & CF_SELECTACTIVATEAS)
   {
     // Don't need to adjust listbox here because FillClassList
     // initializes to the "Activate As" state.
      CheckRadioButton(hDlg, IDCV_CONVERTTO, IDCV_ACTIVATEAS, IDCV_ACTIVATEAS);

      // Hide the icon stuff when Activate is selected...it gets shown
      // again when Convert is selected.

      StandardShowDlgItem(hDlg, IDCV_DISPLAYASICON, SW_HIDE);
      StandardShowDlgItem(hDlg, IDCV_CHANGEICON, SW_HIDE);
      StandardShowDlgItem(hDlg, IDCV_ICON, SW_HIDE);
      StandardShowDlgItem(hDlg, IDCV_ICONLABEL1, SW_HIDE);
      StandardShowDlgItem(hDlg, IDCV_ICONLABEL2, SW_HIDE);
   }
   else
   {
     // Default case.  If user hasn't selected either flag, we will
     // come here anyway.
     // swap listboxes.

     HWND hWndTemp = lpCV->hListVisible;

     if ( lpCV->dwFlags & CF_DISABLEDISPLAYASICON ) {
        StandardShowDlgItem(hDlg, IDCV_DISPLAYASICON, SW_HIDE);
        StandardShowDlgItem(hDlg, IDCV_CHANGEICON, SW_HIDE);
        StandardShowDlgItem(hDlg, IDCV_ICON, SW_HIDE);
        StandardShowDlgItem(hDlg, IDCV_ICONLABEL1, SW_HIDE);
        StandardShowDlgItem(hDlg, IDCV_ICONLABEL2, SW_HIDE);
     }

     lpCV->dwFlags |= CF_SELECTCONVERTTO; // Make sure flag is set
     CheckRadioButton(hDlg, IDCV_CONVERTTO, IDCV_ACTIVATEAS, IDCV_CONVERTTO);

     SwapWindows(hDlg, lpCV->hListVisible, lpCV->hListInvisible);

     lpCV->hListVisible = lpCV->hListInvisible;
     lpCV->hListInvisible = hWndTemp;

     EnableWindow(lpCV->hListInvisible, FALSE);
     EnableWindow(lpCV->hListVisible, TRUE);
   }



   // Initialize Default strings.

   // Default convert string is easy...just user the user type name from
   // the clsid we got, or the current object
   if ( (lpCV->dwFlags & CF_SETCONVERTDEFAULT)
       && (IsValidClassID(lpCV->lpOCV->clsidConvertDefault)) )
   {
      dw = OleStdGetUserTypeOfClass((LPCLSID)(&lpCV->lpOCV->clsidConvertDefault),
                             lpCV->lpszConvertDefault,
                             OLEUI_CCHLABELMAX,
                             NULL);

      if (0 == dw)
         OLESTRCPY ((LPOLESTR)lpCV->lpszConvertDefault, (LPOLESTR)lpCV->lpszCurrentObject);
   }
   else
      OLESTRCPY((LPOLESTR)lpCV->lpszConvertDefault, (LPOLESTR)lpCV->lpszCurrentObject);



   // Default activate is a bit trickier.  We want to use the user type
   // name if from the clsid we got (assuming we got one), or the current
   // object if it fails or we didn't get a clsid.  But...if there's a
   // Treat As entry in the reg db, then we use that instead.  So... the
   // logic boils down to this:
   //
   // if ("Treat As" in reg db)
   //    use it;
   // else
   //    if (CF_SETACTIVATEDEFAULT)
   //      use it;
   //    else
   //      use current object;



   lRet = RegOpenKey(HKEY_CLASSES_ROOT, "CLSID", (HKEY FAR *)&hKey);

   if (lRet != ERROR_SUCCESS)
     goto CheckInputFlag;

   else
   {
      LPOLESTR    lpszCLSID;
      char  lpszAnsiCLSID[256];
      char  szKey[OLEUI_CCHKEYMAX];
      CLSID clsid;
      char  szValue[OLEUI_CCHKEYMAX];
      OLECHAR szUniValue[OLEUI_CCHKEYMAX];

      StringFromCLSID(&(lpCV->lpOCV->clsid), &lpszCLSID);
      W2A (lpszCLSID, lpszAnsiCLSID, 256);
      lstrcpy(szKey, lpszAnsiCLSID);
      lstrcat(szKey, "\\TreatAs");

      dw = OLEUI_CCHKEYMAX;
      lRet = RegQueryValue(hKey, szKey, szValue, (LPDWORD)&dw);

      if (lRet != ERROR_SUCCESS)
      {

        RegCloseKey(hKey);
        OleStdFreeString(lpszCLSID, NULL);
        goto CheckInputFlag;
      }
      else
      {
        A2W (szValue, szUniValue, OLEUI_CCHKEYMAX);
        CLSIDFromString(szUniValue, &clsid);
        if (0 == OleStdGetUserTypeOfClass(&clsid,
                           lpCV->lpszActivateDefault,
                           OLEUI_CCHLABELMAX,
                           NULL))
        {
          RegCloseKey(hKey);
          OleStdFreeString(lpszCLSID, NULL);
          goto CheckInputFlag;
        }
      }
      RegCloseKey(hKey);
      OleStdFreeString(lpszCLSID, NULL);
      goto SelectStringInListbox;
   }


CheckInputFlag:
   if ( (lpCV->dwFlags & CF_SETACTIVATEDEFAULT)
       && (IsValidClassID(lpCV->lpOCV->clsidActivateDefault)) )
   {
      dw = OleStdGetUserTypeOfClass((LPCLSID)(&lpCV->lpOCV->clsidActivateDefault),
                             lpCV->lpszActivateDefault,
                             OLEUI_CCHLABELMAX,
                             NULL);

      if (0 == dw)
         OLESTRCPY((LPOLESTR)lpCV->lpszActivateDefault, (LPOLESTR)lpCV->lpszCurrentObject);
   }
   else
      OLESTRCPY((LPOLESTR)(lpCV->lpszActivateDefault), (LPOLESTR)lpCV->lpszCurrentObject);


SelectStringInListbox:

   if (lpCV->dwFlags & CF_SELECTCONVERTTO) {
      W2A (lpCV->lpszConvertDefault, szAnsiStr, 256);
      lRet = SendMessage(lpCV->hListVisible, LB_SELECTSTRING, (WPARAM)-1, (LPARAM)szAnsiStr);
   }

   else {
      W2A (lpCV->lpszActivateDefault, szAnsiStr, 256);
      lRet = SendMessage(lpCV->hListVisible, LB_SELECTSTRING, (WPARAM)-1, (LPARAM)szAnsiStr);
   }

   if (LB_ERR == lRet)
      SendMessage(lpCV->hListVisible, LB_SETCURSEL, (WPARAM)0, 0L);


   // Initialize icon stuff
   if (DVASPECT_ICON == lpCV->dvAspect )
   {
     SendDlgItemMessage(hDlg, IDCV_DISPLAYASICON, BM_SETCHECK, TRUE, 0L);

     if ((HGLOBAL)NULL != lpOCV->hMetaPict)
     {
       OLECHAR  szLabel[OLEUI_CCHLABELMAX];
       char     szAnsiLabel[OLEUI_CCHLABELMAX];
       HICON hIcon;
       DWORD dwWrapIndex;


       // Set the icon to the icon from the hMetaPict,
       // set the label to the label from the hMetaPict.

       if (0 != OleUIMetafilePictExtractLabel(lpOCV->hMetaPict, szLabel, OLEUI_CCHLABELMAX, &dwWrapIndex))
       {
          W2A (szLabel, szAnsiLabel, OLEUI_CCHLABELMAX);
          if (0 == dwWrapIndex)  // no second line
          {
            SendDlgItemMessage(hDlg, IDCV_ICONLABEL1, WM_SETTEXT, 0, (LPARAM)szAnsiLabel);
            SendDlgItemMessage(hDlg, IDCV_ICONLABEL2, WM_SETTEXT, 0, (LPARAM)"");
          }
          else
          {

            LPSTR lpszSecondLine;

            lpszSecondLine = szAnsiLabel + dwWrapIndex;
            SendDlgItemMessage(hDlg, IDCV_ICONLABEL2,
                           WM_SETTEXT, 0, (LPARAM)lpszSecondLine);

            *lpszSecondLine = '\0';
            SendDlgItemMessage(hDlg, IDCV_ICONLABEL1,
                           WM_SETTEXT, 0, (LPARAM)szAnsiLabel);
          }


       }

       hIcon = OleUIMetafilePictExtractIcon(lpOCV->hMetaPict);

       if (NULL != hIcon)
       {
         SendDlgItemMessage(hDlg, IDCV_ICON, STM_SETICON, (WPARAM)hIcon, 0L);
         lpCV->fCustomIcon = TRUE;
       }

       OleUIMetafilePictExtractIconSource(lpOCV->hMetaPict,
                                 lpCV->lpszIconSource,
                                 &(lpCV->IconIndex));

     }
     else
       UpdateCVClassIcon(hDlg, lpCV, lpCV->hListVisible);
   }
   else
   {
     // Hide & disable icon stuff
     StandardShowDlgItem(hDlg, IDCV_ICON, SW_HIDE);
     StandardShowDlgItem(hDlg, IDCV_ICONLABEL1, SW_HIDE);
     StandardShowDlgItem(hDlg, IDCV_ICONLABEL2, SW_HIDE);
     StandardShowDlgItem(hDlg, IDCV_CHANGEICON, SW_HIDE);
   }

   // Call the hook with lCustData in lParam
   UStandardHook((LPVOID)lpCV, hDlg, WM_INITDIALOG, wParam, lpOCV->lCustData);
   // Update results window
   SetConvertResults(hDlg, lpCV);

   // Update caption if lpszCaption was specified
   if (lpCV->lpOCV->lpszCaption && !IsBadReadPtr(lpCV->lpOCV->lpszCaption, 1)
        && lpCV->lpOCV->lpszCaption[0] != '\0') {
      W2A (lpCV->lpOCV->lpszCaption, szAnsiStr, 256);
      SetWindowText(hDlg, szAnsiStr);
   }

   return TRUE;
   }


/*
 * FillClassList
 *
 * Purpose:
 *  Enumerates available OLE object classes from the registration
 *  database that we can convert or activate the specified clsid from.
 *
 *  Note that this function removes any prior contents of the listbox.
 *
 * Parameters:
 *  clsid           Class ID for class to find convert classes for
 *  hList           HWND to the listbox to fill.
 *  hListInvisible  HWND to invisible listbox that stores "activate as" list.
 *  lpszCurrentClass LPSTR to put the (hr) class name of the clsid; we
 *                   do it here since we've already got the reg db open.
 *  fIsLinkedObject BOOL is the original object a linked object
 *  wFormat         WORD specifying the format of the original class.
 *  cClsidExclude   UINT number of entries in exclude list
 *  lpClsidExclude  LPCLSID array classes to exclude for list
 *
 * Return Value:
 *  UINT            Number of strings added to the listbox, -1 on failure.
 */

UINT FillClassList(
      CLSID clsid,
      HWND hList,
      HWND hListInvisible,
      LPOLESTR FAR *lplpszCurrentClass,
      BOOL fIsLinkedObject,
      WORD wFormat,
      UINT cClsidExclude,
      LPCLSID lpClsidExclude)
{

   DWORD       dw;
   UINT        cStrings=0;
   HKEY        hKey;
   LONG        lRet;
   char        szFormatKey[OLEUI_CCHKEYMAX];
   char        szClass[OLEUI_CCHKEYMAX];
   OLECHAR     szUniClass[OLEUI_CCHKEYMAX];
   char        szFormat[OLEUI_CCHKEYMAX];
   char        szHRClassName[OLEUI_CCHKEYMAX];
   CLSID       clsidForList;

   LPOLESTR    lpszCLSID;
   char        lpszAnsiCLSID[256];
   char        lplpszAnsiCurrentClass[OLEUI_CCHKEYMAX];


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

   //Open up the root key.
   lRet=RegOpenKey(HKEY_CLASSES_ROOT, "CLSID", (HKEY FAR *)&hKey);

   if ((LONG)ERROR_SUCCESS!=lRet)
      return (UINT)-1;

   if (NULL == *lplpszCurrentClass)
      {
      // alloc buffer here...

      LPMALLOC pIMalloc = NULL;
      HRESULT  hrErr;


      hrErr = CoGetMalloc(MEMCTX_TASK, &pIMalloc);

      if (hrErr != NOERROR)
         {
         RegCloseKey(hKey);
         return FALSE;
         }

      // Allocate space for lpszCurrentClass
      *lplpszCurrentClass = (LPOLESTR)pIMalloc->lpVtbl->Alloc(pIMalloc, OLEUI_CCHKEYMAX*sizeof(OLECHAR));
       pIMalloc->lpVtbl->Release(pIMalloc);

      lRet = OleStdGetUserTypeOfClass((REFCLSID)&clsid,
                              *lplpszCurrentClass, OLEUI_CCHLABELMAX, NULL);

      if (0 ==lRet)
         {
         int n = LoadString(ghInst, (UINT)IDS_PSUNKNOWNTYPE, lplpszAnsiCurrentClass,
               OLEUI_CCHKEYMAX);
         A2W (lplpszAnsiCurrentClass, *lplpszCurrentClass, OLEUI_CCHKEYMAX);
         if (!n)
            {
            RegCloseKey(hKey);
            return (UINT)-1;
            }
         }
      }


   W2A (*lplpszCurrentClass, lplpszAnsiCurrentClass, OLEUI_CCHKEYMAX);

   // Get the class name of the original class.
   StringFromCLSID((REFCLSID)&clsid, &lpszCLSID);


   // Here, we step through the entire registration db looking for
   // class that can read or write the original class' format.  We
   // maintain two lists - an activate list and a convert list.  The
   // activate list is a subset of the convert list - activate == read/write
   // and convert == read. We swap the listboxes as needed with
   // SwapWindows, and keep track of which is which in the lpCV structure.

   // Every item has the following format:
   //
   //     Class Name\tclsid\0


   cStrings=0;
   lRet=RegEnumKey(hKey, cStrings++, szClass, OLEUI_CCHKEYMAX);

   while ((LONG)ERROR_SUCCESS==lRet)
      {
      int j;
      BOOL fExclude=FALSE;


      //Check if this CLSID is in the exclusion list.
      A2W (szClass, szUniClass, OLEUI_CCHKEYMAX);
      CLSIDFromString(szUniClass, (LPCLSID)&clsidForList);
      for (j=0; j < (int)cClsidExclude; j++)
         {
         if (IsEqualCLSID(&clsidForList, (LPCLSID)(lpClsidExclude+j)))
            {
            fExclude=TRUE;
            break;
            }
         }

      if (fExclude)
         goto Next;   // don't add this class to list

      // Check for a \Conversion\Readwritable\Main - if its
      // readwriteable, then the class can be added to the ActivateAs
      // list.
      // NOTE: the presence of this key should NOT automatically be
      //       used to add the class to the CONVERT list.

      lstrcpy(szFormatKey, szClass);
      lstrcat(szFormatKey, "\\Conversion\\Readwritable\\Main");

      dw=OLEUI_CCHKEYMAX;

      lRet=RegQueryValue(hKey, szFormatKey, szFormat, (LONG FAR *)&dw);

      if ( ((LONG)ERROR_SUCCESS==lRet)
          && (FormatIncluded(szFormat, wFormat)) )
         {
         // Here, we've got a list of formats that this class can read
         // and write. We need to see if the original class' format is
         // in this list.  We do that by looking for wFormat in
         // szFormat - if it in there, then we add this class to the
         // ACTIVATEAS list only. we do NOT automatically add it to the
         // CONVERT list. Readable and Readwritable format lists should
         // be handled separately.

         dw=OLEUI_CCHKEYMAX;
         lRet=RegQueryValue(hKey, szClass, szHRClassName, (LPDWORD)&dw);

         if ((LONG)ERROR_SUCCESS==lRet)
            {
            lstrcat(szHRClassName, "\t");

            // only add if not already in list
            if (LB_ERR==SendMessage(hList,LB_FINDSTRING, 0,
                  (LPARAM)szHRClassName))
               {
               lstrcat(szHRClassName, szClass);
               SendMessage(hList, LB_ADDSTRING, 0,
                     (DWORD)szHRClassName);
               }
            }
         }


      // Here we'll check to see if the original class' format is in the
      // readable list. if so, we will add the class to the CONVERTLIST


      // We've got a special case for a linked object here.
      // If an object is linked, then the only class that
      // should appear in the convert list is the object's
      // class.  So, here we check to see if the object is
      // linked.  If it is, then we compare the classes.  If
      // they aren't the same, then we just go to the next key.

      W2A (lpszCLSID, lpszAnsiCLSID, 256);
      if ( (!fIsLinkedObject)
            || (lstrcmp(lpszAnsiCLSID, szClass) == 0) )
         {
         //Check for a \Conversion\Readable\Main entry
         lstrcpy(szFormatKey, szClass);
         lstrcat(szFormatKey, "\\Conversion\\Readable\\Main");

         dw=OLEUI_CCHKEYMAX;

         // Check to see if this class can read the original class
         // format.  If it can, add the string to the listbox as
         // CONVERT_LIST.

         lRet=RegQueryValue(hKey, szFormatKey, szFormat, (LPDWORD)&dw);

         if ( ((LONG)ERROR_SUCCESS==lRet)
             && (FormatIncluded(szFormat, wFormat)) )
            {
            dw=OLEUI_CCHKEYMAX;
            lRet=RegQueryValue(hKey, szClass, szHRClassName, (LPDWORD)&dw);

            if ((LONG)ERROR_SUCCESS==lRet)
               {
               lstrcat(szHRClassName, "\t");

               // only add if not already in list
               if (LB_ERR==SendMessage(hListInvisible,LB_FINDSTRING, 0,
                     (LPARAM)szHRClassName))
                  {
                  lstrcat(szHRClassName, szClass);
                  SendMessage(hListInvisible, LB_ADDSTRING, 0,
                        (DWORD)szHRClassName);
                  }
               }  // end if

            } // end if
         } // end else


Next:
      //Continue with the next key.
      lRet=RegEnumKey(hKey, cStrings++, szClass, OLEUI_CCHKEYMAX);

      }  // end while

   // If the original class isn't already in the list, add it.

   lstrcpy(szHRClassName, lplpszAnsiCurrentClass);
   lstrcat(szHRClassName, "\t");

   lRet = SendMessage(hList, LB_FINDSTRING, (WPARAM)-1, (LPARAM)szHRClassName);

   // only add it if it's not there already.
   if (LB_ERR == lRet)
      {
      lstrcat(szHRClassName, lpszAnsiCLSID);
      SendMessage(hList, LB_ADDSTRING, 0, (LPARAM)szHRClassName);
      }

   lRet = SendMessage(hListInvisible, LB_FINDSTRING, (WPARAM)-1, (LPARAM)szHRClassName);

   // only add it if it's not there already.
   if (LB_ERR == lRet)
      SendMessage(hListInvisible, LB_ADDSTRING, 0, (LPARAM)szHRClassName);

   // Free the string we got from StringFromCLSID.
   // OLE2NOTE:  StringFromCLSID uses your IMalloc to alloc a
   // string, so you need to be sure to free the string you
   // get back, otherwise you'll have leaky memory.

   OleStdFreeString(lpszCLSID, NULL);
   RegCloseKey(hKey);
   return cStrings;
   }


/*
 * OleUICanConvertOrActivateAs
 *
 * Purpose:
 *  Determine if there is any OLE object class from the registration
 *  database that we can convert or activate the specified clsid from.
 *
 * Parameters:
 *  rClsid          REFCLSID Class ID for class to find convert classes for
 *  fIsLinkedObject BOOL is the original object a linked object
 *  wFormat         WORD specifying the format of the original class.
 *
 * Return Value:
 *  BOOL            TRUE if Convert command should be enabled, else FALSE
 */

STDAPI_(BOOL) OleUICanConvertOrActivateAs(
      REFCLSID    rClsid,
      BOOL        fIsLinkedObject,
      WORD        wFormat
)
{

   DWORD       dw;
   UINT        cStrings=0;
   HKEY        hKey;
   LONG        lRet;
   char        szFormatKey[OLEUI_CCHKEYMAX];
   char        szClass[OLEUI_CCHKEYMAX];
   char        szFormat[OLEUI_CCHKEYMAX];
   char        szHRClassName[OLEUI_CCHKEYMAX];
   BOOL        fEnableConvert = FALSE;

   LPOLESTR    lpszCLSID;
   char        lpszAnsiCLSID[256];

   //Open up the root key.
   lRet=RegOpenKey(HKEY_CLASSES_ROOT, "CLSID", (HKEY FAR *)&hKey);

   if ((LONG)ERROR_SUCCESS!=lRet)
      return FALSE;

   // Get the class name of the original class.
   StringFromCLSID(rClsid, &lpszCLSID);
   W2A (lpszCLSID, lpszAnsiCLSID, 256);

   // Here, we step through the entire registration db looking for
   // class that can read or write the original class' format.
   // This loop stops if a single class is found.

   cStrings=0;
   lRet=RegEnumKey(hKey, cStrings++, szClass, OLEUI_CCHKEYMAX);

   while ((LONG)ERROR_SUCCESS==lRet)
   {
      if (lstrcmp(lpszAnsiCLSID, szClass) == 0)
         goto next;   // we don't want to consider the source class

      // Check for a \Conversion\ReadWriteable\Main entry first - if its
      // readwriteable, then we don't need to bother checking to see if
      // its readable.

      lstrcpy(szFormatKey, szClass);
      lstrcat(szFormatKey, "\\Conversion\\Readwritable\\Main");

      dw=OLEUI_CCHKEYMAX;

      lRet=RegQueryValue(hKey, szFormatKey, szFormat, (LONG FAR *)&dw);

      if ( (LONG)ERROR_SUCCESS != lRet)
      {
        // Try \\DataFormats\DefaultFile too

        lstrcpy(szFormatKey, szClass);
        lstrcat(szFormatKey, "\\DataFormats\\DefaultFile");

        dw=OLEUI_CCHKEYMAX;

        lRet=RegQueryValue(hKey, szFormatKey, szFormat, (LONG FAR *)&dw);
      }


      if ( ((LONG)ERROR_SUCCESS==lRet)
          && (FormatIncluded(szFormat, wFormat)) )
      {

         // Here, we've got a list of formats that this class can read
         // and write. We need to see if the original class' format is
         // in this list.  We do that by looking for wFormat in
         // szFormat - if it in there, then we add this class to the
         // both lists and continue.  If not, then we look at the
         // class' readable formats.


         dw=OLEUI_CCHKEYMAX;
         lRet=RegQueryValue(hKey, szClass, szHRClassName, (LPDWORD)&dw);

         if ((LONG)ERROR_SUCCESS==lRet)
         {
            fEnableConvert = TRUE;
            break;  // STOP -- found one!
         }

      }


      // We either didn't find the readwritable key, or the
      // list of readwritable formats didn't include the
      // original class format.  So, here we'll check to
      // see if its in the readable list.


      // We've got a special case for a linked object here.
      // If an object is linked, then the only class that
      // should appear in the convert list is the object's
      // class.  So, here we check to see if the object is
      // linked.  If it is, then we compare the classes.  If
      // they aren't the same, then we just go to the next key.

      else if ( (!fIsLinkedObject)
            || (lstrcmp(lpszAnsiCLSID, szClass) == 0) )
      {

         //Check for a \Conversion\Readable\Main entry
         lstrcpy(szFormatKey, szClass);
         lstrcat(szFormatKey, "\\Conversion\\Readable\\Main");

         dw=OLEUI_CCHKEYMAX;

         // Check to see if this class can read the original class
         // format.  If it can, add the string to the listbox as
         // CONVERT_LIST.

         lRet=RegQueryValue(hKey, szFormatKey, szFormat, (LPDWORD)&dw);

         if ( ((LONG)ERROR_SUCCESS==lRet)
             && (FormatIncluded(szFormat, wFormat)) )
         {


            dw=OLEUI_CCHKEYMAX;
            lRet=RegQueryValue(hKey, szClass, szHRClassName, (LPDWORD)&dw);

            if ((LONG)ERROR_SUCCESS==lRet)
            {

               fEnableConvert = TRUE;
               break;  // STOP -- found one!
            }  // end if

         } // end if
      } // end else
next:
      //Continue with the next key.
      lRet=RegEnumKey(hKey, cStrings++, szClass, OLEUI_CCHKEYMAX);

   }  // end while

   // Free the string we got from StringFromCLSID.
   // OLE2NOTE:  StringFromCLSID uses your IMalloc to alloc a
   // string, so you need to be sure to free the string you
   // get back, otherwise you'll have leaky memory.

   OleStdFreeString(lpszCLSID, NULL);

   RegCloseKey(hKey);

   return fEnableConvert;
}


/*
 * FormatIncluded
 *
 * Purpose:
 *  Parses the string for format from the word.
 *
 * Parameters:
 *  szStringToSearch  String to parse
 *  wFormat           format to find
 *
 * Return Value:
 *  BOOL        TRUE if format is found in string,
 *              FALSE otherwise.
 */
BOOL FormatIncluded(LPSTR szStringToSearch, WORD wFormat)
{

   LPSTR        lpToken;
   char         seps[] = ",";
   static char  szFormat[255];  // max size of atom (what GetClipboardName returns)


   if (wFormat < 0xC000)             // RegisterClipboardFormat returns values
      _itoa(wFormat, szFormat, 10);  // between 0xC000 and 0xFFFF.

   else
      GetClipboardFormatName(wFormat, szFormat, 255);


   lpToken = _fstrtok(szStringToSearch, seps);

   while (lpToken != NULL)
   {

    if (0 == lstrcmpi(lpToken, szFormat))
      return TRUE;

    else
      lpToken = _fstrtok(NULL, seps);
   }

   return FALSE;
}


/*
 * UpdateCVClassIcon
 *
 * 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.
 *  lpCV            LPCONVERT pointing to the dialog structure
 *  hList           HWND of the Object Type listbox.
 *
 * Return Value:
 *  None
 */

void UpdateCVClassIcon(HWND hDlg, LPCONVERT lpCV, HWND hList)
   {
   UINT        iSel;
   DWORD       cb;
   HGLOBAL     hMem;
   LPSTR       pszName, pszCLSID;
   OLECHAR     pszUniCLSID[256];
   CLSID       clsid;
   HICON       hIcon, hOldIcon;
   UINT        cch, uWrapIndex;
   RECT        LabelRect;
   char        szLabel[OLEUI_CCHLABELMAX];
   OLECHAR     szUniLabel[OLEUI_CCHLABELMAX];
   LPSTR       lpszLabel = szLabel;
   HFONT       hFont;
   HWND        hLabel1;
   char        szAnsiIconSource[256];
   char        szAnsiStr[256];
   OLECHAR     szUniStr[256];

   /*
    * When we change object type selection, get the new icon for that
    * type into our structure and update it in the display.
    */

   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);

   hMem=GlobalAlloc(GHND, cb+1);

   if (NULL==hMem)
      return;

   pszName=GlobalLock(hMem);

   // Get whole string
   SendMessage(hList, LB_GETTEXT, iSel, (LONG)pszName);

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

   //Create the class ID with this string.
   A2W (pszCLSID, pszUniCLSID, 256);
   CLSIDFromString(pszUniCLSID, (LPCLSID)&clsid);

   W2A (lpCV->lpszIconSource, szAnsiIconSource, 256);
   hIcon = HIconAndSourceFromClass(&clsid, szAnsiIconSource, &(lpCV->IconIndex));

   if (NULL == hIcon)  // Use Vanilla Document
      {
      lstrcpy(szAnsiIconSource, szOLE2DLL);
      A2W (szAnsiIconSource, lpCV->lpszIconSource, 256);
      lpCV->IconIndex = 0;    // 1st icon in OLE2.DLL
      hIcon = ExtractIcon(ghInst,
                     szAnsiIconSource,
                     lpCV->IconIndex);
      }
   else
      A2W (szAnsiIconSource, lpCV->lpszIconSource, 256);

   //Replace the current display with this new one.
   hOldIcon = (HICON)SendDlgItemMessage(hDlg, IDCV_ICON, STM_SETICON, (WPARAM)hIcon, 0L);

   hLabel1 = GetDlgItem(hDlg, IDCV_ICONLABEL1);

   GetWindowRect(hLabel1, &LabelRect);

   // Get the label
   if (lpCV->lpOCV->lpszDefLabel)
      {
      // width is used as 1.5 times width of icon window
      W2A (lpCV->lpOCV->lpszDefLabel, szAnsiStr, 256);
      lpszLabel = ChopText(hLabel1, ((LabelRect.right-LabelRect.left)*3)/2, szAnsiStr);
      W2A(lpCV->lpOCV->lpszDefLabel, szLabel, OLEUI_CCHLABELMAX);
      }
   else
      {
      szUniLabel[0]=0;
      if ((cch = OleStdGetAuxUserType(&clsid, AUXUSERTYPE_SHORTNAME,
            (LPOLESTR)szUniLabel, OLEUI_CCHLABELMAX, NULL)) == 0)
         {
         // If we can't get the AuxUserType2, then try the long name
         if ((cch = OleStdGetUserTypeOfClass(&clsid, (LPOLESTR)szUniLabel,
               OLESTRLEN(szUniLabel)+1, NULL)) == 0)
            {
            //Last resort; use "Document" as label
            LoadStringW(ghInst,(UINT)IDS_DEFICONLABEL,szUniLabel,OLEUI_CCHLABELMAX);
            }
         }

      W2A (szUniLabel, szLabel, 256);
      }

   hFont = (HFONT)SendMessage(hLabel1, WM_GETFONT, 0, 0L);

   // Figure out where to split the label
   A2W (lpszLabel, szUniStr, 256);
   cch = lstrlen(lpszLabel);
   uWrapIndex = OleStdIconLabelTextOut(NULL, hFont, 0, 0, 0, &LabelRect, szUniStr, cch, NULL);

   if (0 == uWrapIndex)
   {
      SendMessage(hLabel1, WM_SETTEXT, 0, (LPARAM)lpszLabel);
      SendDlgItemMessage(hDlg, IDCV_ICONLABEL2, WM_SETTEXT, 0, (LPARAM)"");
   }
   else
   {
      char  chKeep;
      LPSTR lpszSecondLine;

      chKeep = szLabel[uWrapIndex];
      lpszLabel[uWrapIndex] = '\0';

      SendMessage(hLabel1, WM_SETTEXT, 0, (LPARAM)lpszLabel);

      lpszLabel[uWrapIndex] = chKeep;
      lpszSecondLine = lpszLabel + uWrapIndex;

      SendDlgItemMessage(hDlg, IDCV_ICONLABEL2, WM_SETTEXT, 0, (LPARAM)lpszSecondLine);
   }

   // get rid of the old icon
   if ((HICON)NULL != hOldIcon)
     DestroyIcon(hOldIcon);

   GlobalUnlock(hMem);
   GlobalFree(hMem);
   return;
   }






BOOL IsValidClassID(CLSID cID)
{
   if (0 == _fmemcmp(&cID, &CLSID_NULL, sizeof(CLSID)))  // if (CLSID_NULL == cID)
     return FALSE;
   else
     return TRUE;
}



/*
 * SetConvertResults
 *
 * Purpose:
 *  Centralizes setting of the Result display in the Convert
 *  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.
 *  lpCV            LPCONVERT in which we assume that the dwFlags is
 *                  set to the appropriate radio button selection, and
 *                  the list box has the appropriate class selected.
 *
 * Return Value:
 *  None
 */

void SetConvertResults(HWND hDlg, LPCONVERT lpCV)
   {
   LPSTR       pszT,        // temp
            lpszOutput,  // text sent in SetDlgItemText
            lpszDefObj,  // string containing default object class
            lpszSelObj,  // string containing selected object class
            lpszString;  // stirng we get from loadstring

   UINT        i, cch;
   HGLOBAL     hMem;

   HWND        hList;  // handle to listbox (so we can just use SendMsg i
                  // instead of SendDlgItemMsg).


   hList = lpCV->hListVisible;
   /*
    * We need scratch memory for loading the stringtable string, loading
    * the object type from the listbox, loading the source object
    * type, and constructing the final string.  We therefore allocate
    * four buffers as large as the maximum message length (512) plus
    * the object type, guaranteeing that we have enough
    * in all cases.
    */
   i=(UINT)SendMessage(hList, LB_GETCURSEL, 0, 0L);

   cch=512+(UINT)SendMessage(hList, LB_GETTEXTLEN, i, 0L);

   hMem=GlobalAlloc(GHND, (DWORD)(4*cch));

   if (NULL==hMem)
      return;

   lpszOutput = GlobalLock(hMem);
   lpszSelObj = lpszOutput + cch;
   lpszDefObj = lpszSelObj + cch;
   lpszString = lpszDefObj + cch;

   // Get selected object and null terminate human-readable name (1st field).
   SendMessage(hList, LB_GETTEXT, i, (LONG)lpszSelObj);

   pszT = PointerToNthField(lpszSelObj, 2, '\t');

   pszT = AnsiPrev(lpszSelObj, pszT);

   *pszT = '\0';


   // Get default object

   GetDlgItemText(hDlg, IDCV_OBJECTTYPE, lpszDefObj, 512);


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


   if (lpCV->dwFlags & CF_SELECTCONVERTTO)
   {

      if (lpCV->lpOCV->fIsLinkedObject)  // working with linked object
        LoadString(ghInst, (UINT)IDS_CVRESULTCONVERTLINK, lpszOutput, cch);


      else
      {
         // converting to a new class
        if (0 != lstrcmp(lpszDefObj, lpszSelObj))
        {
         if (0 != LoadString(ghInst, (UINT)IDS_CVRESULTCONVERTTO, lpszString, cch))
            wsprintf(lpszOutput, lpszString, lpszDefObj, lpszSelObj);

        }
        else  // converting to the same class (no conversion)
        {

          if (0 != LoadString(ghInst, (UINT)IDS_CVRESULTNOCHANGE, lpszString, cch))
            wsprintf(lpszOutput, lpszString, lpszDefObj);
        }

      }

      if (lpCV->dvAspect == DVASPECT_ICON)  // Display as icon is checked
      {
         if (0 != LoadString(ghInst, (UINT)IDS_CVRESULTDISPLAYASICON, lpszString, cch))
            lstrcat(lpszOutput, lpszString);
      }
   }

   if (lpCV->dwFlags & CF_SELECTACTIVATEAS)
   {

      if (0!=LoadString(ghInst, (UINT)IDS_CVRESULTACTIVATEAS, lpszString, cch))
        wsprintf(lpszOutput, lpszString, lpszDefObj, lpszSelObj);

      // activating as a new class
      if (0 != lstrcmp(lpszDefObj, lpszSelObj))
      {
        if (0!=LoadString(ghInst, (UINT)IDS_CVRESULTACTIVATEDIFF, lpszString, cch))
          lstrcat(lpszOutput, lpszString);
      }
      else // activating as itself.
      {
       lstrcat(lpszOutput, ".");
      }
   }


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

   GlobalUnlock(hMem);
   GlobalFree(hMem);
   return;
   }






/*
 * ConvertCleanup
 *
 * Purpose:
 *  Performs convert-specific cleanup before Convert termination.
 *
 * Parameters:
 *  hDlg            HWND of the dialog box so we can access controls.
 *
 * Return Value:
 *  None
 */
void ConvertCleanup(HWND hDlg, LPCONVERT lpCV)
{

   LPMALLOC pIMalloc;


   // Free our strings. Zero out the user type name string
   // the the calling app doesn't free to it.

   if (NOERROR == CoGetMalloc(MEMCTX_TASK, &pIMalloc))
   {
      pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)lpCV->lpszConvertDefault);
      pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)lpCV->lpszActivateDefault);
      pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)lpCV->lpszIconSource);
      if (lpCV->lpOCV->lpszUserType) {
         pIMalloc->lpVtbl->Free(pIMalloc,(LPVOID)lpCV->lpOCV->lpszUserType);
         lpCV->lpOCV->lpszUserType = NULL;
      }
      if (lpCV->lpOCV->lpszDefLabel) {
         pIMalloc->lpVtbl->Free(pIMalloc,(LPVOID)lpCV->lpOCV->lpszDefLabel);
         lpCV->lpOCV->lpszDefLabel = NULL;
      }

      pIMalloc->lpVtbl->Release(pIMalloc);
   }

   return;
}





/*
 * SwapWindows
 *
 * Purpose:
 *  Moves hWnd1 to hWnd2's position and hWnd2 to hWnd1's position.
 *  Does NOT change sizes.
 *
 *
 * Parameters:
 *  hDlg            HWND of the dialog box so we can turn redraw off
 *
 * Return Value:
 *  None
 */
void SwapWindows(HWND hDlg, HWND hWnd1, HWND hWnd2)
{

   RECT Rect1, Rect2;


   GetWindowRect(hWnd1, &Rect1);
   GetWindowRect(hWnd2, &Rect2);

   ScreenToClient(hDlg, (LPPOINT)&Rect1.left);
   ScreenToClient(hDlg, (LPPOINT)&Rect1.right);

   ScreenToClient(hDlg, (LPPOINT)&Rect2.left);
   ScreenToClient(hDlg, (LPPOINT)&Rect2.right);

   SetWindowPos(hWnd1,
            NULL,
            Rect2.left,
            Rect2.top,
            0,
            0,
            SWP_NOZORDER | SWP_NOSIZE);

   SetWindowPos(hWnd2,
            NULL,
            Rect1.left,
            Rect1.top,
            0,
            0,
            SWP_NOZORDER | SWP_NOSIZE);

   return;

}
