//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1994. // // File: icon.cxx // // Contents: icon.cpp from OLE2 // // History: 11-Apr-94 DrewB Copied from OLE2 // //---------------------------------------------------------------------------- #include "headers.cxx" #pragma hdrstop /* * ICON.CPP * * Functions to create DVASPECT_ICON metafile from filename or classname. * * 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. * OleStdIconLabelTextOut * PointerToNthField * 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 * * (c) Copyright Microsoft Corp. 1992-1993 All Rights Reserved */ #include #include #include #include #include #include #include #include #include "icon.h" static char szMaxWidth[] ="WWWWWWWWWW"; //Strings for metafile comments. static char szIconOnly[]="IconOnly"; //Where to stop to exclude label. #define OLEUI_CCHKEYMAX 256 #define OLEUI_CCHPATHMAX 256 #define OLEUI_CCHLABELMAX 40 #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 char szVanillaDocIcon[] = "DefIcon"; static char szDocument[OLEUI_CCHLABELMAX] = ""; static char szSeparators[] = " \t\\/!:"; static const char szDefIconLabelKey[] = "Software\\Microsoft\\OLE2\\DefaultIconLabel"; #define IS_SEPARATOR(c) ( (c) == ' ' || (c) == '\\' || (c) == '/' || (c) == '\t' || (c) == '!' || (c) == ':' ) #define IS_FILENAME_DELIM(c) ( (c) == '\\' || (c) == '/' || (c) == ':' ) #define LSTRCPYN(lpdst, lpsrc, cch) \ (\ lpdst[cch-1] = '\0', \ lstrcpyn(lpdst, lpsrc, cch-1)\ ) /******* * * 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. * Escape with a comment that is the ASCII of the icon index. * *******/ /* * OleGetIconOfFile(LPSTR lpszPath, BOOL fUseFileAsLabel) * * Purpose: * Returns a hMetaPict containing an icon and label (filename) for the * specified filename. * * Parameters: * lpszPath LPSTR path including filename to use * fUseFileAsLabel BOOL TRUE if the icon's label is the filename, FALSE if * there should be no label. * * Return Value: * HGLOBAL hMetaPict containing the icon and label - if there's no * class in reg db for the file in lpszPath, then we use * Document. If lpszPath is NULL, then we return NULL. */ STDAPI_(HGLOBAL) OleGetIconOfFile(LPSTR lpszPath, BOOL fUseFileAsLabel) { char szIconFile[OLEUI_CCHPATHMAX]; char szLabel[OLEUI_CCHLABELMAX]; LPSTR lpszClsid = NULL; CLSID clsid; HICON hDefIcon = NULL; UINT IconIndex = 0; HGLOBAL hMetaPict; HRESULT hResult; if (NULL == lpszPath) // even if fUseFileAsLabel is FALSE, we still return NULL; // need a valid filename to get the class. hResult = GetClassFile(lpszPath, &clsid); if (NOERROR == hResult) // use the clsid we got to get to the icon { hDefIcon = HIconAndSourceFromClass(clsid, (LPSTR)szIconFile, &IconIndex); } if ( (NOERROR != hResult) || (NULL == hDefIcon) ) { // Here, either GetClassFile failed or HIconAndSourceFromClass failed. LPSTR lpszTemp; lpszTemp = lpszPath; while ((*lpszTemp != '.') && (*lpszTemp != '\0')) lpszTemp++; if ('.' != *lpszTemp) goto UseVanillaDocument; if (FALSE == GetAssociatedExecutable(lpszTemp, (LPSTR)szIconFile)) goto UseVanillaDocument; hDefIcon = ExtractIcon(hmodOLE2, szIconFile, IconIndex); } if (hDefIcon <= (HICON)1) // ExtractIcon returns 1 if szExecutable is not exe, { // 0 if there are no icons. UseVanillaDocument: if (!GetModuleFileName(hmodOLE2, (LPSTR)szIconFile, OLEUI_CCHPATHMAX)) szIconFile[0] = 0; IconIndex = ICONINDEX; hDefIcon = LoadIcon(hmodOLE2, (LPSTR)szVanillaDocIcon); } // Now let's get the label we want to use. if (fUseFileAsLabel) // strip off path, so we just have the filename. { int istrlen; LPSTR lpszBeginFile; istrlen = lstrlen(lpszPath); // set pointer to END of path, so we can walk backwards through it. lpszBeginFile = lpszPath + istrlen -1; while ( (lpszBeginFile >= lpszPath) && (!IS_FILENAME_DELIM(*lpszBeginFile)) ) lpszBeginFile--; lpszBeginFile++; // step back over the delimiter LSTRCPYN(szLabel, lpszBeginFile, sizeof(szLabel)); } else // use the short user type (AuxUserType2) for the label { if (0 == OleStdGetAuxUserType(clsid, AUXUSERTYPE_SHORTNAME, (LPSTR)szLabel, OLEUI_CCHLABELMAX, NULL)) { if ('\0'==szDocument[0]) { LONG cb = sizeof (szDocument); RegQueryValue (HKEY_CLASSES_ROOT, szDefIconLabelKey, szDocument, &cb); // if szDocument is not big enough, RegQueryValue puts a NULL // at the end so we are safe. // if RegQueryValue fails, szDocument[0]=='\0' so we'll use that. } lstrcpy(szLabel, szDocument); } } hMetaPict = OleMetafilePictFromIconAndLabel(hDefIcon, szLabel, (LPSTR)szIconFile, IconIndex); DestroyIcon(hDefIcon); return hMetaPict; } /* * GetAssociatedExecutable * * Purpose: Finds the executable associated with the provided extension * * Parameters: * lpszExtension LPSTR points to the extension we're trying to find an exe * for. Does **NO** validation. * * lpszExecutable LPSTR points to where the exe name will be returned. * No validation here either - pass in 128 char buffer. * * Return: * BOOL TRUE if we found an exe, FALSE if we didn't. * */ BOOL FAR PASCAL GetAssociatedExecutable(LPSTR lpszExtension, LPSTR lpszExecutable) { HKEY hKey; LONG dw; LRESULT lRet; char szValue[OLEUI_CCHKEYMAX]; char szKey[OLEUI_CCHKEYMAX]; LPSTR lpszTemp, lpszExe; lRet = RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey); if (ERROR_SUCCESS != lRet) return FALSE; dw = OLEUI_CCHPATHMAX; lRet = RegQueryValue(hKey, lpszExtension, (LPSTR)szValue, &dw); //ProgId if (ERROR_SUCCESS != lRet) { RegCloseKey(hKey); return FALSE; } // szValue now has ProgID szKey[sizeof(szKey)/sizeof(szKey[0]) - 1] = 0; if ((_snprintf(szKey, sizeof(szKey)/sizeof(szKey[0]), "%s%s", szValue, szKey) < 0) || (szKey[sizeof(szKey)/sizeof(szKey[0]) - 1] != 0)) { RegCloseKey(hKey); return FALSE; } dw = OLEUI_CCHPATHMAX; lRet = RegQueryValue(hKey, (LPSTR)szKey, (LPSTR)szValue, &dw); if (ERROR_SUCCESS != lRet) { RegCloseKey(hKey); return FALSE; } // szValue now has an executable name in it. Let's null-terminate // at the first post-executable space (so we don't have cmd line // args. lpszTemp = (LPSTR)szValue; while (('\0' != *lpszTemp) && (isspace(*lpszTemp))) lpszTemp++; // Strip off leading spaces lpszExe = lpszTemp; while (('\0' != *lpszTemp) && (!isspace(*lpszTemp))) lpszTemp++; // Set through exe name *lpszTemp = '\0'; // null terminate at first space (or at end). lstrcpy(lpszExecutable, lpszExe); return TRUE; } /* * OleGetIconOfClass(REFCLSID rclsid, LPSTR lpszLabel, BOOL fUseTypeAsLabel) * * Purpose: * Returns a hMetaPict containing an icon and label (human-readable form * of class) for the specified clsid. * * Parameters: * rclsid REFCLSID pointing to clsid to use. * lpszLabel label to use for icon. * fUseTypeAsLabel Use the clsid's user type name as the icon's label. * * Return Value: * HGLOBAL hMetaPict containing the icon and label - if we * don't find the clsid in the reg db then we * return NULL. */ STDAPI_(HGLOBAL) OleGetIconOfClass(REFCLSID rclsid, LPSTR lpszLabel, BOOL fUseTypeAsLabel) { char szLabel[OLEUI_CCHLABELMAX]; char szIconFile[OLEUI_CCHPATHMAX]; HICON hDefIcon; UINT IconIndex; HGLOBAL hMetaPict; if (!fUseTypeAsLabel) // Use string passed in as label { if (NULL != lpszLabel) LSTRCPYN(szLabel, lpszLabel, sizeof(szLabel)); else *szLabel = '\0'; } else // Use AuxUserType2 (short name) as label { if (0 == OleStdGetAuxUserType(rclsid, AUXUSERTYPE_SHORTNAME, (LPSTR)szLabel, OLEUI_CCHLABELMAX, NULL)) // If we can't get the AuxUserType2, then try the long name if (0 == OleStdGetUserTypeOfClass(rclsid, szLabel, OLEUI_CCHKEYMAX, NULL)) { if ('\0'==szDocument[0]) { LONG cb = sizeof (szDocument); RegQueryValue (HKEY_CLASSES_ROOT, szDefIconLabelKey, szDocument, &cb); // if RegQueryValue fails, szDocument=="" so we'll use that. } lstrcpy(szLabel, szDocument); // last resort } } // Get the icon, icon index, and path to icon file hDefIcon = HIconAndSourceFromClass(rclsid, (LPSTR)szIconFile, &IconIndex); if (NULL == hDefIcon) // Use Vanilla Document { if (!GetModuleFileName(hmodOLE2, (LPSTR)szIconFile, OLEUI_CCHPATHMAX)) szIconFile[0] = 0; IconIndex = ICONINDEX; hDefIcon = LoadIcon(hmodOLE2, (LPSTR)szVanillaDocIcon); } // Create the metafile hMetaPict = OleMetafilePictFromIconAndLabel(hDefIcon, szLabel, (LPSTR)szIconFile, IconIndex); DestroyIcon(hDefIcon); return hMetaPict; } /* * HIconAndSourceFromClass * * Purpose: * Given an object class name, finds an associated executable in the * registration database and extracts the first icon from that * executable. If none is available or the class has no associated * executable, this function returns NULL. * * Parameters: * rclsid pointer to clsid to look up. * pszSource LPSTR in which to place the source of the icon. * This is assumed to be OLEUI_CCHPATHMAX * puIcon UINT FAR * in which to store the index of the * icon in pszSource. * * Return Value: * HICON Handle to the extracted icon if there is a module * associated to pszClass. NULL on failure to either * find the executable or extract and icon. */ HICON FAR PASCAL HIconAndSourceFromClass(REFCLSID rclsid, LPSTR pszSource, UINT FAR *puIcon) { HICON hIcon; UINT IconIndex; if (CLSID_NULL==rclsid || NULL==pszSource) return NULL; if (!FIconFileFromClass(rclsid, pszSource, OLEUI_CCHPATHMAX, &IconIndex)) return NULL; hIcon=ExtractIcon(hmodOLE2, pszSource, IconIndex); if ((HICON)32 > hIcon) hIcon=NULL; else *puIcon= IconIndex; return hIcon; } /* * FIconFileFromClass * * Purpose: * Looks up the path to executable that contains the class default icon. * * Parameters: * rclsid pointer to CLSID to look up. * pszEXE LPSTR at which to store the server name * cch UINT size of pszEXE * lpIndex LPUINT to index of icon within executable * * Return Value: * BOOL TRUE if one or more characters were loaded into pszEXE. * FALSE otherwise. */ BOOL FAR PASCAL FIconFileFromClass(REFCLSID rclsid, LPSTR pszEXE, UINT cch, UINT FAR *lpIndex) { LONG dw; LONG lRet; HKEY hKey; LPMALLOC lpIMalloc; HRESULT hrErr; LPSTR lpBuffer; LPSTR lpIndexString; UINT cBufferSize = 136; // room for 128 char path and icon's index char szKey[64]; LPSTR pszClass; if (CLSID_NULL==rclsid || NULL==pszEXE || 0==cch) return FALSE; //Here, we use CoGetMalloc and alloc a buffer (maxpathlen + 8) to //pass to RegQueryValue. Then, we copy the exe to pszEXE and the //index to *lpIndex. hrErr = CoGetMalloc(MEMCTX_TASK, &lpIMalloc); if (NOERROR != hrErr) return FALSE; lpBuffer = (LPSTR)lpIMalloc->Alloc(cBufferSize); if (NULL == lpBuffer) { lpIMalloc->Release(); return FALSE; } if (CoIsOle1Class(rclsid)) { LPSTR lpszProgID; // we've got an ole 1.0 class on our hands, so we look at // progID\protocol\stdfileedting\server to get the // name of the executable. ProgIDFromCLSID(rclsid, &lpszProgID); //Open up the class key lRet=RegOpenKey(HKEY_CLASSES_ROOT, lpszProgID, &hKey); if (ERROR_SUCCESS != lRet) { lpIMalloc->Free(lpszProgID); lpIMalloc->Free(lpBuffer); lpIMalloc->Release(); return FALSE; } dw=(LONG)cBufferSize; lRet = RegQueryValue(hKey, "Protocol\\StdFileEditing\\Server", lpBuffer, &dw); if (ERROR_SUCCESS != lRet) { RegCloseKey(hKey); lpIMalloc->Free(lpszProgID); lpIMalloc->Free(lpBuffer); lpIMalloc->Release(); return FALSE; } // Use server and 0 as the icon index LSTRCPYN(pszEXE, lpBuffer, cch); *lpIndex = 0; RegCloseKey(hKey); lpIMalloc->Free(lpszProgID); lpIMalloc->Free(lpBuffer); lpIMalloc->Release(); return TRUE; } /* * We have to go walking in the registration database under the * classname, so we first open the classname key and then check * under "\\DefaultIcon" to get the file that contains the icon. */ StringFromCLSID(rclsid, &pszClass); lstrcpy(szKey, "CLSID\\"); lstrcat(szKey, pszClass); //Open up the class key lRet=RegOpenKey(HKEY_CLASSES_ROOT, szKey, &hKey); if (ERROR_SUCCESS != lRet) { lpIMalloc->Free(lpBuffer); lpIMalloc->Free(pszClass); lpIMalloc->Release(); return FALSE; } //Get the executable path and icon index. dw=(LONG)cBufferSize; lRet=RegQueryValue(hKey, "DefaultIcon", lpBuffer, &dw); if (ERROR_SUCCESS != lRet) { // no DefaultIcon key...try LocalServer dw=(LONG)cBufferSize; lRet=RegQueryValue(hKey, "LocalServer", lpBuffer, &dw); if (ERROR_SUCCESS != lRet) { // no LocalServer entry either...they're outta luck. RegCloseKey(hKey); lpIMalloc->Free(lpBuffer); lpIMalloc->Free(pszClass); lpIMalloc->Release(); return FALSE; } // Use server from LocalServer or Server and 0 as the icon index LSTRCPYN(pszEXE, lpBuffer, cch); *lpIndex = 0; RegCloseKey(hKey); lpIMalloc->Free(lpBuffer); lpIMalloc->Free(pszClass); lpIMalloc->Release(); return TRUE; } RegCloseKey(hKey); // lpBuffer contains a string that looks like ",", // so we need to separate the path and the icon index. lpIndexString = PointerToNthField(lpBuffer, 2, ','); if ('\0' == *lpIndexString) // no icon index specified - use 0 as default. { *lpIndex = 0; } else { LPSTR lpTemp; static char szTemp[16]; LSTRCPYN(((LPSTR)szTemp), lpIndexString, sizeof(szTemp)); // Put the icon index part into *pIconIndex *lpIndex = atoi((const char *)szTemp); // Null-terminate the exe part. lpTemp = AnsiPrev(lpBuffer, lpIndexString); *lpTemp = '\0'; } if (!LSTRCPYN(pszEXE, lpBuffer, cch)) { lpIMalloc->Free(lpBuffer); lpIMalloc->Free(pszClass); lpIMalloc->Release(); return FALSE; } // Free the memory we alloc'd and leave. lpIMalloc->Free(lpBuffer); lpIMalloc->Free(pszClass); lpIMalloc->Release(); return TRUE; } /* * OleMetafilePictFromIconAndLabel * * Purpose: * Creates a METAFILEPICT structure that container a metafile in which * the icon and label are drawn. A comment record is inserted between * the icon and the label code so our special draw function can stop * playing before the label. * * Parameters: * hIcon HICON to draw into the metafile * pszLabel LPSTR to the label string. * pszSourceFile LPSTR containing the local pathname of the icon * as we either get from the user or from the reg DB. * iIcon UINT providing the index into pszSourceFile where * the icon came from. * * Return Value: * HGLOBAL Global memory handle containing a METAFILEPICT where * the metafile uses the MM_ANISOTROPIC mapping mode. The * extents reflect both icon and label. */ STDAPI_(HGLOBAL) OleMetafilePictFromIconAndLabel(HICON hIcon, LPSTR pszLabel , LPSTR pszSourceFile, UINT iIcon) { HDC hDC, hDCScreen; HMETAFILE hMF; HGLOBAL hMem; LPMETAFILEPICT pMF; UINT cxIcon, cyIcon; UINT cxText, cyText; UINT cx, cy; UINT cchLabel = 0; HFONT hFont, hSysFont, hFontT; int cyFont; char szIndex[10]; RECT TextRect; SIZE size; POINT point; LOGFONT logfont; if (NULL==hIcon) // null icon is valid return NULL; //Create a memory metafile hDC=(HDC)CreateMetaFile(NULL); if (NULL==hDC) return NULL; //Allocate the metafilepict hMem=GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, sizeof(METAFILEPICT)); if (NULL==hMem) { hMF=CloseMetaFile(hDC); DeleteMetaFile(hMF); return NULL; } if (NULL!=pszLabel) { cchLabel=lstrlen(pszLabel); if (cchLabel >= OLEUI_CCHLABELMAX) pszLabel[cchLabel] = '\0'; // truncate string } //Need to use the screen DC for these operations hDCScreen=GetDC(NULL); cyFont=-(8*GetDeviceCaps(hDCScreen, LOGPIXELSY))/72; //cyFont was calculated to give us 8 point. // We use the system font as the basis for the character set, // allowing us to handle DBCS strings better hSysFont = GetStockObject( SYSTEM_FONT ); GetObject(hSysFont, sizeof(LOGFONT), &logfont); hFont=CreateFont(cyFont, 5, 0, 0, FW_NORMAL, 0, 0, 0, logfont.lfCharSet , OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY , FF_SWISS, "MS Sans Serif"); hFontT=SelectObject(hDCScreen, hFont); GetTextExtentPoint(hDCScreen,szMaxWidth,lstrlen(szMaxWidth),&size); SelectObject(hDCScreen, hFontT); cxText = size.cx; cyText = size.cy * 2; cxIcon = GetSystemMetrics(SM_CXICON); cyIcon = GetSystemMetrics(SM_CYICON); // If we have no label, then we want the metafile to be the width of // the icon (plus margin), not the width of the fattest string. if ( (NULL == pszLabel) || (NULL == *pszLabel) ) cx = cxIcon + cxIcon / 4; else cx = max(cxText, cxIcon); cy=cyIcon+cyText+4; //Set the metafile size to fit the icon and label SetWindowOrgEx(hDC, 0, 0, &point); SetWindowExtEx(hDC, cx, cy, &size); //Set up rectangle to pass to OleStdIconLabelTextOut SetRectEmpty(&TextRect); TextRect.right = cx; TextRect.bottom = cy; //Draw the icon and the text, centered with respect to each other. DrawIcon(hDC, (cx-cxIcon)/2, 0, hIcon); //String that indicates where to stop if we're only doing icons Escape(hDC, MFCOMMENT, lstrlen(szIconOnly)+1, szIconOnly, NULL); SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT)); SetBkMode(hDC, TRANSPARENT); OleStdIconLabelTextOut(hDC, hFont, 0, cy - cyText, ETO_CLIPPED, &TextRect, pszLabel, cchLabel, NULL); //Write comments containing the icon source file and index. if (NULL!=pszSourceFile) { //+1 on string lengths insures the null terminator is embedded. Escape(hDC, MFCOMMENT, lstrlen(pszSourceFile)+1, pszSourceFile, NULL); cchLabel=wsprintf(szIndex, "%u", iIcon); Escape(hDC, MFCOMMENT, cchLabel+1, szIndex, NULL); } //All done with the metafile, now stuff it all into a METAFILEPICT. hMF=CloseMetaFile(hDC); if (NULL==hMF) { GlobalFree(hMem); ReleaseDC(NULL, hDCScreen); return NULL; } //Fill out the structure pMF=(LPMETAFILEPICT)GlobalLock(hMem); //Transform to HIMETRICS cx=XformWidthInPixelsToHimetric(hDCScreen, cx); cy=XformHeightInPixelsToHimetric(hDCScreen, cy); ReleaseDC(NULL, hDCScreen); pMF->mm=MM_ANISOTROPIC; pMF->xExt=cx; pMF->yExt=cy; pMF->hMF=hMF; GlobalUnlock(hMem); DeleteObject(hFont); return hMem; } /* * OleStdIconLabelTextOut * * Purpose: * Replacement for DrawText to be used in the "Display as Icon" metafile. * Uses ExtTextOut to output a string center on (at most) two lines. * Uses a very simple word wrap algorithm to split the lines. * * Parameters: (same as for ExtTextOut, except for hFont) * hDC device context to draw into; if this is NULL, then we don't * ETO the text, we just return the index of the beginning * of the second line * hFont font to use * nXStart x-coordinate of starting position * nYStart y-coordinate of starting position * fuOptions rectangle type * lpRect rect far * containing rectangle to draw text in. * lpszString string to draw * cchString length of string (truncated if over OLEUI_CCHLABELMAX) * lpDX spacing between character cells * * Return Value: * UINT Index of beginning of last line (0 if there's only one * line of text). * */ STDAPI_(UINT) OleStdIconLabelTextOut(HDC hDC, HFONT hFont, int nXStart, int nYStart, UINT fuOptions, RECT FAR * lpRect, LPSTR lpszString, UINT cchString, int FAR * lpDX) { HDC hDCScreen; static char szTempBuff[OLEUI_CCHLABELMAX]; int cxString, cyString, cxMaxString; int cxFirstLine, cyFirstLine, cxSecondLine; int index; int cch = cchString; char chKeep; LPSTR lpszSecondLine; HFONT hFontT; BOOL fPrintText = TRUE; UINT iLastLineStart = 0; SIZE size; // Initialization stuff... if (NULL == hDC) // If we got NULL as the hDC, then we don't actually call ETO fPrintText = FALSE; // Make a copy of the string (NULL or non-NULL) that we're using if (NULL == lpszString) *szTempBuff = '\0'; else LSTRCPYN(szTempBuff, lpszString, sizeof(szTempBuff)); // set maximum width cxMaxString = lpRect->right - lpRect->left; // get screen DC to do text size calculations hDCScreen = GetDC(NULL); hFontT=SelectObject(hDCScreen, hFont); // get the extent of our label GetTextExtentPoint(hDCScreen, szTempBuff, cch, &size); cxString = size.cx; cyString = size.cy; // Select in the font we want to use if (fPrintText) SelectObject(hDC, hFont); // String is smaller than max string - just center, ETO, and return. if (cxString <= cxMaxString) { if (fPrintText) ExtTextOut(hDC, nXStart + (lpRect->right - cxString) / 2, nYStart, fuOptions, lpRect, szTempBuff, cch, NULL); iLastLineStart = 0; // only 1 line of text goto CleanupAndLeave; } // String is too long...we've got to word-wrap it. // Are there any spaces, slashes, tabs, or bangs in string? if (lstrlen(szTempBuff) != (int)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) { char cchKeep; // scan the string backwards for spaces, slashes, tabs, or bangs while (!IS_SEPARATOR(szTempBuff[index]) ) index--; if (index <= 0) break; cchKeep = szTempBuff[index]; // remember what char was there szTempBuff[index] = '\0'; // just for now GetTextExtentPoint( hDCScreen, (LPSTR)szTempBuff,lstrlen((LPSTR)szTempBuff),&size); cxFirstLine = size.cx; cyFirstLine = size.cy; szTempBuff[index] = cchKeep; // put the right char back if (cxFirstLine <= cxMaxString) { iLastLineStart = index + 1; if (!fPrintText) goto CleanupAndLeave; ExtTextOut(hDC, nXStart + (lpRect->right - cxFirstLine) / 2, nYStart, fuOptions, lpRect, (LPSTR)szTempBuff, index + 1, lpDX); lpszSecondLine = (LPSTR)szTempBuff; lpszSecondLine += index + 1; GetTextExtentPoint(hDCScreen, lpszSecondLine, lstrlen(lpszSecondLine), &size); // If the second line is wider than the rectangle, we // just want to clip the text. cxSecondLine = min(size.cx, cxMaxString); ExtTextOut(hDC, nXStart + (lpRect->right - cxSecondLine) / 2, nYStart + cyFirstLine, fuOptions, lpRect, lpszSecondLine, lstrlen(lpszSecondLine), lpDX); goto CleanupAndLeave; } // end if index--; } // end while } // end if // Here, there are either no spaces in the string (strchr(szTempBuff, ' ') // returned NULL), or there spaces in the string, but they are // positioned so that the first space terminated string is still // longer than one line. So, we walk backwards from the end of the // string until we find the largest string that will fit on the first // line , and then we just clip the second line. cch = lstrlen((LPSTR)szTempBuff); chKeep = szTempBuff[cch]; szTempBuff[cch] = '\0'; GetTextExtentPoint(hDCScreen, szTempBuff, lstrlen(szTempBuff),&size); cxFirstLine = size.cx; cyFirstLine = size.cy; while (cxFirstLine > cxMaxString) { // We allow 40 characters in the label, but the metafile is // only as wide as 10 W's (for aesthetics - 20 W's wide looked // dumb. This means that if we split a long string in half (in // terms of characters), then we could still be wider than the // metafile. So, if this is the case, we just step backwards // from the halfway point until we get something that will fit. // Since we just let ETO clip the second line szTempBuff[cch--] = chKeep; if (0 == cch) goto CleanupAndLeave; chKeep = szTempBuff[cch]; szTempBuff[cch] = '\0'; GetTextExtentPoint( hDCScreen, szTempBuff, lstrlen(szTempBuff), &size); cxFirstLine = size.cx; } iLastLineStart = cch; if (!fPrintText) goto CleanupAndLeave; ExtTextOut(hDC, nXStart + (lpRect->right - cxFirstLine) / 2, nYStart, fuOptions, lpRect, (LPSTR)szTempBuff, lstrlen((LPSTR)szTempBuff), lpDX); szTempBuff[cch] = chKeep; lpszSecondLine = szTempBuff; lpszSecondLine += cch; GetTextExtentPoint( hDCScreen, (LPSTR)lpszSecondLine, lstrlen(lpszSecondLine), &size); // If the second line is wider than the rectangle, we // just want to clip the text. cxSecondLine = min(size.cx, cxMaxString); ExtTextOut(hDC, nXStart + (lpRect->right - cxSecondLine) / 2, nYStart + cyFirstLine, fuOptions, lpRect, lpszSecondLine, lstrlen(lpszSecondLine), lpDX); CleanupAndLeave: SelectObject(hDCScreen, hFontT); ReleaseDC(NULL, hDCScreen); return iLastLineStart; } /* * OleStdGetUserTypeOfClass(REFCLSID, LPSTR, UINT, HKEY) * * Purpose: * Returns the user type (human readable class name) of the specified class. * * Parameters: * rclsid pointer to the clsid to retrieve user type of. * lpszUserType pointer to buffer to return user type in. * cch length of buffer pointed to by lpszUserType * hKey hKey for reg db - if this is NULL, then we * open and close the reg db within this function. If it * is non-NULL, then we assume it's a valid key to the * \ root and use it without closing it. (useful * if you're doing lots of reg db stuff). * * Return Value: * UINT Number of characters in returned string. 0 on error. * */ STDAPI_(UINT) OleStdGetUserTypeOfClass(REFCLSID rclsid, LPSTR lpszUserType, UINT cch, HKEY hKey) { LONG dw; LONG lRet; LPSTR lpszCLSID, lpszProgID; BOOL fFreeProgID = FALSE; BOOL bCloseRegDB = FALSE; char szKey[128]; LPMALLOC lpIMalloc; if (hKey == NULL) { //Open up the root key. lRet=RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey); if ((LONG)ERROR_SUCCESS!=lRet) return (UINT)FALSE; bCloseRegDB = TRUE; } // Get a string containing the class name StringFromCLSID(rclsid, &lpszCLSID); wsprintf(szKey, "CLSID\\%s", lpszCLSID); dw=cch; lRet = RegQueryValue(hKey, szKey, lpszUserType, &dw); if ((LONG)ERROR_SUCCESS!=lRet) dw = 0; if ( ((LONG)ERROR_SUCCESS!=lRet) && (CoIsOle1Class(rclsid)) ) { // 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); fFreeProgID = TRUE; dw = cch; lRet = RegQueryValue(hKey, lpszProgID, lpszUserType, &dw); if ((LONG)ERROR_SUCCESS != lRet) dw = 0; } if (NOERROR == CoGetMalloc(MEMCTX_TASK, &lpIMalloc)) { if (fFreeProgID) lpIMalloc->Free((LPVOID)lpszProgID); lpIMalloc->Free((LPVOID)lpszCLSID); lpIMalloc->Release(); } if (bCloseRegDB) RegCloseKey(hKey); return (UINT)dw; } /* * OleStdGetAuxUserType(RCLSID, WORD, LPSTR, int, HKEY) * * Purpose: * Returns the specified AuxUserType from the reg db. * * Parameters: * rclsid pointer to the clsid to retrieve aux user type of. * hKey hKey for reg db - if this is NULL, then we * open and close the reg db within this function. If it * is non-NULL, then we assume it's a valid key to the * \ root and use it without closing it. (useful * if you're doing lots of reg db stuff). * wAuxUserType which aux user type field to look for. In 4/93 release * 2 is short name and 3 is exe name. * lpszUserType pointer to buffer to return user type in. * cch length of buffer pointed to by lpszUserType * * Return Value: * UINT Number of characters in returned string. 0 on error. * */ STDAPI_(UINT) OleStdGetAuxUserType(REFCLSID rclsid, WORD wAuxUserType, LPSTR lpszAuxUserType, int cch, HKEY hKey) { HKEY hThisKey; BOOL fCloseRegDB = FALSE; LONG dw; LRESULT lRet; LPSTR lpszCLSID; LPMALLOC lpIMalloc; char szKey[OLEUI_CCHKEYMAX]; char szTemp[32]; lpszAuxUserType[0] = '\0'; if (NULL == hKey) { lRet = RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hThisKey); if (ERROR_SUCCESS != lRet) return 0; } else hThisKey = hKey; StringFromCLSID(rclsid, &lpszCLSID); lstrcpy(szKey, "CLSID\\"); lstrcat(szKey, lpszCLSID); wsprintf(szTemp, "\\AuxUserType\\%d", wAuxUserType); lstrcat(szKey, szTemp); dw = cch; lRet = RegQueryValue(hThisKey, szKey, lpszAuxUserType, &dw); if (ERROR_SUCCESS != lRet) { dw = 0; lpszAuxUserType[0] = '\0'; } if (fCloseRegDB) RegCloseKey(hThisKey); if (NOERROR == CoGetMalloc(MEMCTX_TASK, &lpIMalloc)) { lpIMalloc->Free((LPVOID)lpszCLSID); lpIMalloc->Release(); } return (UINT)dw; } /* * PointerToNthField * * Purpose: * Returns a pointer to the beginning of the nth field. * Assumes null-terminated string. * * Parameters: * lpszString string to parse * nField field to return starting index of. * chDelimiter char that delimits fields * * Return Value: * LPSTR pointer to beginning of nField field. * NOTE: If the null terminator is found * Before we find the Nth field, then * we return a pointer to the null terminator - * calling app should be sure to check for * this case. * */ LPSTR FAR PASCAL PointerToNthField(LPSTR lpszString, int nField, char chDelimiter) { LPSTR lpField = lpszString; int cFieldFound = 1; if (1 ==nField) return lpszString; while (*lpField != '\0') { if (*lpField++ == chDelimiter) { cFieldFound++; if (nField == cFieldFound) return lpField; } } return lpField; } /* * XformWidthInPixelsToHimetric * XformWidthInHimetricToPixels * XformHeightInPixelsToHimetric * XformHeightInHimetricToPixels * * Functions to convert an int between a device coordinate system and * logical HiMetric units. * * Parameters: * 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. * * Return Value: * Size Functions: None * Width Functions: Converted value of the input parameters. * * NOTE: * 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 * */ STDAPI_(int) XformWidthInPixelsToHimetric(HDC hDC, int iWidthInPix) { int iXppli; //Pixels per logical inch along width int iWidthInHiMetric; BOOL fSystemDC=FALSE; if (NULL==hDC) { hDC=GetDC(NULL); fSystemDC=TRUE; } 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); return iWidthInHiMetric; } STDAPI_(int) XformWidthInHimetricToPixels(HDC hDC, int iWidthInHiMetric) { int iXppli; //Pixels per logical inch along width int iWidthInPix; BOOL fSystemDC=FALSE; if (NULL==hDC) { hDC=GetDC(NULL); fSystemDC=TRUE; } 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); return iWidthInPix; } STDAPI_(int) XformHeightInPixelsToHimetric(HDC hDC, int iHeightInPix) { int iYppli; //Pixels per logical inch along height int iHeightInHiMetric; BOOL fSystemDC=FALSE; if (NULL==hDC) { hDC=GetDC(NULL); fSystemDC=TRUE; } 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); return iHeightInHiMetric; } STDAPI_(int) XformHeightInHimetricToPixels(HDC hDC, int iHeightInHiMetric) { int iYppli; //Pixels per logical inch along height int iHeightInPix; BOOL fSystemDC=FALSE; if (NULL==hDC) { hDC=GetDC(NULL); fSystemDC=TRUE; } 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); return iHeightInPix; }