/*************************************************************************
**
** The following API's are now OBSOLETE because equivalent API's have been
** added to the OLE2.DLL library
**      GetIconOfFile       superceeded by OleGetIconOfFile
**      GetIconOfClass      superceeded by OleGetIconOfClass
**      OleUIMetafilePictFromIconAndLabel
**                          superceeded by OleMetafilePictFromIconAndLabel
*************************************************************************/

/*
 *  GETICON.C
 *
 *  Functions to create DVASPECT_ICON metafile from filename or classname.
 *
 *  GetIconOfFile
 *  GetIconOfClass
 *  OleUIMetafilePictFromIconAndLabel
 *  HIconAndSourceFromClass Extracts the first icon in a class's server path
 *                          and returns the path and icon index to caller.
 *  FIconFileFromClass      Retrieves the path to the exe/dll containing the
 *                           default icon, and the index of the icon.
 *  OleStdIconLabelTextOut  Draw icon label text (line break if necessary)
 *
 *    (c) Copyright Microsoft Corp. 1992-1993 All Rights Reserved
 */


/*******
 *
 * ICON (DVASPECT_ICON) METAFILE FORMAT:
 *
 * The metafile generated with OleUIMetafilePictFromIconAndLabel contains
 * the following records which are used by the functions in DRAWICON.C
 * to draw the icon with and without the label and to extract the icon,
 * label, and icon source/index.
 *
 *  SetWindowOrg
 *  SetWindowExt
 *  DrawIcon:
 *      Inserts records of DIBBITBLT or DIBSTRETCHBLT, once for the
 *      AND mask, one for the image bits.
 *  Escape with the comment "IconOnly"
 *      This indicates where to stop record enumeration to draw only
 *      the icon.
 *  SetTextColor
 *  SetTextAlign
 *  SetBkColor
 *  CreateFont
 *  SelectObject on the font.
 *  ExtTextOut
 *      One or more ExtTextOuts occur if the label is wrapped.  The
 *      text in these records is used to extract the label.
 *  SelectObject on the old font.
 *  DeleteObject on the font.
 *  Escape with a comment that contains the path to the icon source.
 *  Escape with a comment that is the ASCII of the icon index.
 *
 *******/

#define STRICT  1
#include "ole2ui.h"

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <commdlg.h>
#include <memory.h>
#include <cderr.h>
#include "common.h"
#include "utility.h"

static char szSeparators[] = " \t\\/!:";

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


#if defined( OBSOLETE )
static HINSTANCE  s_hInst;

static char szMaxWidth[] ="WWWWWWWWWW";

//Strings for metafile comments.
static OLECHAR szIconOnly[]= OLESTR("IconOnly");        //Where to stop to exclude label.


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

#define ICONINDEX              0

#define AUXUSERTYPE_SHORTNAME  USERCLASSTYPE_SHORT  // short name
#define HIMETRIC_PER_INCH   2540      // number HIMETRIC units per inch
#define PTS_PER_INCH          72      // number points (font size) per inch

#define MAP_PIX_TO_LOGHIM(x,ppli)   MulDiv(HIMETRIC_PER_INCH, (x), (ppli))
#define MAP_LOGHIM_TO_PIX(x,ppli)   MulDiv((ppli), (x), HIMETRIC_PER_INCH)

static char szVanillaDocIcon[] = "DefIcon";

static char szDocument[40] = "";


/*
 * GetIconOfFile(HINSTANCE hInst, LPSTR lpszPath, BOOL fUseFileAsLabel)
 *
 * Purpose:
 *  Returns a hMetaPict containing an icon and label (filename) for the
 *  specified filename.
 *
 * Parameters:
 *  hinst
 *  lpszPath        LPSTR path including filename to use
 *  fUseFileAsLabel BOOL TRUE if the icon's label is the filename, FALSE if
 *                  there should be no label.
 *
 * Return Value:
 *  HGLOBAL         hMetaPict containing the icon and label - if there's no
 *                  class in reg db for the file in lpszPath, then we use
 *                  Document.  If lpszPath is NULL, then we return NULL.
 */

STDAPI_(HGLOBAL) GetIconOfFile(HINSTANCE hInst, LPSTR lpszPath, BOOL fUseFileAsLabel)
{
  char     szIconFile[OLEUI_CCHPATHMAX];
  char     szLabel[OLEUI_CCHLABELMAX];
  LPSTR    lpszClsid = NULL;
  CLSID    clsid;
  HICON    hDefIcon = NULL;
  UINT     IconIndex = 0;
  HGLOBAL  hMetaPict;
  HRESULT  hResult;

  if (NULL == lpszPath)  // even if fUseFileAsLabel is FALSE, we still
   return NULL;             // need a valid filename to get the class.

  s_hInst = hInst;

  hResult = GetClassFile(lpszPath, &clsid);

  if (NOERROR == hResult)  // use the clsid we got to get to the icon
  {
     hDefIcon = HIconAndSourceFromClass(&clsid,
                               szIconFile,
                               &IconIndex);
  }

  if ( (NOERROR != hResult) || (NULL == hDefIcon) )
  {
    // Here, either GetClassFile failed or HIconAndSourceFromClass failed.

    LPSTR lpszTemp;

    lpszTemp = lpszPath;

    while ((*lpszTemp != '.') && (*lpszTemp != '\0'))
      lpszTemp++;


    if ('.' != *lpszTemp)
      goto UseVanillaDocument;


    if (FALSE == GetAssociatedExecutable(lpszTemp, szIconFile))
      goto UseVanillaDocument;

    hDefIcon = ExtractIcon(s_hInst, szIconFile, IconIndex);
  }

  if (hDefIcon <= (HICON)1) // ExtractIcon returns 1 if szExecutable is not exe,
  {                         // 0 if there are no icons.
UseVanillaDocument:

   OLESTRCPY(szIconFile, szOLE2DLL);
   IconIndex = ICONINDEX;
   hDefIcon = ExtractIcon(s_hInst, szIconFile, IconIndex);

  }

  // Now let's get the label we want to use.

  if (fUseFileAsLabel)   // strip off path, so we just have the filename.
  {
    int istrlen;
    LPSTR lpszBeginFile;

    istrlen = lstrlen(lpszPath);

    // set pointer to END of path, so we can walk backwards through it.
    lpszBeginFile = lpszPath + istrlen -1;

    while ( (lpszBeginFile >= lpszPath)
          && (!IS_FILENAME_DELIM(*lpszBeginFile)) )
     lpszBeginFile--;


    lpszBeginFile++;  // step back over the delimiter


    LSTRCPYN(szLabel, lpszBeginFile, OLEUI_CCHLABELMAX);
  }

  else   // use the short user type (AuxUserType2) for the label
  {

     if (0 == OleStdGetAuxUserType(&clsid, AUXUSERTYPE_SHORTNAME,
                           szLabel, OLEUI_CCHLABELMAX, NULL)) {

       if ('\0'==szDocument[0]) {
          LoadString(
             s_hInst,IDS_DEFICONLABEL,szDocument,sizeof(szDocument));
       }
       lstrcpy(szLabel, szDocument);
     }
  }


  hMetaPict = OleUIMetafilePictFromIconAndLabel(hDefIcon,
                                    szLabel,
                                    szIconFile,
                                    IconIndex);

  DestroyIcon(hDefIcon);

  return hMetaPict;

}


/*
 * GetIconOfClass(HINSTANCE hInst, REFCLSID rclsid, LPSTR lpszLabel, BOOL fUseTypeAsLabel)
 *
 * Purpose:
 *  Returns a hMetaPict containing an icon and label (human-readable form
 *  of class) for the specified clsid.
 *
 * Parameters:
 *  hinst
 *  rclsid          REFCLSID pointing to clsid to use.
 *  lpszLabel       label to use for icon.
 *  fUseTypeAsLabel Use the clsid's user type name as the icon's label.
 *
 * Return Value:
 *  HGLOBAL         hMetaPict containing the icon and label - if we
 *                  don't find the clsid in the reg db then we
 *                  return NULL.
 */

STDAPI_(HGLOBAL)    GetIconOfClass(HINSTANCE hInst, REFCLSID rclsid, LPSTR lpszLabel, BOOL fUseTypeAsLabel)
{

  char    szLabel[OLEUI_CCHLABELMAX];
  char    szIconFile[OLEUI_CCHPATHMAX];
  HICON   hDefIcon;
  UINT    IconIndex;
  HGLOBAL hMetaPict;

  s_hInst = hInst;

  if (!fUseTypeAsLabel)  // Use string passed in as label
  {
   if (NULL != lpszLabel)
      LSTRCPYN(szLabel, lpszLabel, sizeof(szLabel));
   else
      *szLabel = '\0';
  }
  else   // Use AuxUserType2 (short name) as label
  {

     if (0 == OleStdGetAuxUserType(rclsid,
                           AUXUSERTYPE_SHORTNAME,
                           szLabel,
                           OLEUI_CCHLABELMAX,
                           NULL))

      // If we can't get the AuxUserType2, then try the long name
      if (0 == OleStdGetUserTypeOfClass(rclsid, szLabel, OLEUI_CCHKEYMAX, NULL)) {
       if ('\0'==szDocument[0]) {
          LoadString(
             s_hInst,IDS_DEFICONLABEL,szDocument,sizeof(szDocument));
       }
       lstrcpy(szLabel, szDocument);  // last resort
      }
  }

  // Get the icon, icon index, and path to icon file
  hDefIcon = HIconAndSourceFromClass(rclsid,
              szIconFile,
              &IconIndex);

  if (NULL == hDefIcon)  // Use Vanilla Document
  {
   OLESTRCPY(szIconFile, szOLE2DLL);
   IconIndex = ICONINDEX;
   hDefIcon = ExtractIcon(s_hInst, szIconFile, IconIndex);
  }

  // Create the metafile
  hMetaPict = OleUIMetafilePictFromIconAndLabel(hDefIcon, szLabel,
                                    szIconFile, IconIndex);

  DestroyIcon(hDefIcon);

  return hMetaPict;

}


/*
 * OleUIMetafilePictFromIconAndLabel
 *
 * Purpose:
 *  Creates a METAFILEPICT structure that container a metafile in which
 *  the icon and label are drawn.  A comment record is inserted between
 *  the icon and the label code so our special draw function can stop
 *  playing before the label.
 *
 * Parameters:
 *  hIcon           HICON to draw into the metafile
 *  pszLabel        LPSTR to the label string.
 *  pszSourceFile   LPSTR containing the local pathname of the icon
 *                  as we either get from the user or from the reg DB.
 *  iIcon           UINT providing the index into pszSourceFile where
 *                  the icon came from.
 *
 * Return Value:
 *  HGLOBAL         Global memory handle containing a METAFILEPICT where
 *                  the metafile uses the MM_ANISOTROPIC mapping mode.  The
 *                  extents reflect both icon and label.
 */

STDAPI_(HGLOBAL) OleUIMetafilePictFromIconAndLabel(HICON hIcon, LPSTR pszLabel
   , LPSTR pszSourceFile, UINT iIcon)
   {
   HDC             hDC, hDCScreen;
   HMETAFILE       hMF;
   HGLOBAL         hMem;
   LPMETAFILEPICT  pMF;
   UINT            cxIcon, cyIcon;
   UINT            cxText, cyText;
   UINT            cx, cy;
   UINT            cchLabel = 0;
   HFONT           hFont, hFontT;
   int             cyFont;
   char            szIndex[10];
   RECT            TextRect;
   SIZE            size;
   POINT           point;
   UINT            fuAlign;

   if (NULL==hIcon)  // null label is valid but NOT a null icon
      return NULL;

   //Create a memory metafile
   hDC=(HDC)CreateMetaFile(NULL);

   if (NULL==hDC)
      return NULL;

   //Allocate the metafilepict
   hMem=GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, sizeof(METAFILEPICT));

   if (NULL==hMem)
      {
      hMF=CloseMetaFile(hDC);
      DeleteMetaFile(hMF);
      return NULL;
      }


   if (NULL!=pszLabel)
      {
      cchLabel=lstrlen(pszLabel);

      if (cchLabel >= OLEUI_CCHLABELMAX)
         pszLabel[cchLabel] = '\0';   // truncate string
      }

   //Need to use the screen DC for these operations
   hDCScreen=GetDC(NULL);
   cyFont=-(8*GetDeviceCaps(hDCScreen, LOGPIXELSY))/72;

   //cyFont was calculated to give us 8 point.
   hFont=CreateFont(cyFont, 5, 0, 0, FW_NORMAL, 0, 0, 0, ANSI_CHARSET
      , OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY
      , FF_SWISS, "MS Sans Serif");

   hFontT=SelectObject(hDCScreen, hFont);

   GetTextExtentPoint(hDCScreen,szMaxWidth,lstrlen(szMaxWidth),&size);
   SelectObject(hDCScreen, hFontT);

   cxText = size.cx;
   cyText = size.cy * 2;

   cxIcon = GetSystemMetrics(SM_CXICON);
   cyIcon = GetSystemMetrics(SM_CYICON);


   // If we have no label, then we want the metafile to be the width of
   // the icon (plus margin), not the width of the fattest string.
   if ( (NULL == pszLabel) || ('\0' == *pszLabel) )
      cx = cxIcon + cxIcon / 4;
   else
      cx = max(cxText, cxIcon);

   cy=cyIcon+cyText+4;

   //Set the metafile size to fit the icon and label
   SetWindowOrgEx(hDC, 0, 0, &point);
   SetWindowExtEx(hDC, cx, cy, &size);

   //Set up rectangle to pass to OleStdIconLabelTextOut
   SetRectEmpty(&TextRect);

   TextRect.right = cx;
   TextRect.bottom = cy;

   //Draw the icon and the text, centered with respect to each other.
   DrawIcon(hDC, (cx-cxIcon)/2, 0, hIcon);

   //String that indicates where to stop if we're only doing icons
   Escape(hDC, MFCOMMENT, lstrlen(szIconOnly)+1, szIconOnly, NULL);

   SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
   SetBkMode(hDC, TRANSPARENT);
   fuAlign = SetTextAlign(hDC, TA_LEFT | TA_TOP | TA_NOUPDATECP);

   OleStdIconLabelTextOut(hDC,
                     hFont,
                     0,
                     cy - cyText,
                     ETO_CLIPPED,
                     &TextRect,
                     pszLabel,
                     cchLabel,
                     NULL);

   //Write comments containing the icon source file and index.
   if (NULL!=pszSourceFile)
      {
      //+1 on string lengths insures the null terminator is embedded.
      Escape(hDC, MFCOMMENT, lstrlen(pszSourceFile)+1, pszSourceFile, NULL);

      cchLabel=wsprintf(szIndex, "%u", iIcon);
      Escape(hDC, MFCOMMENT, cchLabel+1, szIndex, NULL);
      }

   SetTextAlign(hDC, fuAlign);

   //All done with the metafile, now stuff it all into a METAFILEPICT.
   hMF=CloseMetaFile(hDC);

   if (NULL==hMF)
      {
      GlobalFree(hMem);
      ReleaseDC(NULL, hDCScreen);
      return NULL;
      }

   //Fill out the structure
   pMF=(LPMETAFILEPICT)GlobalLock(hMem);

   //Transform to HIMETRICS
   cx=XformWidthInPixelsToHimetric(hDCScreen, cx);
   cy=XformHeightInPixelsToHimetric(hDCScreen, cy);
   ReleaseDC(NULL, hDCScreen);

   pMF->mm=MM_ANISOTROPIC;
   pMF->xExt=cx;
   pMF->yExt=cy;
   pMF->hMF=hMF;

   GlobalUnlock(hMem);

   DeleteObject(hFont);

   return hMem;
   }

#endif  // OBSOLETE


/*
 * GetAssociatedExecutable
 *
 * Purpose:  Finds the executable associated with the provided extension
 *
 * Parameters:
 *   lpszExtension   LPSTR points to the extension we're trying to find
 *                   an exe for. Does **NO** validation.
 *
 *   lpszExecutable  LPSTR points to where the exe name will be returned.
 *                   No validation here either - pass in 128 char buffer.
 *
 * Return:
 *   BOOL            TRUE if we found an exe, FALSE if we didn't.
 *
 */

BOOL FAR PASCAL GetAssociatedExecutable(LPSTR lpszExtension, LPSTR lpszExecutable)

{
   HKEY    hKey;
   LONG    dw;
   LRESULT lRet;
   char    szValue[OLEUI_CCHKEYMAX];
   char    szKey[OLEUI_CCHKEYMAX];
   LPSTR   lpszTemp, lpszExe;


   lRet = RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey);

   if (ERROR_SUCCESS != lRet)
     return FALSE;

   dw = OLEUI_CCHPATHMAX;
   lRet = RegQueryValue(hKey, lpszExtension, szValue, &dw);  //ProgId

   if (ERROR_SUCCESS != lRet)
   {
     RegCloseKey(hKey);
     return FALSE;
   }


   // szValue now has ProgID
   lstrcpy(szKey, szValue);
   lstrcat(szKey, "\\Shell\\Open\\Command");


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

   if (ERROR_SUCCESS != lRet)
   {
     RegCloseKey(hKey);
     return FALSE;
   }

   // szValue now has an executable name in it.  Let's null-terminate
   // at the first post-executable space (so we don't have cmd line
   // args.

   lpszTemp = szValue;

   while (('\0' != *lpszTemp) && (isspace(*lpszTemp)))
     lpszTemp++;     // Strip off leading spaces

   lpszExe = lpszTemp;

   while (('\0' != *lpszTemp) && (!isspace(*lpszTemp)))
     lpszTemp++;     // Step through exe name

   *lpszTemp = '\0';  // null terminate at first space (or at end).


   lstrcpy(lpszExecutable, lpszExe);

   return TRUE;

}


/*
 * HIconAndSourceFromClass
 *
 * Purpose:
 *  Given an object class name, finds an associated executable in the
 *  registration database and extracts the first icon from that
 *  executable.  If none is available or the class has no associated
 *  executable, this function returns NULL.
 *
 * Parameters:
 *  rclsid          pointer to clsid to look up.
 *  pszSource       LPSTR in which to place the source of the icon.
 *                  This is assumed to be OLEUI_CCHPATHMAX
 *  puIcon          UINT FAR * in which to store the index of the
 *                  icon in pszSource.
 *
 * Return Value:
 *  HICON           Handle to the extracted icon if there is a module
 *                  associated to pszClass.  NULL on failure to either
 *                  find the executable or extract and icon.
 */

HICON FAR PASCAL HIconAndSourceFromClass(REFCLSID rclsid, LPSTR pszSource, UINT FAR *puIcon)
   {
   HICON           hIcon;
   UINT            IconIndex;

   if (NULL==rclsid || NULL==pszSource || IsEqualCLSID(rclsid,&CLSID_NULL))
      return NULL;

   if (!FIconFileFromClass(rclsid, pszSource, OLEUI_CCHPATHMAX, &IconIndex))
      return NULL;

   hIcon=ExtractIcon(ghInst, pszSource, IconIndex);

   if ((HICON)32 > hIcon)
      hIcon=NULL;
   else
      *puIcon= IconIndex;

   return hIcon;
   }


/*
 * PointerToNthField
 *
 * Purpose:
 *  Returns a pointer to the beginning of the nth field.
 *  Assumes null-terminated string.
 *
 * Parameters:
 *  lpszString        string to parse
 *  nField            field to return starting index of.
 *  chDelimiter       char that delimits fields
 *
 * Return Value:
 *  LPSTR             pointer to beginning of nField field.
 *                    NOTsE: If the null terminator is found
 *                          Before we find the Nth field, then
 *                          we return a pointer to the null terminator -
 *                          calling app should be sure to check for
 *                          this case.
 *
 */
LPSTR FAR PASCAL PointerToNthField(LPSTR lpszString, int nField, char chDelimiter)
{
   LPSTR lpField = lpszString;
   int   cFieldFound = 1;

   if (1 ==nField)
     return lpszString;

   while (*lpField != '\0')
   {

     if (*lpField++ == chDelimiter)
     {

       cFieldFound++;

       if (nField == cFieldFound)
         return lpField;
     }
   }

   return lpField;

}


/*
 * FIconFileFromClass
 *
 * Purpose:
 *  Looks up the path to executable that contains the class default icon.
 *
 * Parameters:
 *  rclsid          pointer to CLSID to look up.
 *  pszEXE          LPSTR at which to store the server name
 *  cch             UINT size of pszEXE
 *  lpIndex         LPUINT to index of icon within executable
 *
 * Return Value:
 *  BOOL            TRUE if one or more characters were loaded into pszEXE.
 *                  FALSE otherwise.
 */

BOOL FAR PASCAL FIconFileFromClass(REFCLSID rclsid, LPSTR pszEXE, UINT cch, UINT FAR *lpIndex)
{

   LONG          dw;
   LONG          lRet;
   HKEY          hKey;
   LPMALLOC      lpIMalloc;
   HRESULT       hrErr;
   LPSTR         lpBuffer;
   LPSTR         lpIndexString;
   UINT          cBufferSize = 136;// room for 128 char path and icon's index
   char          szKey[64];
   char          pszClass[256];
   LPOLESTR      pszUniClass;


   if (NULL==rclsid || NULL==pszEXE || 0==cch || IsEqualCLSID(rclsid,&CLSID_NULL))
      return FALSE;

   //Here, we use CoGetMalloc and alloc a buffer (maxpathlen + 8) to
   //pass to RegQueryValue.  Then, we copy the exe to pszEXE and the
   //index to *lpIndex.

   hrErr = CoGetMalloc(MEMCTX_TASK, &lpIMalloc);

   if (NOERROR != hrErr)
     return FALSE;

   lpBuffer = (LPSTR)lpIMalloc->lpVtbl->Alloc(lpIMalloc, cBufferSize);

   if (NULL == lpBuffer)
   {
     lpIMalloc->lpVtbl->Release(lpIMalloc);
     return FALSE;
   }


   if (CoIsOle1Class(rclsid))
   {

     LPOLESTR lpszUniProgID;
     char lpszProgID[256];

     // we've got an ole 1.0 class on our hands, so we look at
     // progID\protocol\stdfileedting\server to get the
     // name of the executable.

     ProgIDFromCLSID(rclsid, &lpszUniProgID);
     W2A (lpszUniProgID, lpszProgID, 256);

     //Open up the class key
     lRet=RegOpenKey(HKEY_CLASSES_ROOT, lpszProgID, &hKey);

     if (ERROR_SUCCESS != lRet)
     {
       lpIMalloc->lpVtbl->Free(lpIMalloc, lpszUniProgID);
       lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);
       lpIMalloc->lpVtbl->Release(lpIMalloc);
       return FALSE;
     }

     dw=(LONG)cBufferSize;
     lRet = RegQueryValue(hKey, "Protocol\\StdFileEditing\\Server", lpBuffer, &dw);

     if (ERROR_SUCCESS != lRet)
     {

       RegCloseKey(hKey);
       lpIMalloc->lpVtbl->Free(lpIMalloc, lpszUniProgID);
       lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);
       lpIMalloc->lpVtbl->Release(lpIMalloc);
       return FALSE;
     }


     // Use server and 0 as the icon index
     LSTRCPYN(pszEXE, lpBuffer, cch);

     *lpIndex = 0;

     RegCloseKey(hKey);
     lpIMalloc->lpVtbl->Free(lpIMalloc, lpszUniProgID);
     lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);
     lpIMalloc->lpVtbl->Release(lpIMalloc);
     return TRUE;

   }



   /*
    * We have to go walking in the registration database under the
    * classname, so we first open the classname key and then check
    * under "\\DefaultIcon" to get the file that contains the icon.
    */


   StringFromCLSID(rclsid, &pszUniClass);
   W2A (pszUniClass, pszClass, 256);

   lstrcpy(szKey, "CLSID\\");
   lstrcat(szKey, pszClass);

   //Open up the class key
   lRet=RegOpenKey(HKEY_CLASSES_ROOT, szKey, &hKey);

   if (ERROR_SUCCESS != lRet)
   {
      lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);
      lpIMalloc->lpVtbl->Free(lpIMalloc, pszUniClass);
      lpIMalloc->lpVtbl->Release(lpIMalloc);
      return FALSE;
   }

   //Get the executable path and icon index.

   dw=(LONG)cBufferSize;
   lRet=RegQueryValue(hKey, "DefaultIcon", lpBuffer, &dw);

   if (ERROR_SUCCESS != lRet)
   {
     // no DefaultIcon  key...try LocalServer

     dw=(LONG)cBufferSize;
#ifdef WIN32
     lRet=RegQueryValue(hKey, "LocalServer32", lpBuffer, &dw);
#else
     lRet=RegQueryValue(hKey, "LocalServer", lpBuffer, &dw);
#endif

     if (ERROR_SUCCESS != lRet)
     {
       // no LocalServer entry either...they're outta luck.

       RegCloseKey(hKey);
       lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);
       lpIMalloc->lpVtbl->Free(lpIMalloc, pszUniClass);
       lpIMalloc->lpVtbl->Release(lpIMalloc);
       return FALSE;
     }


     // Use server from LocalServer or Server and 0 as the icon index
     LSTRCPYN(pszEXE, lpBuffer, cch);

     *lpIndex = 0;

     RegCloseKey(hKey);
     lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);
     lpIMalloc->lpVtbl->Free(lpIMalloc, pszUniClass);
     lpIMalloc->lpVtbl->Release(lpIMalloc);
     return TRUE;
   }

   RegCloseKey(hKey);

   // lpBuffer contains a string that looks like "<pathtoexe>,<iconindex>",
   // so we need to separate the path and the icon index.

   lpIndexString = PointerToNthField(lpBuffer, 2, ',');

   if ('\0' == *lpIndexString)  // no icon index specified - use 0 as default.
   {
      *lpIndex = 0;

   }
   else
   {
      LPSTR lpTemp;
      static char  szTemp[16];

      lstrcpy(szTemp, lpIndexString);

      // Put the icon index part into *pIconIndex
      *lpIndex = atoi((const char *)szTemp);

      // Null-terminate the exe part.
      lpTemp = AnsiPrev(lpBuffer, lpIndexString);
      *lpTemp = '\0';
   }

   if (!LSTRCPYN(pszEXE, lpBuffer, cch))
   {
      lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);
      lpIMalloc->lpVtbl->Free(lpIMalloc, pszUniClass);
      lpIMalloc->lpVtbl->Release(lpIMalloc);
      return FALSE;
   }

   // Free the memory we alloc'd and leave.
   lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);
   lpIMalloc->lpVtbl->Free(lpIMalloc, pszUniClass);
   lpIMalloc->lpVtbl->Release(lpIMalloc);
   return TRUE;
}



/*
 * OleStdIconLabelTextOut
 *
 * Purpose:
 *  Replacement for DrawText to be used in the "Display as Icon" metafile.
 *  Uses ExtTextOut to output a string center on (at most) two lines.
 *  Uses a very simple word wrap algorithm to split the lines.
 *
 * Parameters:  (same as for ExtTextOut, except for hFont)
 *  hDC           device context to draw into; if this is NULL, then we don't
 *                ETO the text, we just return the index of the beginning
 *                of the second line
 *  hFont         font to use
 *  nXStart       x-coordinate of starting position
 *  nYStart       y-coordinate of starting position
 *  fuOptions     rectangle type
 *  lpRect        rect far * containing rectangle to draw text in.
 *  lpszString    string to draw
 *  cchString     length of string (truncated if over OLEUI_CCHLABELMAX)
 *  lpDX          spacing between character cells
 *
 * Return Value:
 *  UINT          Index of beginning of last line (0 if there's only one
 *                line of text).
 *
 */

STDAPI_(UINT) OleStdIconLabelTextOut(HDC        hDC,
                            HFONT      hFont,
                            int        nXStart,
                            int        nYStart,
                            UINT       fuOptions,
                            RECT FAR * lpRect,
                            LPOLESTR   lpszString,
                            UINT       cchString,
                            int FAR *  lpDX)
{

  HDC          hDCScreen;
  static char  szTempBuff[OLEUI_CCHLABELMAX];
  int          cxString, cyString, cxMaxString;
  int          cxFirstLine, cyFirstLine, cxSecondLine;
  int          index;
  int          cch = cchString;
  char         chKeep;
  LPSTR        lpszSecondLine;
  HFONT        hFontT;
  BOOL         fPrintText = TRUE;
  UINT         iLastLineStart = 0;
  SIZE         size;

  // Initialization stuff...

  if (NULL == hDC)  // If we got NULL as the hDC, then we don't actually call ETO
   fPrintText = FALSE;


  // Make a copy of the string (NULL or non-NULL) that we're using
  if (NULL == lpszString)
   *szTempBuff = '\0';

  else
  {
     W2A (lpszString, szTempBuff, OLEUI_CCHLABELMAX);
  }

  // set maximum width
  cxMaxString = lpRect->right - lpRect->left;

  // get screen DC to do text size calculations
  hDCScreen = GetDC(NULL);

  hFontT=SelectObject(hDCScreen, hFont);

  // get the extent of our label
  GetTextExtentPoint(hDCScreen, szTempBuff, cch, &size);

  cxString = size.cx;
  cyString = size.cy;

  // Select in the font we want to use
  if (fPrintText)
    SelectObject(hDC, hFont);

  // String is smaller than max string - just center, ETO, and return.
  if (cxString <= cxMaxString)
  {

   if (fPrintText)
      ExtTextOut(hDC,
              nXStart + (lpRect->right - cxString) / 2,
              nYStart,
              fuOptions,
              lpRect,
              szTempBuff,
              cch,
              NULL);

   iLastLineStart = 0;  // only 1 line of text
   goto CleanupAndLeave;
  }

  // String is too long...we've got to word-wrap it.


  // Are there any spaces, slashes, tabs, or bangs in string?

  if (lstrlen(szTempBuff) != (int)strcspn(szTempBuff, szSeparators))
  {
    // Yep, we've got spaces, so we'll try to find the largest
    // space-terminated string that will fit on the first line.

    index = cch;


    while (index >= 0)
    {

      char cchKeep;

      // scan the string backwards for spaces, slashes, tabs, or bangs

      while (!IS_SEPARATOR(szTempBuff[index]) )
       index--;


      if (index <= 0)
       break;

      cchKeep = szTempBuff[index];  // remember what char was there

      szTempBuff[index] = '\0';  // just for now

      GetTextExtentPoint(
            hDCScreen, szTempBuff,lstrlen(szTempBuff),&size);

      cxFirstLine = size.cx;
      cyFirstLine = size.cy;

      szTempBuff[index] = cchKeep;   // put the right char back

      if (cxFirstLine <= cxMaxString)
      {

         iLastLineStart = index + 1;

         if (!fPrintText)
          goto CleanupAndLeave;

         ExtTextOut(hDC,
                 nXStart +  (lpRect->right - cxFirstLine) / 2,
                 nYStart,
                 fuOptions,
                 lpRect,
                 szTempBuff,
                 index + 1,
                 lpDX);

         lpszSecondLine = szTempBuff;

         lpszSecondLine += index + 1;

         GetTextExtentPoint(hDCScreen,
                           lpszSecondLine,
                           lstrlen(lpszSecondLine),
                           &size);

         // If the second line is wider than the rectangle, we
         // just want to clip the text.
         cxSecondLine = min(size.cx, cxMaxString);

         ExtTextOut(hDC,
                 nXStart + (lpRect->right - cxSecondLine) / 2,
                 nYStart + cyFirstLine,
                 fuOptions,
                 lpRect,
                 lpszSecondLine,
                 lstrlen(lpszSecondLine),
                 lpDX);

         goto CleanupAndLeave;

      }  // end if

      index--;

    }  // end while

  }  // end if

  // Here, there are either no spaces in the string (strchr(szTempBuff, ' ')
  // returned NULL), or there spaces in the string, but they are
  // positioned so that the first space terminated string is still
  // longer than one line. So, we walk backwards from the end of the
  // string until we find the largest string that will fit on the first
  // line , and then we just clip the second line.

  cch = lstrlen(szTempBuff);

  chKeep = szTempBuff[cch];
  szTempBuff[cch] = '\0';

  GetTextExtentPoint(hDCScreen, szTempBuff, lstrlen(szTempBuff),&size);

  cxFirstLine = size.cx;
  cyFirstLine = size.cy;

  while (cxFirstLine > cxMaxString)
  {
    // We allow 40 characters in the label, but the metafile is
    // only as wide as 10 W's (for aesthetics - 20 W's wide looked
    // dumb.  This means that if we split a long string in half (in
    // terms of characters), then we could still be wider than the
    // metafile.  So, if this is the case, we just step backwards
    // from the halfway point until we get something that will fit.
    // Since we just let ETO clip the second line

    szTempBuff[cch--] = chKeep;
    if (0 == cch)
      goto CleanupAndLeave;

    chKeep = szTempBuff[cch];
    szTempBuff[cch] = '\0';

    GetTextExtentPoint(
          hDCScreen, szTempBuff, lstrlen(szTempBuff), &size);
    cxFirstLine = size.cx;
  }

  iLastLineStart = cch;

  if (!fPrintText)
   goto CleanupAndLeave;

  ExtTextOut(hDC,
          nXStart + (lpRect->right - cxFirstLine) / 2,
          nYStart,
          fuOptions,
          lpRect,
          szTempBuff,
          lstrlen(szTempBuff),
          lpDX);

  szTempBuff[cch] = chKeep;
  lpszSecondLine = szTempBuff;
  lpszSecondLine += cch;

  GetTextExtentPoint(
        hDCScreen, lpszSecondLine, lstrlen(lpszSecondLine), &size);

  // If the second line is wider than the rectangle, we
  // just want to clip the text.
  cxSecondLine = min(size.cx, cxMaxString);

  ExtTextOut(hDC,
          nXStart + (lpRect->right - cxSecondLine) / 2,
          nYStart + cyFirstLine,
          fuOptions,
          lpRect,
          lpszSecondLine,
          lstrlen(lpszSecondLine),
          lpDX);

CleanupAndLeave:
  SelectObject(hDCScreen, hFontT);
  ReleaseDC(NULL, hDCScreen);
  return iLastLineStart;

}
