2388 lines
66 KiB
C++
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;
|
|
}
|