/*************************************************************************
**
** 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 TCHAR szSeparators[] = TEXT(" \t\\/!:");

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


#if defined( OBSOLETE )
static HINSTANCE  s_hInst;

static TCHAR szMaxWidth[] =TEXT("WWWWWWWWWW");

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

#ifdef WIN32
static TCHAR szOLE2DLL[] = TEXT("ole2w32.dll");   // name of OLE 2.0 library
#else
static TCHAR szOLE2DLL[] = TEXT("ole2.dll");   // name of OLE 2.0 library
#endif

#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 TCHAR szVanillaDocIcon[] = TEXT("DefIcon");

static TCHAR szDocument[40] = TEXT("");


/*
 * GetIconOfFile(HINSTANCE hInst, LPSTR lpszPath, BOOL fUseFileAsLabel)
 *
 * Purpose:
 *  Returns a hMetaPict containing an icon and label (filename) for the
 *  specified filename.
 *
 * Parameters:
 *  hinst
 *  lpszPath        LPTSTR 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, LPTSTR lpszPath, BOOL fUseFileAsLabel)
{
  TCHAR    szIconFile[OLEUI_CCHPATHMAX];
  TCHAR    szLabel[OLEUI_CCHLABELMAX];
  LPTSTR    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 = GetClassFileA(lpszPath, &clsid);

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

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

     LPTSTR lpszTemp;

     lpszTemp = lpszPath;

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


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


     if (FALSE == GetAssociatedExecutable(lpszTemp, (LPTSTR)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:

    lstrcpy((LPTSTR)szIconFile, (LPTSTR)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;
     LPTSTR 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, sizeof(szLabel)/sizeof(TCHAR));
  }

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

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

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


  hMetaPict = OleUIMetafilePictFromIconAndLabel(hDefIcon,
                                                szLabel,
                                                (LPTSTR)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, LPTSTR lpszLabel, BOOL fUseTypeAsLabel)
{

  TCHAR    szLabel[OLEUI_CCHLABELMAX];
  TCHAR    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, OLEUI_CCHLABELMAX_SIZE);
    else
       *szLabel = TEXT('\0');
  }
  else   // Use AuxUserType2 (short name) as label
  {

      if (0 == OleStdGetAuxUserType(rclsid,
                                    AUXUSERTYPE_SHORTNAME,
                                    (LPTSTR)szLabel,
                                    OLEUI_CCHLABELMAX_SIZE,
                                    NULL))

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

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

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

  // Create the metafile
  hMetaPict = OleUIMetafilePictFromIconAndLabel(hDefIcon, szLabel,
                                                (LPTSTR)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        LPTSTR to the label string.
 *  pszSourceFile   LPTSTR 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, LPTSTR pszLabel
    , LPTSTR 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;
    TCHAR           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] = TEXT('\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, TEXT("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) || (TEXT('\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, TEXT("%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(LPTSTR lpszExtension, LPTSTR lpszExecutable)

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


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

   if (ERROR_SUCCESS != lRet)
      return FALSE;

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

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


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


   dw = OLEUI_CCHPATHMAX_SIZE;
   lRet = RegQueryValue(hKey, (LPTSTR)szKey, (LPTSTR)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 = (LPTSTR)szValue;

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

   lpszExe = lpszTemp;

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

   *lpszTemp = TEXT('\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, LPTSTR 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_SIZE, &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.
 *                    NOTE: 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.
 *
 */
LPTSTR FAR PASCAL PointerToNthField(LPTSTR lpszString, int nField, TCHAR chDelimiter)
{
   LPTSTR lpField = lpszString;
   int   cFieldFound = 1;

   if (1 ==nField)
      return lpszString;

   while (*lpField != TEXT('\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, LPTSTR pszEXE, UINT cchBytes, UINT FAR *lpIndex)
{

    LONG          dw;
    LONG          lRet;
    HKEY          hKey;
    LPMALLOC      lpIMalloc;
    HRESULT       hrErr;
    LPTSTR	  lpBuffer;
    LPTSTR	  lpIndexString;
    UINT          cBufferSize = 136;// room for 128 char path and icon's index
    TCHAR	  szKey[64];
    LPSTR	  pszClass;
    UINT	  cch=cchBytes / sizeof(TCHAR);  // number of characters


    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 = (LPTSTR)lpIMalloc->lpVtbl->Alloc(lpIMalloc, cBufferSize);

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


    if (CoIsOle1Class(rclsid))
    {

      LPOLESTR lpszProgID;

      // 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, &lpszProgID);

      //Open up the class key
#ifdef UNICODE
      lRet=RegOpenKey(HKEY_CLASSES_ROOT, lpszProgID, &hKey);
#else
      {
         char szTemp[255];

         wcstombs(szTemp, lpszProgID, 255);
      	lRet=RegOpenKey(HKEY_CLASSES_ROOT, szTemp, &hKey);
      }
#endif

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

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

      if (ERROR_SUCCESS != lRet)
      {

         RegCloseKey(hKey);
         lpIMalloc->lpVtbl->Free(lpIMalloc, lpszProgID);
         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, lpszProgID);
      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.
     */

    StringFromCLSIDA(rclsid, &pszClass);

    lstrcpy(szKey, TEXT("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, pszClass);
        lpIMalloc->lpVtbl->Release(lpIMalloc);
        return FALSE;
    }

    //Get the executable path and icon index.

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

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

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

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

         RegCloseKey(hKey);
         lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);
         lpIMalloc->lpVtbl->Free(lpIMalloc, pszClass);
         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, pszClass);
      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, TEXT(','));

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

    }
    else
    {
       LPTSTR lpTemp;
       static TCHAR  szTemp[16];

       lstrcpy((LPTSTR)szTemp, lpIndexString);

       // Put the icon index part into *pIconIndex
#ifdef UNICODE
       {
          char szTEMP1[16];

          wcstombs(szTEMP1, szTemp, 16);
          *lpIndex = atoi((const char *)szTEMP1);
       }
#else
       *lpIndex = atoi((const char *)szTemp);
#endif

       // Null-terminate the exe part.
#ifdef WIN32
       lpTemp = CharPrev(lpBuffer, lpIndexString);
#else
       lpTemp = AnsiPrev(lpBuffer, lpIndexString);
#endif
       *lpTemp = TEXT('\0');
    }

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

    // Free the memory we alloc'd and leave.
    lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);
    lpIMalloc->lpVtbl->Free(lpIMalloc, pszClass);
    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,
                                     LPTSTR      lpszString,
                                     UINT       cchString,
                                     int FAR *  lpDX)
{

  HDC          hDCScreen;
  static TCHAR  szTempBuff[OLEUI_CCHLABELMAX];
  int          cxString, cyString, cxMaxString;
  int          cxFirstLine, cyFirstLine, cxSecondLine;
  int          index;
  int          cch = cchString;
  TCHAR        chKeep;
  LPTSTR       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 = TEXT('\0');

  else
    LSTRCPYN(szTempBuff, lpszString, sizeof(szTempBuff)/sizeof(TCHAR));

  // 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
#ifdef WIN32
  // GetTextExtentPoint32 has fixed the off-by-one bug.
  GetTextExtentPoint32(hDCScreen, szTempBuff, cch, &size);
#else
  GetTextExtentPoint(hDCScreen, szTempBuff, cch, &size);
#endif

  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)
#ifdef UNICODE
     wcscspn(szTempBuff, szSeparators)
#else
     strcspn(szTempBuff, szSeparators)
#endif
     )
  {
     // 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)
     {

       TCHAR 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] = TEXT('\0');  // just for now

#ifdef WIN32
       GetTextExtentPoint32(
               hDCScreen, (LPTSTR)szTempBuff,lstrlen((LPTSTR)szTempBuff),&size);
#else
       GetTextExtentPoint(
               hDCScreen, (LPTSTR)szTempBuff,lstrlen((LPTSTR)szTempBuff),&size);
#endif

       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,
                      (LPTSTR)szTempBuff,
                      index + 1,
                      lpDX);

           lpszSecondLine = (LPTSTR)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((LPTSTR)szTempBuff);

  chKeep = szTempBuff[cch];
  szTempBuff[cch] = TEXT('\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] = TEXT('\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,
             (LPTSTR)szTempBuff,
             lstrlen((LPTSTR)szTempBuff),
             lpDX);

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

  GetTextExtentPoint(
          hDCScreen, (LPTSTR)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;

}