windows-nt/Source/XPSP1/NT/com/ole32/ole232/stdimpl/icon.cpp
2020-09-26 16:20:57 +08:00

2388 lines
66 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1996.
//
// File: icon.cpp
//
// Contents: Functions to create DVASPECT_ICON metafile from a filename
// or class ID
//
// Classes:
//
// Functions:
// OleGetIconOfFile
// OleGetIconOfClass
// OleMetafilePictFromIconAndLabel
//
// 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.
// IconLabelTextOut
// XformWidthInPixelsToHimetric
// Converts an int width into HiMetric units
// XformWidthInHimetricToPixels
// Converts an int width from HiMetric units
// XformHeightInPixelsToHimetric
// Converts an int height into HiMetric units
// XformHeightInHimetricToPixels
// Converts an int height from HiMetric units
//
// History: dd-mmm-yy Author Comment
// 24-Nov-93 alexgo 32bit port
// 15-Dec-93 alexgo fixed some bad UNICODE string handling
// 11-Jan-94 alexgo added VDATEHEAP macros to every function
// 25-Jan-94 alexgo first pass at converting to Cairo-style
// memory allocations.
// 26-Apr-94 AlexT Add tracing, fix bugs, etc
// 27-Dec-94 alexgo fixed multithreading problems, added
// support for quoted icon names
//
// Notes:
//
//--------------------------------------------------------------------------
#include <le2int.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <commdlg.h>
#include <memory.h>
#include <cderr.h>
#include <resource.h>
#include "icon.h"
#define OLEUI_CCHKEYMAX 256
#define OLEUI_CCHPATHMAX 256
#define OLEUI_CCHLABELMAX 42
#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 OLECHAR const gszDefIconLabelKey[] =
OLESTR( "Software\\Microsoft\\OLE2\\DefaultIconLabel");
#define IS_SEPARATOR(c) ( (c) == OLESTR(' ') || (c) == OLESTR('\\') || (c) == OLESTR('/') || (c) == OLESTR('\t') || (c) == OLESTR('!') || (c) == OLESTR(':') )
//REVIEW: what about the \\ case for UNC filenames, could it be considered a delimter also?
#define IS_FILENAME_DELIM(c) ( (c) == OLESTR('\\') || (c) == OLESTR('/') || (c) == OLESTR(':') )
#ifdef WIN32
#define LSTRCPYN(lpdst, lpsrc, cch) \
(\
lpdst[cch-1] = OLESTR('\0'), \
lstrcpynW(lpdst, lpsrc, cch-1)\
)
#else
#define LSTRCPYN(lpdst, lpsrc, cch) \
(\
lpdst[cch-1] = OLESTR('\0'), \
lstrncpy(lpdst, lpsrc, cch-1)\
)
#endif
void IconLabelTextOut(HDC hDC, HFONT hFont, int nXStart, int nYStart,
UINT fuOptions, RECT FAR * lpRect, LPCSTR lpszString,
UINT cchString);
/*******
*
* ICON METAFILE FORMAT:
*
* The metafile generated with OleMetafilePictFromIconAndLabel 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
* 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 (ANSI).
* Escape with a comment that is the string of the icon index (ANSI).
*
* Additional optional fields (new for 32-bit OLE, and only present if icon
* source or label was not translatable):
*
* Escape with a comment that contains the string
* "OLE: Icon label next (Unicode)" (ANSI string)
* Escape with a comment that contains the Unicode label
*
* Escape with a comment that contains the string
* "OLE: Icon source next (Unicode)" (ANSI string)
* Escape with a comment that contains the path to the icon source (UNICODE)
*
*******/
//+-------------------------------------------------------------------------
//
// Function: OleGetIconOfFile (public)
//
// Synopsis: Returns a hMetaPict containing an icon and label (filename)
// for the specified filename
//
// Effects:
//
// Arguments: [lpszPath] -- LPOLESTR path including filename to use
// [fUseAsLabel] -- if TRUE, use the filename as the icon's
// label; no label if FALSE
//
// Requires: lpszPath != NULL
//
// Returns: HGLOBAL to the hMetaPict
//
// Signals:
//
// Modifies:
//
// Algorithm: tries to get the icon from the class ID or from the
// exe associated with the file extension.
//
// History: dd-mmm-yy Author Comment
// 27-Nov-93 alexgo first 32bit port (minor cleanup)
// 15-Dec-93 alexgo changed lstrlen to _xstrlen
// 27-Dec-93 erikgav chicago port
// 28-Dec-94 alexgo fixed multithreading problems
//
// Notes:
//
//--------------------------------------------------------------------------
STDAPI_(HGLOBAL) OleGetIconOfFile(LPOLESTR lpszPath, BOOL fUseFileAsLabel)
{
OLETRACEIN((API_OleGetIconOfFile, PARAMFMT("lpszPath= %ws, fUseFileAsLabel= %B"),
lpszPath, fUseFileAsLabel));
VDATEHEAP();
HGLOBAL hMetaPict = NULL;
BOOL fUseGenericDocIcon = FALSE;
BOOL bRet;
OLECHAR szIconFile[OLEUI_CCHPATHMAX];
OLECHAR szLabel[OLEUI_CCHLABELMAX];
OLECHAR szDocument[OLEUI_CCHLABELMAX];
CLSID clsid;
HICON hDefIcon = NULL;
UINT IconIndex = 0;
UINT cchPath;
BOOL fGotLabel = FALSE;
HRESULT hResult = E_FAIL;
UINT uFlags;
LEDebugOut((DEB_TRACE, "%p _IN OleGetIconOfFile (%p, %d)\n",
NULL, lpszPath, fUseFileAsLabel));
*szIconFile = OLESTR('\0');
*szDocument = OLESTR('\0');
if (NULL == lpszPath)
{
// The spec allows a NULL lpszPath...
hMetaPict = NULL;
goto ErrRtn;
}
SHFILEINFO shfi;
uFlags = (SHGFI_ICON | SHGFI_LARGEICON | SHGFI_DISPLAYNAME |
SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES);
_xmemset(&shfi, 0, sizeof(shfi));
if (fUseFileAsLabel)
uFlags |= SHGFI_LINKOVERLAY;
if (OleSHGetFileInfo( lpszPath, FILE_ATTRIBUTE_NORMAL, &shfi, sizeof(shfi), uFlags))
{
if (shfi.iIcon == 0)
{
// Destroy the returned icon
DestroyIcon(shfi.hIcon);
// REVIEW: if non-NULL path str, do we want parameter validation?
hResult = GetClassFile(lpszPath, &clsid);
// use the clsid we got to get to the icon
if( NOERROR == hResult )
{
hDefIcon = HIconAndSourceFromClass(clsid, szIconFile, &IconIndex);
}
}
else
{
hDefIcon = shfi.hIcon;
hResult = NOERROR;
OLECHAR szUnicodeLabel[OLEUI_CCHLABELMAX];
#ifdef _CHICAGO_
LPTSTR lpszDisplayName;
if (fUseFileAsLabel)
lpszDisplayName = shfi.szDisplayName;
else
lpszDisplayName = shfi.szTypeName;
if(MultiByteToWideChar(AreFileApisANSI() ? CP_ACP : CP_OEMCP, 0, lpszDisplayName,
-1, szUnicodeLabel, OLEUI_CCHLABELMAX) )
{
LSTRCPYN(szLabel, szUnicodeLabel,
sizeof(szLabel)/sizeof(OLECHAR) );
}
#else
if (fUseFileAsLabel)
LSTRCPYN(szLabel, shfi.szDisplayName, sizeof(szLabel)/sizeof(OLECHAR));
else
LSTRCPYN(szLabel, shfi.szTypeName, sizeof(szLabel)/sizeof(OLECHAR));
#endif
fGotLabel = TRUE;
// need to fill out szIconFile, which is the path to the file in which the icon
// was extracted. Unfortunately, the shell can't return this value to us, so we
// must get the file that OLE would have used in the fallback case. This could
// be inconsistant with the shell if the application has installed a custom icon
// handler.
hResult = GetClassFile(lpszPath, &clsid);
if( NOERROR == hResult )
{
FIconFileFromClass(clsid, szIconFile, OLEUI_CCHPATHMAX, &IconIndex);
}
}
}
cchPath = _xstrlen(lpszPath);
if ((NOERROR != hResult) || (NULL == hDefIcon))
{
WORD index = 0;
// we need to copy into a large buffer because the second
// parameter of ExtractAssociatedIcon (the path name) is an
// in/out
_xstrcpy(szIconFile, lpszPath);
hDefIcon = OleExtractAssociatedIcon(g_hmodOLE2, szIconFile, &index);
IconIndex = index;
}
if (fUseGenericDocIcon || hDefIcon <= (HICON)1)
{
DWORD dwLen;
dwLen = GetModuleFileName(g_hmodOLE2,
szIconFile,
sizeof(szIconFile) / sizeof(OLECHAR));
if (0 == dwLen)
{
LEDebugOut((DEB_WARN,
"OleGetIconOfFile: GetModuleFileName failed - %ld",
GetLastError()));
goto ErrRtn;
}
IconIndex = ICONINDEX;
hDefIcon = LoadIcon(g_hmodOLE2, MAKEINTRESOURCE(DEFICON));
}
// Now let's get the label we want to use.
if (fGotLabel)
{
// Do nothing
}
else if (fUseFileAsLabel)
{
// This assumes the path uses only '\', '/', and '.' as separators
// strip off path, so we just have the filename.
LPOLESTR lpszBeginFile;
// set pointer to END of path, so we can walk backwards
// through it.
lpszBeginFile = lpszPath + cchPath - 1;
while ((lpszBeginFile >= lpszPath) &&
(!IS_FILENAME_DELIM(*lpszBeginFile)))
{
#ifdef WIN32
lpszBeginFile--;
#else
lpszBeginFile = CharPrev(lpszPath, lpszBeginFile);
#endif
}
lpszBeginFile++; // step back over the delimiter
// LSTRCPYN takes count of characters!
LSTRCPYN(szLabel, lpszBeginFile, sizeof(szLabel) / sizeof(OLECHAR));
}
// use the short user type (AuxUserType2) for the label
else if (0 == OleStdGetAuxUserType(clsid, AUXUSERTYPE_SHORTNAME,
szLabel, OLEUI_CCHLABELMAX, NULL))
{
if (OLESTR('\0')==szDocument[0]) // review, this is always true
{
LONG lRet;
LONG lcb;
lcb = sizeof (szDocument);
lRet = RegQueryValue(HKEY_CLASSES_ROOT, gszDefIconLabelKey,
szDocument, &lcb);
#if DBG==1
if (ERROR_SUCCESS != lRet)
{
LEDebugOut((DEB_WARN,
"RegQueryValue for default icon label failed - %d\n",
GetLastError()));
}
#endif
// NULL out last byte of string so don't rely on Reg behavior if buffer isn't big enough
szDocument[OLEUI_CCHLABELMAX -1] = OLESTR('\0');
}
_xstrcpy(szLabel, szDocument);
}
hMetaPict = OleMetafilePictFromIconAndLabel(hDefIcon, szLabel,
szIconFile, IconIndex);
bRet = DestroyIcon(hDefIcon);
Win4Assert(bRet && "DestroyIcon failed");
ErrRtn:
LEDebugOut((DEB_TRACE, "%p OUT OleGetIconOfFile( %lx )\n",
hMetaPict ));
OLETRACEOUTEX((API_OleGetIconOfFile, RETURNFMT("%h"), hMetaPict));
return hMetaPict;
}
//+-------------------------------------------------------------------------
//
// Function: GetAssociatedExectutable
//
// Synopsis: Finds the executables associated with the provided extension
//
// Effects:
//
// Arguments: [lpszExtension] -- pointer to the extension
// [lpszExecutable] -- where to put the executable name
// (assumes OLEUIPATHMAX OLECHAR buffer
// from calling function)
//
// Requires: lpszExecutable must be large enough to hold the path
//
// Returns: TRUE if exe found, FALSE otherwise
//
// Signals:
//
// Modifies:
//
// Algorithm: Queries reg database
//
// History: dd-mmm-yy Author Comment
// 27-Nov-93 alexgo 32bit port
// 15-Dec-93 alexgo fixed bug calculating size of strings
// 26-Apr-94 AlexT Tracing, bug fixes
//
// Notes:
//
//--------------------------------------------------------------------------
BOOL FAR PASCAL GetAssociatedExecutable(LPOLESTR lpszExtension,
LPOLESTR lpszExecutable)
{
VDATEHEAP();
BOOL bRet;
HKEY hKey;
LONG dw;
LRESULT lRet;
OLECHAR szValue[OLEUI_CCHKEYMAX];
OLECHAR szKey[OLEUI_CCHKEYMAX];
LPOLESTR lpszTemp, lpszExe;
LEDebugOut((DEB_ITRACE, "%p _IN GetAssociatedExecutable (%p, %p)\n",
NULL, lpszExtension, lpszExecutable));
// REVIEW: actually returns a LONG, which is indeed an LRESULT, not
// sure why the distinction here
lRet = RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey);
if (ERROR_SUCCESS != lRet)
{
bRet = FALSE;
goto ErrRtn;
}
dw = sizeof(szValue);
lRet = RegQueryValue(hKey, lpszExtension, szValue, &dw);
if (ERROR_SUCCESS != lRet)
{
RegCloseKey(hKey);
bRet = FALSE;
goto ErrRtn;
}
// szValue now has ProgID
_xstrcpy(szKey, szValue);
_xstrcat(szKey, OLESTR("\\Shell\\Open\\Command"));
// RegQueryValue wants *bytes*, not characters
dw = sizeof(szValue);
lRet = RegQueryValue(hKey, szKey, szValue, &dw);
RegCloseKey(hKey);
if (ERROR_SUCCESS != lRet)
{
bRet = FALSE;
goto ErrRtn;
}
// 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;
PUSHORT pCharTypes;
pCharTypes = (PUSHORT)_alloca (sizeof (USHORT) * (lstrlenW(lpszTemp) + 1));
if (pCharTypes == NULL)
{
goto ErrRtn;
}
GetStringTypeW (CT_CTYPE1, lpszTemp, -1, pCharTypes);
while ((OLESTR('\0') != *lpszTemp) && (pCharTypes[lpszTemp - szValue] & C1_SPACE))
{
lpszTemp++; // Strip off leading spaces
}
lpszExe = lpszTemp;
while ((OLESTR('\0') != *lpszTemp) && ((pCharTypes[lpszTemp - szValue] & C1_SPACE) == 0))
{
lpszTemp++; // Set through exe name
}
// null terminate at first space (or at end).
*lpszTemp = OLESTR('\0');
Win4Assert(_xstrlen(lpszExe) < OLEUI_CCHPATHMAX &&
"GetAssociatedFile too long");
_xstrcpy(lpszExecutable, lpszExe);
bRet = TRUE;
ErrRtn:
LEDebugOut((DEB_ITRACE, "%p OUT GetAssociatedExecutable( %d )\n",
bRet ));
return bRet;
}
//+-------------------------------------------------------------------------
//
// Function: OleGetIconOfClass (public)
//
// Synopsis: returns a hMetaPict containing an icon and label for the
// specified class ID
//
// Effects:
//
// Arguments: [rclsid] -- the class ID to use
// [lpszLabel] -- the label for the icon
// [fUseTypeAsLabel] -- if TRUE, use the clsid's user type
// as the label
//
// Requires:
//
// Returns: HGLOBAL
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 15-Dec-93 alexgo fixed small bugs with Unicode strings
// 27-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDAPI_(HGLOBAL) OleGetIconOfClass(REFCLSID rclsid, LPOLESTR lpszLabel,
BOOL fUseTypeAsLabel)
{
OLETRACEIN((API_OleGetIconOfClass,
PARAMFMT("rclisd= %I, lpszLabel= %p, fUseTypeAsLabel= %B"),
&rclsid, lpszLabel, fUseTypeAsLabel));
VDATEHEAP();
BOOL bRet;
OLECHAR szLabel[OLEUI_CCHLABELMAX];
OLECHAR szIconFile[OLEUI_CCHPATHMAX];
OLECHAR szDocument[OLEUI_CCHLABELMAX];
HICON hDefIcon;
UINT IconIndex;
HGLOBAL hMetaPict = NULL;
LEDebugOut((DEB_TRACE, "%p _IN OleGetIconOfClass (%p, %p, %d)\n",
NULL, &rclsid, lpszLabel, fUseTypeAsLabel));
*szLabel = OLESTR('\0');
*szDocument = OLESTR('\0');
#if DBG==1
if (fUseTypeAsLabel && (NULL != lpszLabel))
{
LEDebugOut((DEB_WARN,
"Ignoring non-NULL lpszLabel passed to OleGetIconOfClass\n"));
}
#endif
if (!fUseTypeAsLabel) // Use string passed in as label
{
if (NULL != lpszLabel)
{
// LSTRCPYN takes count of characters!
LSTRCPYN(szLabel, lpszLabel, sizeof(szLabel) / sizeof(OLECHAR));
}
}
// Use AuxUserType2 (short name) as label
else if (0 == OleStdGetAuxUserType(rclsid, AUXUSERTYPE_SHORTNAME,
szLabel,
sizeof(szLabel) / sizeof(OLECHAR),
NULL))
{
// If we can't get the AuxUserType2, then try the long name
if (0 == OleStdGetUserTypeOfClass(rclsid,
szLabel,
sizeof(szLabel) / sizeof(OLECHAR),
NULL))
{
if (OLESTR('\0') == szDocument[0])
{
// RegQueryValue expects number of *bytes*
LONG lRet;
LONG lcb;
lcb = sizeof(szDocument);
lRet = RegQueryValue(HKEY_CLASSES_ROOT, gszDefIconLabelKey,
szDocument, &lcb);
#if DBG==1
if (ERROR_SUCCESS != lRet)
{
LEDebugOut((DEB_WARN,
"RegQueryValue for default icon label failed - %d\n",
GetLastError()));
}
#endif
// NULL out last byte of string so don't rely on Reg behavior if buffer isn't big enough
szDocument[OLEUI_CCHLABELMAX -1] = OLESTR('\0');
}
_xstrcpy(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
{
DWORD dwLen;
dwLen = GetModuleFileName(g_hmodOLE2,
szIconFile,
sizeof(szIconFile) / sizeof(OLECHAR));
if (0 == dwLen)
{
LEDebugOut((DEB_WARN,
"OleGetIconOfClass: GetModuleFileName failed - %ld",
GetLastError()));
goto ErrRtn;
}
IconIndex = ICONINDEX;
hDefIcon = LoadIcon(g_hmodOLE2, MAKEINTRESOURCE(DEFICON));
}
// Create the metafile
hMetaPict = OleMetafilePictFromIconAndLabel(hDefIcon, szLabel,
szIconFile, IconIndex);
if(hDefIcon)
bRet = DestroyIcon(hDefIcon);
Win4Assert(bRet && "DestroyIcon failed");
ErrRtn:
LEDebugOut((DEB_TRACE, "%p OUT OleGetIconOfClass( %p )\n",
NULL, hMetaPict ));
OLETRACEOUTEX((API_OleGetIconOfClass, RETURNFMT("%h"), hMetaPict));
return hMetaPict;
}
//+-------------------------------------------------------------------------
//
// Function: HIconAndSourceFromClass
//
// Synopsis:
// 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.
//
// Effects:
//
// Arguments: [rclsid] -- pointer the class id
// [pszSource] -- where to put the source of the icon
// [puIcon] -- where to store the index of the icon
// -- in [pszSource]
//
// Requires:
//
// Returns: HICON -- handle to the extracted icon
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 27-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
HICON FAR PASCAL HIconAndSourceFromClass(REFCLSID rclsid, LPOLESTR pszSource,
UINT FAR *puIcon)
{
VDATEHEAP();
HICON hIcon = NULL;
UINT IconIndex;
LEDebugOut((DEB_ITRACE, "%p _IN HIconAndSourceFromClass (%p, %p, %p)\n",
NULL, &rclsid, pszSource, puIcon));
if (IsEqualCLSID(CLSID_NULL, rclsid) || NULL==pszSource)
{
goto ErrRtn;
}
if (!FIconFileFromClass(rclsid, pszSource, OLEUI_CCHPATHMAX, &IconIndex))
{
goto ErrRtn;
}
hIcon = OleExtractIcon(g_hmodOLE2, pszSource, IconIndex);
// REVIEW: What's special about icon handles > 32 ?
if ((HICON)32 > hIcon)
{
// REVIEW: any cleanup or releasing of handle needed before we lose
// the ptr?
hIcon=NULL;
}
else
{
*puIcon= IconIndex;
}
ErrRtn:
LEDebugOut((DEB_ITRACE, "%p OUT HIconAndSourceFromClass( %lx ) [ %d ]\n",
NULL, hIcon, *puIcon));
return hIcon;
}
//+-------------------------------------------------------------------------
//
// Function: ExtractNameAndIndex
//
// Synopsis: from the given string, extract the file name and icon index
//
// Effects:
//
// Arguments: [pszInfo] -- the starting string
// [pszEXE] -- where to put the name (already allocated)
// [cchEXE] -- sizeof pszEXE
// [pIndex] -- where to put the icon index
//
// Requires: pszInfo != NULL
// pszEXE != NULL
// cchEXE != 0
// pIndex != NULL
//
// Returns: BOOL -- TRUE on success, FALSE on error
//
// Signals:
//
// Modifies:
//
// Algorithm: takes strings of the form '"name",index' or 'name,index'
// from the DefaultIcon registry entry
//
// parsing is very simple: if the name is enclosed in quotes,
// take that as the exe name. If any other characters exist,
// they must be a comma followed by digits (for the icon index)
//
// if the name is not enclosed by quotes, assume the name is
// the entire string up until the last comma (if it exists).
//
// History: dd-mmm-yy Author Comment
// 27-Dec-94 alexgo author
//
// Notes: legal filenames in NT and Win95 can include commas, but not
// quotation marks.
//
//--------------------------------------------------------------------------
BOOL ExtractNameAndIndex( LPOLESTR pszInfo, LPOLESTR pszEXE, UINT cchEXE,
UINT *pIndex)
{
BOOL fRet = FALSE;
LPOLESTR pszStart = pszInfo;
LPOLESTR pszIndex = NULL;
LPOLESTR pszDest = pszEXE;
UINT cchName = 0;
DWORD i = 0;
Assert(pszInfo);
Assert(pszEXE);
Assert(cchEXE != 0);
Assert(pIndex);
VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN ExtractNameAndIndex ( \"%ws\" , \"%ws\" ,"
" %d , %p )\n", NULL, pszInfo, pszEXE, cchEXE, pIndex));
*pIndex = 0;
if( *pszStart == OLESTR('\"') )
{
// name enclosed by quotes; just zoom down til the very last quote
pszStart++;
while( *pszStart != OLESTR('\0') && *pszStart != OLESTR('\"') &&
pszDest < (pszEXE + cchEXE))
{
*pszDest = *pszStart;
pszDest++;
pszStart++;
}
*pszDest = OLESTR('\0');
if( *pszStart == OLESTR('\"') )
{
pszIndex = pszStart + 1;
}
else
{
pszIndex = pszStart;
}
fRet = TRUE;
}
else
{
// find the last comma (if available)
pszIndex = pszStart + _xstrlen(pszStart);
while( *pszIndex != OLESTR(',') && pszIndex > pszStart )
{
pszIndex--;
}
// if no comma was found, just reset the index pointer to the end
if( pszIndex == pszStart )
{
pszIndex = pszStart + _xstrlen(pszStart);
}
cchName = (ULONG) (pszIndex - pszStart)/sizeof(OLECHAR);
if( cchEXE > cchName )
{
while( pszStart < pszIndex )
{
*pszDest = *pszStart;
pszDest++;
pszStart++;
}
*pszDest = OLESTR('\0');
fRet = TRUE;
}
}
// now fetch the index value
if( *pszIndex == OLESTR(',') )
{
pszIndex++;
}
*pIndex = wcstol(pszIndex, NULL, 10);
LEDebugOut((DEB_ITRACE, "%p OUT ExtractNameAndIndex ( %d ) [ \"%ws\" , "
" %d ]\n", NULL, fRet, pszEXE, *pIndex));
return fRet;
}
#if DBG == 1
//+-------------------------------------------------------------------------
//
// Function: VerifyExtractNameAndIndex
//
// Synopsis: verifies the functioning of ExtractNameAndIndex (DEBUG only)
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: void
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 27-Dec-94 alexgo author
//
// Notes:
//
//--------------------------------------------------------------------------
void VerifyExtractNameAndIndex( void )
{
OLECHAR szName[256];
UINT index = 0;
BOOL fRet = FALSE;
VDATEHEAP();
fRet = ExtractNameAndIndex( OLESTR("\"foo,8\",8"), szName, 256, &index);
Assert(fRet);
Assert(_xstrcmp(szName, OLESTR("foo,8")) == 0);
Assert(index == 8);
fRet = ExtractNameAndIndex( OLESTR("foo,8,8,89"), szName, 256, &index);
Assert(fRet);
Assert(_xstrcmp(szName, OLESTR("foo,8,8")) == 0);
Assert(index == 89);
fRet = ExtractNameAndIndex( OLESTR("progman.exe"), szName, 256, &index);
Assert(fRet);
Assert(_xstrcmp(szName, OLESTR("progman.exe")) == 0);
Assert(index == 0);
fRet = ExtractNameAndIndex( OLESTR("\"progman.exe\""), szName, 256,
&index);
Assert(fRet);
Assert(_xstrcmp(szName, OLESTR("progman.exe")) == 0);
Assert(index == 0);
VDATEHEAP();
}
#endif // DBG == 1
LONG RegReadDefValue(HKEY hKey, LPOLESTR pszKey, LPOLESTR *ppszValue)
{
HKEY hSubKey = NULL;
DWORD dw = 0;
LONG lRet;
LPOLESTR pszValue = NULL;
lRet = RegOpenKeyEx(hKey, pszKey, 0, KEY_READ, &hSubKey);
if(lRet != ERROR_SUCCESS) goto ErrRtn;
lRet = RegQueryValueEx(hSubKey, NULL, NULL, NULL, NULL, &dw);
if(lRet != ERROR_SUCCESS) goto ErrRtn;
pszValue = (LPOLESTR) CoTaskMemAlloc(dw);
if(!pszValue)
{
lRet = ERROR_OUTOFMEMORY;
goto ErrRtn;
}
lRet = RegQueryValueEx(hSubKey, NULL, NULL, NULL, (PBYTE) pszValue, &dw);
ErrRtn:
if(lRet != ERROR_SUCCESS && pszValue)
{
CoTaskMemFree(pszValue);
pszValue = NULL;
}
if(hSubKey)
RegCloseKey(hSubKey);
*ppszValue = pszValue;
return lRet;
}
//+-------------------------------------------------------------------------
//
// Function: FIconFileFromClass, private
//
// Synopsis: Looks up the path to the exectuble that contains the class
// default icon
//
// Effects:
//
// Arguments: [rclsid] -- the class ID to lookup
// [pszEXE] -- where to put the server name
// [cch] -- UINT size of [pszEXE]
// [lpIndex] -- where to put the index of the icon
// in the executable
//
// Requires: pszEXE != NULL
// cch != 0
//
// Returns: TRUE if one or more characters where found for [pszEXE],
// FALSE otherwise
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 27-Nov-93 alexgo 32bit port
// 15-Dec-93 alexgo fixed memory allocation bug and
// some UNICODE string manip stuff
// 27-Apr-94 AlexT Tracing, clean up memory allocation
//
// Notes:
//
//--------------------------------------------------------------------------
BOOL FAR PASCAL FIconFileFromClass(REFCLSID rclsid, LPOLESTR pszEXE,
UINT cch, UINT FAR *lpIndex)
{
VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN FIconFileFromClass (%p, %p, %d, %p)\n",
NULL, &rclsid, pszEXE, cch, lpIndex));
Win4Assert(NULL != pszEXE && "Bad argument to FIconFileFromClass");
Win4Assert(cch != 0 && "Bad argument to FIconFileFromClass");
BOOL bRet;
LPOLESTR lpBuffer = NULL;
LPOLESTR lpBufferExp = NULL;
LONG dw;
LONG lRet;
HKEY hKey;
LPOLESTR lpIndexString;
if (IsEqualCLSID(CLSID_NULL, rclsid))
{
bRet = FALSE;
goto ErrRtn;
}
//Here, we alloc a buffer (maxpathlen + 8) to
//pass to RegQueryValue. Then, we copy the exe to pszEXE and the
//index to *lpIndex.
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.
// REVIEW: could this possibly fail and leave you with an
// invalid ptr passed into regopenkey?
ProgIDFromCLSID(rclsid, &lpszProgID);
//Open up the class key
lRet=RegOpenKey(HKEY_CLASSES_ROOT, lpszProgID, &hKey);
PubMemFree(lpszProgID);
if (ERROR_SUCCESS != lRet)
{
bRet = FALSE;
goto ErrRtn;
}
// RegQueryValue expects number of *bytes*
lRet = RegReadDefValue(hKey, OLESTR("Protocol\\StdFileEditing\\Server"), &lpBuffer);
RegCloseKey(hKey);
if (ERROR_SUCCESS != lRet)
{
bRet = FALSE;
goto ErrRtn;
}
// Use server and 0 as the icon index
dw = ExpandEnvironmentStringsW(lpBuffer, pszEXE, cch);
if(dw == 0 || dw > (LONG)cch)
{
bRet = FALSE;
goto ErrRtn;
}
// REVIEW: is this internally trusted? No validation...
// (same for rest of writes to it this fn)
*lpIndex = 0;
bRet = TRUE;
goto ErrRtn;
}
/*
* 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.
*/
{
LPOLESTR pszClass;
OLECHAR szKey[64];
StringFromCLSID(rclsid, &pszClass);
_xstrcpy(szKey, OLESTR("CLSID\\"));
_xstrcat(szKey, pszClass);
PubMemFree(pszClass);
//Open up the class key
lRet=RegOpenKey(HKEY_CLASSES_ROOT, szKey, &hKey);
}
if (ERROR_SUCCESS != lRet)
{
bRet = FALSE;
goto ErrRtn;
}
//Get the executable path and icon index.
// RegQueryValue expects number of bytes
lRet = RegReadDefValue(hKey, OLESTR("DefaultIcon"), &lpBuffer);
if (ERROR_SUCCESS != lRet)
{
// no DefaultIcon key...try LocalServer
lRet = RegReadDefValue(hKey, OLESTR("LocalServer32"), &lpBuffer);
}
if (ERROR_SUCCESS != lRet)
{
lRet = RegReadDefValue(hKey, OLESTR("LocalServer"), &lpBuffer);
}
RegCloseKey(hKey);
if (ERROR_SUCCESS != lRet)
{
// no LocalServer entry either...they're outta luck.
bRet = FALSE;
goto ErrRtn;
}
// Nt #335548
dw = ExpandEnvironmentStringsW(lpBuffer, NULL, 0);
if(dw)
{
lpBufferExp = (LPOLESTR) CoTaskMemAlloc(dw * sizeof(OLECHAR));
dw = ExpandEnvironmentStringsW(lpBuffer, lpBufferExp, dw);
}
if(!dw)
{
LEDebugOut((DEB_WARN, "ExpandEnvStrings failure!"));
bRet = FALSE;
goto ErrRtn;
}
// lpBuffer contains a string that looks like
// "<pathtoexe>,<iconindex>",
// so we need to separate the path and the icon index.
bRet = ExtractNameAndIndex(lpBufferExp, pszEXE, cch, lpIndex);
#if DBG == 1
// do some quick checking while we're at it.
VerifyExtractNameAndIndex();
#endif // DBG == 1
ErrRtn:
if(lpBuffer)
CoTaskMemFree(lpBuffer);
if(lpBufferExp)
CoTaskMemFree(lpBufferExp);
LEDebugOut((DEB_ITRACE, "%p OUT FIconFileFromClass ( %d ) [%d]\n",
NULL, bRet, *lpIndex));
return bRet;
}
//+-------------------------------------------------------------------------
//
// Function: OleMetafilePictFromIconAndLabel (public)
//
// Synopsis:
// 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.
//
// Effects:
//
// Arguments: [hIcon] -- icon to draw into the metafile
// [pszLabel] -- the label string
// [pszSourceFile] -- local pathname of the icon
// [iIcon] -- index into [pszSourceFile] for the icon
//
// Requires:
//
// Returns: HGLOBAL to a METAFILEPICT structure (using MM_ANISOTROPIC
// mapping mode)
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 27-Nov-93 alexgo first 32bit port
// 15-Dec-93 alexgo fixed bugs with UNICODE strings
// 09-Mar-94 AlexT Make this backwards compatible
//
// Notes: REVIEW32:: need to fix font grabbing etc, to be international
// friendly, see comments below
//
//--------------------------------------------------------------------------
STDAPI_(HGLOBAL) OleMetafilePictFromIconAndLabel(HICON hIcon,
LPOLESTR pwcsLabel, LPOLESTR pwcsSourceFile, UINT iIcon)
{
OLETRACEIN((API_OleMetafilePictFromIconAndLabel,
PARAMFMT("hIcon= %h, pwcsLabel= %ws, pwcsSourceFile= %ws, iIcon= %d"),
hIcon, pwcsLabel, pwcsSourceFile, iIcon));
VDATEHEAP();
LEDebugOut((DEB_TRACE, "%p _IN OleMetafilePictFromIconAndLabel (%p, %p, %p, %d)\n",
NULL, hIcon, pwcsLabel, pwcsSourceFile, iIcon));
//Where to stop to exclude label (explicitly ANSI)
static char szIconOnly[] = "IconOnly";
static char szIconLabelNext[] = "OLE: Icon label next (Unicode)";
static char szIconSourceNext[] = "OLE: Icon source next (Unicode)";
static char szDefaultChar[] = "?";
// REVIEW: Mein Got! This is a huge fn, could it be broken up?
HGLOBAL hMem = NULL;
HDC hDC, hDCScreen = NULL;
HMETAFILE hMF;
LPMETAFILEPICT pMF;
OLECHAR wszIconLabel[OLEUI_CCHLABELMAX + 1];
char szIconLabel[OLEUI_CCHLABELMAX + 1];
UINT cchLabelW;
UINT cchLabelA;
UINT cchIndex;
BOOL bUsedDefaultChar;
TEXTMETRICA textMetric;
UINT cxIcon, cyIcon;
UINT cxText, cyText;
UINT cx, cy;
HFONT hFont, hSysFont, hFontT;
int cyFont;
char szIndex[10];
RECT TextRect;
char * pszSourceFile;
UINT cchSourceFile;
int iRet;
BOOL bWriteUnicodeLabel;
BOOL bWriteUnicodeSource;
LOGFONT logfont;
if (NULL == hIcon) // null icon is valid
{
goto ErrRtn;
}
//Need to use the screen DC for these operations
hDCScreen = GetDC(NULL);
if (!hDCScreen)
goto ErrRtn;
// REVIEW: ptr validation on IN params?
bWriteUnicodeSource = FALSE;
pszSourceFile = NULL;
if (NULL != pwcsSourceFile)
{
// Prepare source file string
cchSourceFile = _xstrlen(pwcsSourceFile) + 1;
#if defined(WIN32)
pszSourceFile = (char *) PrivMemAlloc(cchSourceFile * sizeof(WCHAR));
#else
pszSourceFile = (char *) PrivMemAlloc(cchSourceFile);
#endif // WIN32
if (NULL == pszSourceFile)
{
LEDebugOut((DEB_WARN, "PrivMemAlloc(%d) failed\n",
cchSourceFile));
goto ErrRtn;
}
#if defined(WIN32)
iRet = WideCharToMultiByte(AreFileApisANSI() ? CP_ACP : CP_OEMCP, 0,
pwcsSourceFile, cchSourceFile,
pszSourceFile, cchSourceFile * sizeof(WCHAR),
szDefaultChar, &bUsedDefaultChar);
#else
iRet = WideCharToMultiByte(AreFileApisANSI() ? CP_ACP : CP_OEMCP, 0,
pwcsSourceFile, cchSourceFile,
pszSourceFile, cchSourceFile,
szDefaultChar, &bUsedDefaultChar);
#endif // WIN32
bWriteUnicodeSource = bUsedDefaultChar;
if (0 == iRet)
{
// Unexpected failure, since at worst we should have
// just filled in pszSourceFile with default characters.
LEDebugOut((DEB_WARN, "WideCharToMultiByte failed - %lx\n",
GetLastError()));
}
}
// Create a memory metafile. We explicitly make it an ANSI metafile for
// backwards compatibility.
#ifdef WIN32
hDC = CreateMetaFileA(NULL);
#else
hDC = CreateMetaFile(NULL);
#endif
if (NULL == hDC)
{
LEDebugOut((DEB_WARN, "CreateMetaFile failed - %lx\n",
GetLastError()));
PrivMemFree(pszSourceFile);
goto ErrRtn;
}
//Allocate the metafilepict
hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, sizeof(METAFILEPICT));
if (NULL == hMem)
{
LEDebugOut((DEB_WARN, "GlobalAlloc failed - %lx\n",
GetLastError()));
hMF = CloseMetaFile(hDC);
DeleteMetaFile(hMF);
PrivMemFree(pszSourceFile);
goto ErrRtn;
}
// Prepare ANSI label
szIconLabel[0] = '\0';
cchLabelW = 0;
cchLabelA = 0;
// REVIEW: don't follow the logic here: you conditionally set it above
// and explicity clear it here?
bWriteUnicodeLabel = FALSE;
if (NULL != pwcsLabel)
{
cchLabelW = _xstrlen(pwcsLabel) + 1;
if (OLEUI_CCHLABELMAX < cchLabelW)
{
//REVIEW: would it be worth warning of the truncation in debug builds?
// or is this a common case?
LSTRCPYN(wszIconLabel, pwcsLabel, OLEUI_CCHLABELMAX);
wszIconLabel[OLEUI_CCHLABELMAX] = L'\0';
pwcsLabel = wszIconLabel;
cchLabelW = OLEUI_CCHLABELMAX;
}
#if defined(WIN32)
cchLabelA = WideCharToMultiByte(AreFileApisANSI() ? CP_ACP : CP_OEMCP, 0,
pwcsLabel, cchLabelW,
szIconLabel, 0,
NULL, NULL);
#else
cchLabelA = cchLabelW;
#endif // WIN32
// We have a label - translate it to ANSI for the TextOut's...
iRet = WideCharToMultiByte(AreFileApisANSI() ? CP_ACP : CP_OEMCP, 0,
pwcsLabel, cchLabelW,
szIconLabel, sizeof(szIconLabel),
szDefaultChar, &bUsedDefaultChar);
if (0 == iRet)
{
// Unexpected failure, since at worst we should have
// just filled in pszSourceFile with default characters.
LEDebugOut((DEB_WARN, "WideCharToMultiByte failed - %lx\n",
GetLastError()));
}
bWriteUnicodeLabel = bUsedDefaultChar;
}
LOGFONT lf;
SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, FALSE);
hFont = CreateFontIndirect(&lf);
hFontT= (HFONT) SelectObject(hDCScreen, hFont);
GetTextMetricsA(hDCScreen, &textMetric);
// We use double the height to provide some margin space
cyText = textMetric.tmHeight*3; //max 2 lines & some space
SelectObject(hDCScreen, hFontT);
cxIcon = GetSystemMetrics(SM_CXICON);
cyIcon = GetSystemMetrics(SM_CYICON);
cxText = cxIcon*3; //extent of text based upon icon width causes
//the label to look nice and proportionate.
// 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 ('\0' == szIconLabel[0])
{
cx = cxIcon + cxIcon / 4;
}
else
{
cx = max(cxText, cxIcon);
}
cy = cyIcon + cyText + 4; // Why 4?
//Set the metafile size to fit the icon and label
SetMapMode(hDC, MM_ANISOTROPIC);
SetWindowOrgEx(hDC, 0, 0, NULL);
SetWindowExtEx(hDC, cx, cy, NULL);
//Set up rectangle to pass to IconLabelTextOut
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, sizeof(szIconOnly), szIconOnly, NULL);
SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
SetBkMode(hDC, TRANSPARENT);
IconLabelTextOut(hDC, hFont, 0, cy - cyText, ETO_CLIPPED,
&TextRect, szIconLabel, cchLabelA);
// Write comments containing the icon source file and index.
if (NULL != pwcsSourceFile)
{
AssertSz(pszSourceFile != NULL, "Unicode source existed");
//Escape wants number of *bytes*
Escape(hDC, MFCOMMENT,
cchSourceFile, pszSourceFile, NULL);
cchIndex = wsprintfA(szIndex, "%u", iIcon);
// Escape wants number of *bytes*
Escape(hDC, MFCOMMENT, cchIndex + 1, szIndex, NULL);
}
else if (bWriteUnicodeLabel || bWriteUnicodeSource)
{
// We're going to write out comment records for the Unicode
// strings, so we need to emit dummy ANSI source comments.
//Escape wants number of *bytes*
Escape(hDC, MFCOMMENT, sizeof(""), "", NULL);
// Escape wants number of *bytes*
Escape(hDC, MFCOMMENT, sizeof("0"), "0", NULL);
}
if (bWriteUnicodeLabel)
{
// Now write out the UNICODE label
Escape(hDC, MFCOMMENT,
sizeof(szIconLabelNext), szIconLabelNext, NULL);
Escape(hDC, MFCOMMENT,
cchLabelW * sizeof(OLECHAR), (LPSTR) pwcsLabel,
NULL);
}
if (bWriteUnicodeSource)
{
// Now write out the UNICODE label
Escape(hDC, MFCOMMENT,
sizeof(szIconSourceNext), szIconSourceNext, NULL);
Escape(hDC, MFCOMMENT,
cchSourceFile * sizeof(OLECHAR), (LPSTR) pwcsSourceFile,
NULL);
}
//All done with the metafile, now stuff it all into a METAFILEPICT.
hMF = CloseMetaFile(hDC);
if (NULL==hMF)
{
GlobalFree(hMem);
hMem = NULL;
goto ErrRtn;
}
pMF=(LPMETAFILEPICT)GlobalLock(hMem);
//Transform to HIMETRICS
cx=XformWidthInPixelsToHimetric(hDCScreen, cx);
cy=XformHeightInPixelsToHimetric(hDCScreen, cy);
pMF->mm=MM_ANISOTROPIC;
pMF->xExt=cx;
pMF->yExt=cy;
pMF->hMF=hMF;
GlobalUnlock(hMem);
if(hFont)
DeleteObject(hFont);
PrivMemFree(pszSourceFile);
// REVIEW: any need to release the font resource?
ErrRtn:
if(hDCScreen)
ReleaseDC(NULL, hDCScreen);
LEDebugOut((DEB_TRACE, "%p OUT OleMetafilePictFromIconAndLabel ( %p )\n",
NULL, hMem));
OLETRACEOUTEX((API_OleMetafilePictFromIconAndLabel,
RETURNFMT("%h"), hMem));
return hMem;
}
//+-------------------------------------------------------------------------
//
// Function: IconLabelTextOut (internal)
//
// Synopsis:
// Replacement for DrawText to be used in the "Display as Icon" metafile.
// Uses ExtTextOutA to output a string center on (at most) two lines.
// Uses a very simple word wrap algorithm to split the lines.
//
// Effects:
//
// Arguments: [hDC] -- device context (cannot be NULL)
// [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), including terminating
// NULL
//
// Requires:
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 28-Nov-93 alexgo initial 32bit port
// 09-Mar-94 AlexT Use ANSI strings
//
// Notes:
//
//--------------------------------------------------------------------------
// POSTPPC: The parameter 'cchString' is superfluous since lpszString
// is guaranteed to be null terminated
void IconLabelTextOut(HDC hDC, HFONT hFont, int nXStart, int nYStart,
UINT fuOptions, RECT FAR * lpRect, LPCSTR lpszString,
UINT cchString)
{
VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN IconLabelTextOut (%lx, %lx, %d, %d, %d, %p, %p, %d)\n",
NULL, hDC, hFont,
nXStart, nYStart, fuOptions, lpRect, lpszString, cchString));
AssertSz(hDC != NULL, "Bad arg to IconLabelTextOut");
AssertSz(lpszString != NULL, "Bad arg to IconLabelTextOut");
AssertSz(strlen(lpszString) < OLEUI_CCHLABELMAX,
"Bad arg to IconLabelTextOut");
// REVIEW: does our compiler have to initialize static function scoped
// data? I know old versions did...
static char szSeparators[] = " \t\\/!:";
static char szTempBuff[OLEUI_CCHLABELMAX];
HDC hDCScreen;
int cxString, cyString, cxMaxString;
int cxFirstLine, cyFirstLine, cxSecondLine;
int index;
char chKeep;
LPSTR lpszSecondLine;
LPSTR lpstrLast;
HFONT hFontT;
SIZE size;
int cch = strlen(lpszString);
UINT uiAlign = GDI_ERROR;
// Initialization stuff...
strcpy(szTempBuff, lpszString);
// set maximum width
cxMaxString = lpRect->right - lpRect->left;
// get screen DC to do text size calculations
hDCScreen = GetDC(NULL);
if(!hDCScreen)
return;
hFontT= (HFONT)SelectObject(hDCScreen, hFont);
// get the extent of our label
GetTextExtentPointA(hDCScreen, szTempBuff, cch, &size);
cxString = size.cx;
cyString = size.cy;
// Select in the font we want to use
SelectObject(hDC, hFont);
// Center the string
uiAlign = SetTextAlign(hDC, TA_CENTER);
// String is smaller than max string - just center, ETO, and return.
if (cxString <= cxMaxString)
{
ExtTextOutA(hDC,
nXStart + lpRect->right / 2,
nYStart,
fuOptions,
lpRect,
szTempBuff,
cch,
NULL);
goto CleanupAndLeave;
}
// String is too long...we've got to word-wrap it.
// Are there any spaces, slashes, tabs, or bangs in string?
if (strlen(szTempBuff) != 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)
{
// scan the string backwards for spaces, slashes,
// tabs, or bangs
// REVIEW: scary. Could this result in a negative
// index, or is it guarnateed to hit a separator
// before that?
while (!IS_SEPARATOR(szTempBuff[index]) )
{
index--;
}
if (index <= 0)
{
break;
}
// remember what char was there
chKeep = szTempBuff[index];
szTempBuff[index] = '\0'; // just for now
GetTextExtentPointA(hDCScreen, szTempBuff,
index,&size);
cxFirstLine = size.cx;
cyFirstLine = size.cy;
// REVIEW: but chKeep is NOT an OLECHAR
// put the right OLECHAR back
szTempBuff[index] = chKeep;
if (cxFirstLine <= cxMaxString)
{
ExtTextOutA(hDC,
nXStart + lpRect->right / 2,
nYStart,
fuOptions,
lpRect,
szTempBuff,
index + 1,
NULL);
lpszSecondLine = szTempBuff;
lpszSecondLine += index + 1;
GetTextExtentPointA(hDCScreen,
lpszSecondLine,
strlen(lpszSecondLine),
&size);
// If the second line is wider than the
// rectangle, we just want to clip the text.
cxSecondLine = min(size.cx, cxMaxString);
ExtTextOutA(hDC,
nXStart + lpRect->right / 2,
nYStart + cyFirstLine,
fuOptions,
lpRect,
lpszSecondLine,
strlen(lpszSecondLine),
NULL);
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.
// 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
cch = strlen(szTempBuff);
lpstrLast = &szTempBuff[cch];
chKeep = *lpstrLast;
*lpstrLast = '\0';
GetTextExtentPointA(hDCScreen, szTempBuff, cch, &size);
cxFirstLine = size.cx;
cyFirstLine = size.cy;
while (cxFirstLine > cxMaxString)
{
*lpstrLast = chKeep;
// The string is always ansi, so always use CharPrevA.
lpstrLast = CharPrevA(szTempBuff, lpstrLast);
if (szTempBuff == lpstrLast)
{
goto CleanupAndLeave;
}
chKeep = *lpstrLast;
*lpstrLast = '\0';
// need to calculate the new length of the string
cch = strlen(szTempBuff);
GetTextExtentPointA(hDCScreen, szTempBuff,
cch, &size);
cxFirstLine = size.cx;
}
ExtTextOutA(hDC,
nXStart + lpRect->right / 2,
nYStart,
fuOptions,
lpRect,
szTempBuff,
strlen(szTempBuff),
NULL);
szTempBuff[cch] = chKeep;
lpszSecondLine = szTempBuff;
lpszSecondLine += cch;
GetTextExtentPointA(hDCScreen, lpszSecondLine,
strlen(lpszSecondLine), &size);
// If the second line is wider than the rectangle, we
// just want to clip the text.
cxSecondLine = min(size.cx, cxMaxString);
ExtTextOutA(hDC,
nXStart + lpRect->right / 2,
nYStart + cyFirstLine,
fuOptions,
lpRect,
lpszSecondLine,
strlen(lpszSecondLine),
NULL);
CleanupAndLeave:
// If we changed the alignment we restore it here
if (uiAlign != GDI_ERROR)
{
SetTextAlign(hDC, uiAlign);
}
SelectObject(hDCScreen, hFontT);
ReleaseDC(NULL, hDCScreen);
LEDebugOut((DEB_ITRACE, "%p OUT IconLabelTextOut ()\n"));
}
//+-------------------------------------------------------------------------
//
// Function: OleStdGetUserTypeOfClass, private
//
// Synopsis: Returns the user type info of the specified class
//
// Effects:
//
// Arguments: [rclsid] -- the class ID in question
// [lpszUserType] -- where to put the user type string
// [cch] -- the length of [lpszUserType] (in
// *characters*, not bytes)
// [hKey] -- handle to the reg db (may be NULL)
//
// Requires:
//
// Returns: UINT -- the number of characters put into the return string
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 29-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDAPI_(UINT) OleStdGetUserTypeOfClass(REFCLSID rclsid, LPOLESTR lpszUserType, UINT cch, HKEY hKey)
{
VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN OleStdGetUserTypeOfClass (%p, %p, %d, %lx)\n",
NULL, &rclsid, lpszUserType, cch, hKey));
LONG dw = 0;
LONG lRet;
// REVIEW: would make more sense to set this when the reg is opened
BOOL bCloseRegDB = FALSE;
if (hKey == NULL)
{
//Open up the root key.
lRet=RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey);
if ((LONG)ERROR_SUCCESS!=lRet)
{
goto ErrRtn;
}
bCloseRegDB = TRUE;
}
// Get a string containing the class name
{
LPOLESTR lpszCLSID;
OLECHAR szKey[128];
StringFromCLSID(rclsid, &lpszCLSID);
_xstrcpy(szKey, OLESTR("CLSID\\"));
_xstrcat(szKey, lpszCLSID);
PubMemFree((LPVOID)lpszCLSID);
dw = cch * sizeof(OLECHAR);
lRet = RegQueryValue(hKey, szKey, lpszUserType, &dw);
dw = dw / sizeof(OLECHAR);
}
if ((LONG)ERROR_SUCCESS!=lRet)
{
dw = 0;
}
if ( ((LONG)ERROR_SUCCESS!=lRet) && (CoIsOle1Class(rclsid)) )
{
LPOLESTR lpszProgID;
// We've got an OLE 1.0 class, so let's try to get the user
// type name from the ProgID entry.
ProgIDFromCLSID(rclsid, &lpszProgID);
// REVIEW: will progidfromclsid always set your ptr for you?
dw = cch * sizeof(OLECHAR);
lRet = RegQueryValue(hKey, lpszProgID, lpszUserType, &dw);
dw = dw / sizeof(OLECHAR);
PubMemFree((LPVOID)lpszProgID);
if ((LONG)ERROR_SUCCESS != lRet)
{
dw = 0;
}
}
if (bCloseRegDB)
{
RegCloseKey(hKey);
}
ErrRtn:
LEDebugOut((DEB_ITRACE, "%p OUT OleStdGetUserTypeOfClass ( %d )\n",
NULL, dw));
return (UINT)dw;
}
//+-------------------------------------------------------------------------
//
// Function: OleStdGetAuxUserType, private
//
// Synopsis: Returns the specified AuxUserType from the reg db
//
// Effects:
//
// Arguments: [rclsid] -- the class ID in question
// [hKey] -- handle to the reg db root (may be NULL)
// [wAuxUserType] -- which field to look for (name, exe, etc)
// [lpszUserType] -- where to put the returned string
// [cch] -- size of [lpszUserType] in *characters*
//
// Requires:
//
// Returns: UINT -- number of characters in returned string.
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 29-Nov-93 alexgo 32bit port
// 27-Apr-94 AlexT Tracing, clean up
//
// Notes:
//
//--------------------------------------------------------------------------
STDAPI_(UINT) OleStdGetAuxUserType(REFCLSID rclsid,
WORD wAuxUserType,
LPOLESTR lpszAuxUserType,
int cch,
HKEY hKey)
{
VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN OleStdGetAuxUserType (%p, %hu, %p, %d, %lx)\n",
NULL, &rclsid, wAuxUserType, lpszAuxUserType, cch, hKey));
LONG dw = 0;
HKEY hThisKey;
BOOL bCloseRegDB = FALSE;
LRESULT lRet;
LPOLESTR lpszCLSID;
OLECHAR szKey[OLEUI_CCHKEYMAX];
OLECHAR szTemp[32];
lpszAuxUserType[0] = OLESTR('\0');
if (NULL == hKey)
{
lRet = RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hThisKey);
if (ERROR_SUCCESS != lRet)
{
goto ErrRtn;
}
bCloseRegDB = TRUE;
}
else
{
hThisKey = hKey;
}
StringFromCLSID(rclsid, &lpszCLSID);
_xstrcpy(szKey, OLESTR("CLSID\\"));
_xstrcat(szKey, lpszCLSID);
wsprintf(szTemp, OLESTR("\\AuxUserType\\%d"), wAuxUserType);
_xstrcat(szKey, szTemp);
PubMemFree(lpszCLSID);
dw = cch * sizeof(OLECHAR);
lRet = RegQueryValue(hThisKey, szKey, lpszAuxUserType, &dw);
// Convert dw from byte count to OLECHAR count
dw = dw / sizeof(OLECHAR);
if (ERROR_SUCCESS != lRet)
{
dw = 0;
lpszAuxUserType[0] = '\0';
}
if (bCloseRegDB)
{
RegCloseKey(hThisKey);
}
ErrRtn:
// dw is
LEDebugOut((DEB_ITRACE, "%p OUT OleStdGetAuxUserType ( %d )\n",
NULL, dw));
return (UINT)dw;
}
//REVIEW: these seem redundant, could the fns be mereged creatively?
//+-------------------------------------------------------------------------
//
// Function:
// XformWidthInPixelsToHimetric
// XformWidthInHimetricToPixels
// XformHeightInPixelsToHimetric
// XformHeightInHimetricToPixels
//
// Synopsis:
// Functions to convert an int between a device coordinate system and
// logical HiMetric units.
//
// Effects:
//
// Arguments:
//
// [hDC] HDC providing reference to the pixel mapping. If
// NULL, a screen DC is used.
//
// Size Functions:
// [lpSizeSrc] LPSIZEL providing the structure to convert. This
// contains pixels in XformSizeInPixelsToHimetric and
// logical HiMetric units in the complement function.
// [lpSizeDst] LPSIZEL providing the structure to receive converted
// units. This contains pixels in
// XformSizeInPixelsToHimetric and logical HiMetric
// units in the complement function.
//
// Width Functions:
// [iWidth] int containing the value to convert.
//
// Requires:
//
// Returns:
// Size Functions: None
// Width Functions: Converted value of the input parameters.
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 29-Nov-93 alexgo 32bit port (initial)
//
// Notes:
//
// When displaying on the screen, Window apps display everything enlarged
// from its actual size so that it is easier to read. For example, if an
// app wants to display a 1in. horizontal line, that when printed is
// actually a 1in. line on the printed page, then it will display the line
// on the screen physically larger than 1in. This is described as a line
// that is "logically" 1in. along the display width. Windows maintains as
// part of the device-specific information about a given display device:
// LOGPIXELSX -- no. of pixels per logical in along the display width
// LOGPIXELSY -- no. of pixels per logical in along the display height
//
// The following formula converts a distance in pixels into its equivalent
// logical HIMETRIC units:
//
// DistInHiMetric = (HIMETRIC_PER_INCH * DistInPix)
// -------------------------------
// PIXELS_PER_LOGICAL_IN
//
//
// REVIEW32:: merge all these functions into one, as they all do
// basically the same thing
//
//--------------------------------------------------------------------------
STDAPI_(int) XformWidthInPixelsToHimetric(HDC hDC, int iWidthInPix)
{
VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN XformWidthInPixelsToHimetric (%lx, %d)\n",
NULL, hDC, iWidthInPix));
int iXppli; // Pixels per logical inch along width
int iWidthInHiMetric;
BOOL fSystemDC=FALSE;
if (NULL==hDC)
{
hDC=GetDC(NULL);
fSystemDC=TRUE;
if(!hDC)
return 0;
}
iXppli = GetDeviceCaps (hDC, LOGPIXELSX);
// We got pixel units, convert them to logical HIMETRIC along
// the display
iWidthInHiMetric = MAP_PIX_TO_LOGHIM(iWidthInPix, iXppli);
if (fSystemDC)
{
ReleaseDC(NULL, hDC);
}
LEDebugOut((DEB_ITRACE, "%p OUT XformWidthInPixelsToHimetric (%d)\n",
NULL, iWidthInHiMetric));
return iWidthInHiMetric;
}
//+-------------------------------------------------------------------------
//
// Function: XformWidthInHimetricToPixels
//
// Synopsis: see XformWidthInPixelsToHimetric
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 29-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDAPI_(int) XformWidthInHimetricToPixels(HDC hDC, int iWidthInHiMetric)
{
VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN XformWidthInHimetricToPixels (%lx, %d)\n",
NULL, hDC, iWidthInHiMetric));
int iXppli; //Pixels per logical inch along width
int iWidthInPix;
BOOL fSystemDC=FALSE;
if (NULL==hDC)
{
hDC=GetDC(NULL);
fSystemDC=TRUE;
if(!hDC)
return 0;
}
iXppli = GetDeviceCaps (hDC, LOGPIXELSX);
// We got logical HIMETRIC along the display, convert them to
// pixel units
iWidthInPix = MAP_LOGHIM_TO_PIX(iWidthInHiMetric, iXppli);
if (fSystemDC)
{
ReleaseDC(NULL, hDC);
}
LEDebugOut((DEB_ITRACE, "%p OUT XformWidthInHimetricToPixels (%d)\n",
NULL, iWidthInPix));
return iWidthInPix;
}
//+-------------------------------------------------------------------------
//
// Function: XformHeightInPixelsToHimetric
//
// Synopsis: see XformWidthInPixelsToHimetric
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 29-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDAPI_(int) XformHeightInPixelsToHimetric(HDC hDC, int iHeightInPix)
{
VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN XformHeightInPixelsToHimetric (%lx, %d)\n",
NULL, hDC, iHeightInPix));
int iYppli; //Pixels per logical inch along height
int iHeightInHiMetric;
BOOL fSystemDC=FALSE;
if (NULL==hDC)
{
hDC=GetDC(NULL);
fSystemDC=TRUE;
if(!hDC)
return 0;
}
iYppli = GetDeviceCaps (hDC, LOGPIXELSY);
// We got pixel units, convert them to logical HIMETRIC along the
// display
iHeightInHiMetric = MAP_PIX_TO_LOGHIM(iHeightInPix, iYppli);
if (fSystemDC)
{
ReleaseDC(NULL, hDC);
}
LEDebugOut((DEB_ITRACE, "%p OUT XformHeightInPixelsToHimetric (%d)\n",
NULL, hDC, iHeightInHiMetric));
return iHeightInHiMetric;
}
//+-------------------------------------------------------------------------
//
// Function: XformHeightInHimetricToPixels
//
// Synopsis: see XformWidthInPixelsToHimetric
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 29-Nov-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
STDAPI_(int) XformHeightInHimetricToPixels(HDC hDC, int iHeightInHiMetric)
{
VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN XformHeightInHimetricToPixels (%lx, %d)\n",
NULL, hDC, iHeightInHiMetric));
int iYppli; //Pixels per logical inch along height
int iHeightInPix;
BOOL fSystemDC=FALSE;
if (NULL==hDC)
{
hDC=GetDC(NULL);
fSystemDC=TRUE;
if(!hDC)
return 0;
}
iYppli = GetDeviceCaps (hDC, LOGPIXELSY);
// We got logical HIMETRIC along the display, convert them to pixel
// units
iHeightInPix = MAP_LOGHIM_TO_PIX(iHeightInHiMetric, iYppli);
if (fSystemDC)
{
ReleaseDC(NULL, hDC);
}
LEDebugOut((DEB_ITRACE, "%p OUT XformHeightInHimetricToPixels (%d)\n",
NULL, hDC, iHeightInPix));
return iHeightInPix;
}