/* * UTILITY.CPP * * Utility routines for functions inside OLEDLG.DLL * * General: * ---------------------- * HourGlassOn Displays the hourglass * HourGlassOff Hides the hourglass * * Misc Tools: * ---------------------- * Browse Displays the "File..." or "Browse..." dialog. * ReplaceCharWithNull Used to form filter strings for Browse. * ErrorWithFile Creates an error message with embedded filename * OpenFileError Give error message for OpenFile error return * ChopText Chop a file path to fit within a specified width * DoesFileExist Checks if file is valid * * * Copyright (c)1992 Microsoft Corporation, All Right Reserved */ #include "precomp.h" #include "common.h" #include #include #include #include #include "utility.h" OLEDBGDATA /* * HourGlassOn * * Purpose: * Shows the hourglass cursor returning the last cursor in use. * * Parameters: * None * * Return Value: * HCURSOR Cursor in use prior to showing the hourglass. */ HCURSOR WINAPI HourGlassOn(void) { HCURSOR hCur; hCur=SetCursor(LoadCursor(NULL, IDC_WAIT)); ShowCursor(TRUE); return hCur; } /* * HourGlassOff * * Purpose: * Turns off the hourglass restoring it to a previous cursor. * * Parameters: * hCur HCURSOR as returned from HourGlassOn * * Return Value: * None */ void WINAPI HourGlassOff(HCURSOR hCur) { ShowCursor(FALSE); SetCursor(hCur); return; } /* * Browse * * Purpose: * Displays the standard GetOpenFileName dialog with the title of * "Browse." The types listed in this dialog are controlled through * iFilterString. If it's zero, then the types are filled with "*.*" * Otherwise that string is loaded from resources and used. * * Parameters: * hWndOwner HWND owning the dialog * lpszFile LPSTR specifying the initial file and the buffer in * which to return the selected file. If there is no * initial file the first character of this string should * be NULL. * lpszInitialDir LPSTR specifying the initial directory. If none is to * set (ie, the cwd should be used), then this parameter * should be NULL. * cchFile UINT length of pszFile * iFilterString UINT index into the stringtable for the filter string. * dwOfnFlags DWORD flags to OR with OFN_HIDEREADONLY * nBrowseID * lpfnHook Callback Hook Proceedure. Set if OFN_ENABLE_HOOK is * in dwOfnFlags else it should be NULL. * * Return Value: * BOOL TRUE if the user selected a file and pressed OK. * FALSE otherwise, such as on pressing Cancel. */ BOOL WINAPI Browse(HWND hWndOwner, LPTSTR lpszFile, LPTSTR lpszInitialDir, UINT cchFile, UINT iFilterString, DWORD dwOfnFlags, UINT nBrowseID, LPOFNHOOKPROC lpfnHook) { UINT cch; TCHAR szFilters[256]; TCHAR szDlgTitle[128]; // that should be big enough if (NULL == lpszFile || 0 == cchFile) return FALSE; /* * Exact contents of the filter combobox is TBD. One idea * is to take all the extensions in the RegDB and place them in here * with the descriptive class name associate with them. This has the * extra step of finding all extensions of the same class handler and * building one extension string for all of them. Can get messy quick. * UI demo has only *.* which we do for now. */ if (0 != iFilterString) { cch = LoadString(_g_hOleStdResInst, iFilterString, szFilters, sizeof(szFilters)/sizeof(TCHAR)); } else { szFilters[0] = 0; cch = 1; } if (0 == cch) return FALSE; ReplaceCharWithNull(szFilters, szFilters[cch-1]); // Prior string must also be initialized, if there is one. OPENFILENAME ofn; memset(&ofn, 0, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = hWndOwner; ofn.lpstrFile = lpszFile; ofn.nMaxFile = cchFile; ofn.lpstrFilter = szFilters; ofn.nFilterIndex = 1; ofn.lpfnHook = lpfnHook; if (LoadString(_g_hOleStdResInst, IDS_BROWSE, szDlgTitle, sizeof(szDlgTitle)/sizeof(TCHAR))) ofn.lpstrTitle = szDlgTitle; ofn.hInstance = _g_hOleStdResInst; if (NULL != lpszInitialDir) ofn.lpstrInitialDir = lpszInitialDir; ofn.Flags = OFN_HIDEREADONLY | dwOfnFlags; if (bWin4) ofn.Flags |= OFN_EXPLORER; // Lastly, parent to tweak OFN parameters if (hWndOwner != NULL) SendMessage(hWndOwner, uMsgBrowseOFN, nBrowseID, (LPARAM)&ofn); // On success, copy the chosen filename to the static display BOOL bResult = StandardGetOpenFileName((LPOPENFILENAME)&ofn); return bResult; } /* * ReplaceCharWithNull * * Purpose: * Walks a null-terminated string and replaces a given character * with a zero. Used to turn a single string for file open/save * filters into the appropriate filter string as required by the * common dialog API. * * Parameters: * psz LPTSTR to the string to process. * ch int character to replace. * * Return Value: * int Number of characters replaced. -1 if psz is NULL. */ int WINAPI ReplaceCharWithNull(LPTSTR psz, int ch) { int cChanged = 0; if (psz == NULL) return -1; while ('\0' != *psz) { if (ch == *psz) { *psz++ = '\0'; cChanged++; continue; } psz = CharNext(psz); } return cChanged; } /* * ErrorWithFile * * Purpose: * Displays a message box built from a stringtable string containing * one %s as a placeholder for a filename and from a string of the * filename to place there. * * Parameters: * hWnd HWND owning the message box. The caption of this * window is the caption of the message box. * hInst HINSTANCE from which to draw the idsErr string. * idsErr UINT identifier of a stringtable string containing * the error message with a %s. * lpszFile LPSTR to the filename to include in the message. * uFlags UINT flags to pass to MessageBox, like MB_OK. * * Return Value: * int Return value from MessageBox. */ int WINAPI ErrorWithFile(HWND hWnd, HINSTANCE hInst, UINT idsErr, LPTSTR pszFile, UINT uFlags) { int iRet=0; HANDLE hMem; const UINT cb = (2*MAX_PATH); LPTSTR psz1, psz2, psz3; if (NULL == hInst || NULL == pszFile) return iRet; // Allocate three 2*MAX_PATH byte work buffers hMem=GlobalAlloc(GHND, (DWORD)(3*cb)*sizeof(TCHAR)); if (NULL==hMem) return iRet; psz1 = (LPTSTR)GlobalLock(hMem); psz2 = psz1+cb; psz3 = psz2+cb; if (0 != LoadString(hInst, idsErr, psz1, cb)) { wsprintf(psz2, psz1, pszFile); // Steal the caption of the dialog GetWindowText(hWnd, psz3, cb); iRet=MessageBox(hWnd, psz2, psz3, uFlags); } GlobalUnlock(hMem); GlobalFree(hMem); return iRet; } // returns width of line of text. this is a support routine for ChopText static LONG GetTextWSize(HDC hDC, LPTSTR lpsz) { SIZE size; if (GetTextExtentPoint(hDC, lpsz, lstrlen(lpsz), (LPSIZE)&size)) return size.cx; else return 0; } LPTSTR FindChar(LPTSTR lpsz, TCHAR ch) { while (*lpsz != 0) { if (*lpsz == ch) return lpsz; lpsz = CharNext(lpsz); } return NULL; } LPTSTR FindReverseChar(LPTSTR lpsz, TCHAR ch) { LPTSTR lpszLast = NULL; while (*lpsz != 0) { if (*lpsz == ch) lpszLast = lpsz; lpsz = CharNext(lpsz); } return lpszLast; } static void WINAPI Abbreviate(HDC hdc, int nWidth, LPTSTR lpch, int nMaxChars) { /* string is too long to fit; chop it */ /* set up new prefix & determine remaining space in control */ LPTSTR lpszFileName = NULL; LPTSTR lpszCur = CharNext(CharNext(lpch)); lpszCur = FindChar(lpszCur, TEXT('\\')); // algorithm will insert \... so allocate extra 4 LPTSTR lpszNew = (LPTSTR)OleStdMalloc((lstrlen(lpch)+5) * sizeof(TCHAR)); if (lpszNew == NULL) return; if (lpszCur != NULL) // at least one backslash { *lpszNew = (TCHAR)0; *lpszCur = (TCHAR)0; lstrcpy(lpszNew, lpch); *lpszCur = TEXT('\\'); // lpszNew now contains c: or \\servername lstrcat(lpszNew, TEXT("\\...")); // lpszNew now contains c:\... or \\servername\... LPTSTR lpszEnd = lpszNew; while (*lpszEnd != (TCHAR)0) lpszEnd = CharNext(lpszEnd); // lpszEnd is now at the end of c:\... or \\servername\... // move down directories until it fits or no more directories while (lpszCur != NULL) { *lpszEnd = (TCHAR)0; lstrcat(lpszEnd, lpszCur); if (GetTextWSize(hdc, lpszNew) <= nWidth && lstrlen(lpszNew) < nMaxChars) { lstrcpyn(lpch, lpszNew, nMaxChars); OleStdFree(lpszNew); return; } lpszCur = CharNext(lpszCur); // advance past backslash lpszCur = FindChar(lpszCur, TEXT('\\')); } // try just ...filename and then shortening filename lpszFileName = FindReverseChar(lpch, TEXT('\\')); } else lpszFileName = lpch; while (*lpszFileName != (TCHAR)0) { lstrcpy(lpszNew, TEXT("...")); lstrcat(lpszNew, lpszFileName); if (GetTextWSize(hdc, lpszNew) <= nWidth && lstrlen(lpszNew) < nMaxChars) { lstrcpyn(lpch, lpszNew, nMaxChars); OleStdFree(lpszNew); return; } lpszFileName = CharNext(lpszFileName); } OleStdFree(lpszNew); // not even a single character fit *lpch = (TCHAR)0; } /* * ChopText * * Purpose: * Parse a string (pathname) and convert it to be within a specified * length by chopping the least significant part * * Parameters: * hWnd window handle in which the string resides * nWidth max width of string in pixels * use width of hWnd if zero * lpch pointer to beginning of the string * nMaxChars maximum allowable number of characters (0 ignore) * * Return Value: * pointer to the modified string */ LPTSTR WINAPI ChopText(HWND hWnd, int nWidth, LPTSTR lpch, int nMaxChars) { HDC hdc; HFONT hfont; HFONT hfontOld = NULL; RECT rc; if (!hWnd || !lpch) return NULL; if (nMaxChars == 0) nMaxChars = 32768; // big number /* Get length of static field. */ if (!nWidth) { GetClientRect(hWnd, (LPRECT)&rc); nWidth = rc.right - rc.left; } /* Set up DC appropriately for the static control */ hdc = CreateIC(TEXT("DISPLAY"), NULL, NULL, NULL); hfont = (HFONT)SendMessage(hWnd, WM_GETFONT, 0, 0L); if (NULL != hfont) // WM_GETFONT returns NULL if window uses system font hfontOld = (HFONT)SelectObject(hdc, hfont); /* check horizontal extent of string */ if (GetTextWSize(hdc, lpch) > nWidth || lstrlen(lpch) >= nMaxChars) Abbreviate(hdc, nWidth, lpch, nMaxChars); if (NULL != hfont) SelectObject(hdc, hfontOld); DeleteDC(hdc); return lpch; } /* * OpenFileError * * Purpose: * display message for error returned from OpenFile * * Parameters: * hDlg HWND of the dialog. * nErrCode UINT error code returned in OFSTRUCT passed to OpenFile * lpszFile LPSTR file name passed to OpenFile * * Return Value: * None */ void WINAPI OpenFileError(HWND hDlg, UINT nErrCode, LPTSTR lpszFile) { switch (nErrCode) { case 0x0005: // Access denied ErrorWithFile(hDlg, _g_hOleStdResInst, IDS_CIFILEACCESS, lpszFile, MB_OK | MB_ICONEXCLAMATION); break; case 0x0020: // Sharing violation ErrorWithFile(hDlg, _g_hOleStdResInst, IDS_CIFILESHARE, lpszFile, MB_OK | MB_ICONEXCLAMATION); break; case 0x0002: // File not found case 0x0003: // Path not found ErrorWithFile(hDlg, _g_hOleStdResInst, IDS_CIINVALIDFILE, lpszFile, MB_OK | MB_ICONEXCLAMATION); break; default: ErrorWithFile(hDlg, _g_hOleStdResInst, IDS_CIFILEOPENFAIL, lpszFile, MB_OK | MB_ICONEXCLAMATION); break; } } /* * DoesFileExist * * Purpose: * Determines if a file path exists * * Parameters: * lpszFile LPTSTR - file name * cchMax UINT - size of the lpszFile string buffer in characters. * * Return Value: * BOOL TRUE if file exists, else FALSE. * * NOTE: lpszFile may be changed as a result of this call to match the first * matching file name found by this routine. * */ BOOL WINAPI DoesFileExist(LPTSTR lpszFile, UINT cchMax) { static const TCHAR *arrIllegalNames[] = { TEXT("LPT1"), TEXT("LPT2"), TEXT("LPT3"), TEXT("COM1"), TEXT("COM2"), TEXT("COM3"), TEXT("COM4"), TEXT("CON"), TEXT("AUX"), TEXT("PRN") }; // check is the name is an illegal name (eg. the name of a device) for (int i = 0; i < (sizeof(arrIllegalNames)/sizeof(arrIllegalNames[0])); i++) { if (lstrcmpi(lpszFile, arrIllegalNames[i])==0) return FALSE; } // First try to find the file with an exact match // check the file's attributes DWORD dwAttrs = GetFileAttributes(lpszFile); if (dwAttrs == 0xFFFFFFFF) // file wasn't found { // look in path for file TCHAR szTempFileName[MAX_PATH]; LPTSTR lpszFilePart; BOOL fFound = SearchPath(NULL, lpszFile, NULL, MAX_PATH, szTempFileName, &lpszFilePart) != 0; if (!fFound) { // File wasn't found in the search path // Try to append a .* and use FindFirstFile to try for a match in the current directory UINT cchFile = lstrlen(lpszFile); if (cchFile + 4 < MAX_PATH) { WIN32_FIND_DATA sFindFileData; lstrcpy(szTempFileName,lpszFile); lstrcpy(&szTempFileName[cchFile], TEXT("*.*")); HANDLE hFindFile = FindFirstFile(szTempFileName, &sFindFileData); if (INVALID_HANDLE_VALUE != hFindFile) { // found something while (0 != sFindFileData.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_TEMPORARY)) { // found a directory or a temporary file try again if (!FindNextFile(hFindFile, &sFindFileData)) { // Could only match a directory or temporary file. FindClose(hFindFile); return(FALSE); } } // Copy the name of the found file into the end of the path in the // temporary buffer (if any). // First scan back for the last file separator. UINT cchPath = lstrlen(szTempFileName); while (cchPath) { if (_T('\\') == szTempFileName[cchPath - 1] || _T('/') == szTempFileName[cchPath - 1]) { break; } cchPath--; } lstrcpyn(&szTempFileName[cchPath], sFindFileData.cFileName, MAX_PATH - cchPath); fFound = TRUE; FindClose(hFindFile); } } } if (fFound) { // copy the temporary buffer into szFile lstrcpyn(lpszFile, szTempFileName, cchMax -1); } return(fFound); } else if (dwAttrs & (FILE_ATTRIBUTE_DIRECTORY| FILE_ATTRIBUTE_TEMPORARY)) { return FALSE; } return TRUE; } /* * FormatStrings * * Purpose: * Simple message formatting API compatible w/ different languages * * Note: * Shamelessly stolen/modified from MFC source code * */ void WINAPI FormatStrings(LPTSTR lpszDest, LPCTSTR lpszFormat, LPCTSTR* rglpsz, int nString) { LPCTSTR pchSrc = lpszFormat; while (*pchSrc != '\0') { if (pchSrc[0] == '%' && (pchSrc[1] >= '1' && pchSrc[1] <= '9')) { int i = pchSrc[1] - '1'; pchSrc += 2; if (i >= nString) *lpszDest++ = '?'; else if (rglpsz[i] != NULL) { lstrcpy(lpszDest, rglpsz[i]); lpszDest += lstrlen(lpszDest); } } else { #ifndef _UNICODE if (IsDBCSLeadByte(*pchSrc)) *lpszDest++ = *pchSrc++; // copy first of 2 bytes #endif *lpszDest++ = *pchSrc++; } } *lpszDest = '\0'; } void WINAPI FormatString1(LPTSTR lpszDest, LPCTSTR lpszFormat, LPCTSTR lpsz1) { FormatStrings(lpszDest, lpszFormat, &lpsz1, 1); } void WINAPI FormatString2(LPTSTR lpszDest, LPCTSTR lpszFormat, LPCTSTR lpsz1, LPCTSTR lpsz2) { LPCTSTR rglpsz[2]; rglpsz[0] = lpsz1; rglpsz[1] = lpsz2; FormatStrings(lpszDest, lpszFormat, rglpsz, 2); } // Replacement for stdlib atol, // which didn't work and doesn't take far pointers. // Must be tolerant of leading spaces. // // LONG WINAPI Atol(LPTSTR lpsz) { signed int sign = +1; UINT base = 10; LONG l = 0; if (NULL==lpsz) { OleDbgAssert (0); return 0; } while (*lpsz == ' ' || *lpsz == '\t' || *lpsz == '\n') lpsz++; if (*lpsz=='-') { lpsz++; sign = -1; } if (lpsz[0] == TEXT('0') && lpsz[1] == TEXT('x')) { base = 16; lpsz+=2; } if (base == 10) { while (*lpsz >= '0' && *lpsz <= '9') { l = l * base + *lpsz - '0'; lpsz++; } } else { OleDbgAssert(base == 16); while (*lpsz >= '0' && *lpsz <= '9' || *lpsz >= 'A' && *lpsz <= 'F' || *lpsz >= 'a' && *lpsz <= 'f') { l = l * base; if (*lpsz >= '0' && *lpsz <= '9') l += *lpsz - '0'; else if (*lpsz >= 'a' && *lpsz <= 'f') l += *lpsz - 'a' + 10; else l += *lpsz - 'A' + 10; lpsz++; } } return l * sign; } BOOL WINAPI IsValidClassID(REFCLSID clsid) { return clsid != CLSID_NULL; } /* PopupMessage * ------------ * * Purpose: * Popup messagebox and get some response from the user. It is the same * as MessageBox() except that the title and message string are loaded * from the resource file. * * Parameters: * hwndParent parent window of message box * idTitle id of title string * idMessage id of message string * fuStyle style of message box */ int WINAPI PopupMessage(HWND hwndParent, UINT idTitle, UINT idMessage, UINT fuStyle) { TCHAR szTitle[256]; TCHAR szMsg[256]; LoadString(_g_hOleStdResInst, idTitle, szTitle, sizeof(szTitle)/sizeof(TCHAR)); LoadString(_g_hOleStdResInst, idMessage, szMsg, sizeof(szMsg)/sizeof(TCHAR)); return MessageBox(hwndParent, szMsg, szTitle, fuStyle); } /* DiffPrefix * ---------- * * Purpose: * Compare (case-insensitive) two strings and return the prefixes of the * the strings formed by removing the common suffix string from them. * Integrity of tokens (directory name, filename and object names) are * preserved. Note that the prefixes are converted to upper case * characters. * * Parameters: * lpsz1 string 1 * lpsz2 string 2 * lplpszPrefix1 prefix of string 1 * lplpszPrefix2 prefix of string 2 * * Returns: * */ void WINAPI DiffPrefix(LPCTSTR lpsz1, LPCTSTR lpsz2, TCHAR FAR* FAR* lplpszPrefix1, TCHAR FAR* FAR* lplpszPrefix2) { LPTSTR lpstr1; LPTSTR lpstr2; TCHAR szTemp1[MAX_PATH]; TCHAR szTemp2[MAX_PATH]; OleDbgAssert(lpsz1); OleDbgAssert(lpsz2); OleDbgAssert(*lpsz1); OleDbgAssert(*lpsz2); OleDbgAssert(lplpszPrefix1); OleDbgAssert(lplpszPrefix2); // need to copy into temporary for case insensitive compare lstrcpy(szTemp1, lpsz1); lstrcpy(szTemp2, lpsz2); CharLower(szTemp1); CharLower(szTemp2); // do comparison lpstr1 = szTemp1 + lstrlen(szTemp1); lpstr2 = szTemp2 + lstrlen(szTemp2); while ((lpstr1 > szTemp1) && (lpstr2 > szTemp2)) { lpstr1 = CharPrev(szTemp1, lpstr1); lpstr2 = CharPrev(szTemp2, lpstr2); if (*lpstr1 != *lpstr2) { lpstr1 = CharNext(lpstr1); lpstr2 = CharNext(lpstr2); break; } } // scan forward to first delimiter while (*lpstr1 && *lpstr1 != '\\' && *lpstr1 != '!') lpstr1 = CharNext(lpstr1); while (*lpstr2 && *lpstr2 != '\\' && *lpstr2 != '!') lpstr2 = CharNext(lpstr2); *lpstr1 = '\0'; *lpstr2 = '\0'; // initialize in case of failure *lplpszPrefix1 = NULL; *lplpszPrefix2 = NULL; // allocate memory for the result *lplpszPrefix1 = (LPTSTR)OleStdMalloc((lstrlen(lpsz1)+1) * sizeof(TCHAR)); if (!*lplpszPrefix1) return; *lplpszPrefix2 = (LPTSTR)OleStdMalloc((lstrlen(lpsz2)+1) * sizeof(TCHAR)); if (!*lplpszPrefix2) { OleStdFree(*lplpszPrefix1); *lplpszPrefix1 = NULL; return; } // copy result lstrcpyn(*lplpszPrefix1, lpsz1, lstrlen(szTemp1)+1); lstrcpyn(*lplpszPrefix2, lpsz2, lstrlen(szTemp2)+1); } UINT WINAPI GetFileName(LPCTSTR lpszPathName, LPTSTR lpszTitle, UINT nMax) { // always capture the complete file name including extension (if present) LPTSTR lpszTemp = (LPTSTR)lpszPathName; for (LPCTSTR lpsz = lpszPathName; *lpsz != '\0'; lpsz = CharNext(lpsz)) { // remember last directory/drive separator if (*lpsz == '\\' || *lpsz == '/' || *lpsz == ':') lpszTemp = CharNext(lpsz); } // lpszTitle can be NULL which just returns the number of bytes if (lpszTitle == NULL) return lstrlen(lpszTemp)+1; // otherwise copy it into the buffer provided lstrcpyn(lpszTitle, lpszTemp, nMax); return 0; } BOOL WINAPI IsValidMetaPict(HGLOBAL hMetaPict) { BOOL fReturn = FALSE; LPMETAFILEPICT pMF = (LPMETAFILEPICT) GlobalLock(hMetaPict); if (pMF != NULL) { if (!IsBadReadPtr( pMF, sizeof(METAFILEPICT))) { if (GetMetaFileBitsEx(pMF->hMF, 0, 0)) { fReturn = TRUE; } } GlobalUnlock(hMetaPict); } return(fReturn); } /////////////////////////////////////////////////////////////////////////////