1178 lines
32 KiB
C
1178 lines
32 KiB
C
/*************************************************************************
|
||
**
|
||
** 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;
|
||
|
||
}
|
||
|