//+------------------------------------------------------------------------- // // 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 #include #include #include #include #include #include #include #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 // ",", // 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; }