//----------------------------------------------------------------------------- // File: useful.cpp // // Desc: Contains various utility classes and functions to help the // UI carry its operations more easily. // // Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved. //----------------------------------------------------------------------------- #include #include #include #include #include // assert include (make sure assert actually works with build) #ifdef DBG #undef NDEBUG #endif #include #include "useful.h" #include "collections.h" /*--------- \/ stuff for collections.h \/ ---------*/ BOOL AfxIsValidAddress( const void* lp, UINT nBytes, BOOL bReadWrite) { // return lp != NULL; // simple version using Win-32 APIs for pointer validation. return (lp != NULL && !IsBadReadPtr(lp, nBytes) && (!bReadWrite || !IsBadWritePtr((LPVOID)lp, nBytes))); } CPlex* PASCAL CPlex::Create(CPlex*& pHead, UINT nMax, UINT cbElement) { assert(nMax > 0 && cbElement > 0); CPlex* p = (CPlex*) new BYTE[sizeof(CPlex) + nMax * cbElement]; // may throw exception if (p) { p->pNext = pHead; pHead = p; // change head (adds in reverse order for simplicity) } return p; } void CPlex::FreeDataChain() // free this one and links { CPlex* p = this; while (p != NULL) { BYTE* bytes = (BYTE*) p; CPlex* pNext = p->pNext; delete[] bytes; p = pNext; } } /*--------- /\ stuff for collections.h /\ ---------*/ int ConvertVal(int x, int a1, int a2, int b1, int b2) { assert(a1 != a2 && a2 - a1); return MulDiv(x - a1, b2 - b1, a2 - a1) + b1; } double dConvertVal(double x, double a1, double a2, double b1, double b2) { assert(a1 != a2 && a2 - a1); return (x - a1) * (b2 - b1) / (a2 - a1) + b1; } SIZE GetRectSize(const RECT &rect) { SIZE size = { rect.right - rect.left, rect.bottom - rect.top}; return size; } SIZE GetTextSize(LPCTSTR tszText, HFONT hFont) { if (!tszText) { SIZE z = {0, 0}; return z; } RECT trect = {0, 0, 1, 1}; HDC hDC = CreateCompatibleDC(NULL); if (hDC != NULL) { HGDIOBJ hOld = NULL; if (hFont) hOld = SelectObject(hDC, hFont); DrawText(hDC, tszText, -1, &trect, DT_CALCRECT | DT_NOPREFIX); if (hFont) SelectObject(hDC, hOld); DeleteDC(hDC); } SIZE size = {trect.right - trect.left, trect.bottom - trect.top}; return size; } int GetTextHeight(HFONT hFont) { static const TCHAR str[] = _T("Happy Test! :D"); SIZE size = GetTextSize(str, hFont); return size.cy; } int vFormattedMsgBox(HINSTANCE hInstance, HWND hParent, UINT uType, UINT uTitle, UINT uMsg, va_list args) { int i; const int len = 1024; static TCHAR title[len], format[len], msg[len]; if (!LoadString(hInstance, uTitle, title, len)) _tcscpy(title, _T("(could not load title string)")); if (!LoadString(hInstance, uMsg, format, len)) return MessageBox(hParent, _T("(could not load message/format string)"), title, uType); #ifdef WIN95 { char *psz = NULL; char szDfs[1024]={0}; strcpy(szDfs,format); // make a local copy of format string while (psz = strstr(szDfs,"%p")) // find each %p *(psz+1) = 'x'; // replace each %p with %x i = _vsntprintf(msg, len, szDfs, args); // use the local format string } #else { i = _vsntprintf(msg, len, format, args); } #endif if (i < 0) return MessageBox(hParent, _T("(could not format message)"), title, uType); if (i < 1) msg[0] = 0; return MessageBox(hParent, msg, title, uType); } int FormattedMsgBox(HINSTANCE hInstance, HWND hParent, UINT uType, UINT uTitle, UINT uMsg, ...) { va_list args; va_start(args, uMsg); int i = vFormattedMsgBox(hInstance, hParent, uType, uTitle, uMsg, args); va_end(args); return i; } BOOL UserConfirm(HINSTANCE hInstance, HWND hParent, UINT uTitle, UINT uMsg, ...) { va_list args; va_start(args, uMsg); int i = vFormattedMsgBox(hInstance, hParent, MB_ICONQUESTION | MB_YESNO, uTitle, uMsg, args); va_end(args); return i == IDYES; } int FormattedErrorBox(HINSTANCE hInstance, HWND hParent, UINT uTitle, UINT uMsg, ...) { va_list args; va_start(args, uMsg); int i = vFormattedMsgBox(hInstance, hParent, MB_OK | MB_ICONSTOP, uTitle, uMsg, args); va_end(args); return i; } int FormattedLastErrorBox(HINSTANCE hInstance, HWND hParent, UINT uTitle, UINT uMsg, DWORD dwError) { // format an error message from GetLastError(). LPVOID lpMsgBuf = NULL; DWORD result = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL); if (!result || lpMsgBuf == NULL) return FormattedErrorBox(hInstance, hParent, uTitle, uMsg, _T("An unknown error occured (could not format the error code).")); int i = FormattedErrorBox(hInstance, hParent, uTitle, uMsg, (LPCTSTR)lpMsgBuf); LocalFree(lpMsgBuf); return i; } LPTSTR AllocLPTSTR(LPCWSTR wstr) { if (wstr == NULL) return NULL; #ifdef UNICODE return _tcsdup(wstr); #else int len = wcslen(wstr) * 2 + 1; char *ret = (char *)malloc(len); if (!ret) return NULL; WideCharToMultiByte(CP_ACP, 0, wstr, -1, ret, len, NULL, NULL); ret[len-1] = '\0'; return ret; #endif } LPTSTR AllocLPTSTR(LPCSTR str) { if (str == NULL) return NULL; #ifndef UNICODE return _tcsdup(str); #else int len = strlen(str); WCHAR *ret = (WCHAR *)malloc((len + 1) * sizeof(WCHAR)); if (!ret) return NULL; mbstowcs(ret, str, len); ret[len] = L'\0'; return ret; #endif } void CopyStr(LPWSTR dest, LPCWSTR src, size_t max) { if (dest == NULL || src == NULL) return; wcsncpy(dest, src, max); } void CopyStr(LPSTR dest, LPCSTR src, size_t max) { if (dest == NULL || src == NULL) return; strncpy(dest, src, max); } void CopyStr(LPWSTR dest, LPCSTR src, size_t max) { if (dest == NULL || src == NULL) return; mbstowcs(dest, src, max); } void CopyStr(LPSTR dest, LPCWSTR src, size_t max) { if (dest == NULL || src == NULL) return; WideCharToMultiByte(CP_ACP, 0, src, -1, dest, max, NULL, NULL); } LPWSTR AllocLPWSTR(LPCWSTR wstr) { if (wstr == NULL) return NULL; return _wcsdup(wstr); } LPWSTR AllocLPWSTR(LPCSTR str) { if (str == NULL) return NULL; size_t len = strlen(str); size_t retsize = mbstowcs(NULL, str, len); WCHAR *ret = (WCHAR *)malloc((retsize + 1) * sizeof(WCHAR)); if (!ret) return NULL; mbstowcs(ret, str, len); ret[retsize] = L'\0'; return ret; } LPSTR AllocLPSTR(LPCWSTR wstr) { if (wstr == NULL) return NULL; size_t len = wcslen(wstr); size_t retsize = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL); CHAR *ret = (CHAR *)malloc((retsize + 1) * sizeof(CHAR)); if (!ret) return NULL; WideCharToMultiByte(CP_ACP, 0, wstr, -1, ret, retsize, NULL, NULL); ret[retsize] = '\0'; return ret; } LPSTR AllocLPSTR(LPCSTR str) { if (str == NULL) return NULL; return _strdup(str); } LPTSTR AllocFileNameNoPath(LPTSTR path) { TCHAR fname[_MAX_FNAME]; TCHAR ext[_MAX_EXT]; if (path == NULL) return NULL; _tsplitpath(path, NULL, NULL, fname, ext); LPTSTR ret = (LPTSTR)malloc(sizeof(TCHAR) * (_tcslen(fname) + _tcslen(ext) + 1)); if (ret != NULL) { _tcscpy(ret, fname); _tcscat(ret, ext); } return ret; } LPTSTR utilstr::Eject() { LPTSTR str = m_str; m_str = NULL; m_len = 0; return str; } void utilstr::Empty() { if (m_str != NULL) free(m_str); m_len = 0; } bool utilstr::IsEmpty() const { return !GetLength(); } int utilstr::GetLength() const { if (m_str == NULL) return 0; if (!m_len) return 0; return _tcslen(m_str); } void utilstr::Format(LPCTSTR format, ...) { static TCHAR buf[2048]; va_list args; va_start(args, format); #ifdef WIN95 { char *psz = NULL; char szDfs[1024]={0}; strcpy(szDfs,format); // make a local copy of format string while (psz = strstr(szDfs,"%p")) // find each %p *(psz+1) = 'x'; // replace each %p with %x _vsntprintf(buf, sizeof(buf)/sizeof(TCHAR), szDfs, args); // use the local format string } #else { _vsntprintf(buf, sizeof(buf)/sizeof(TCHAR), format, args); } #endif va_end(args); equal(buf); } void utilstr::equal(LPCTSTR str) { Empty(); if (str == NULL) return; m_len = _tcslen(str); m_str = (LPTSTR)malloc(sizeof(TCHAR) * (m_len + 1)); if (m_str != NULL) _tcscpy(m_str, str); else m_len = 0; } void utilstr::add(LPCTSTR str) { if (str == NULL) return; if (IsEmpty()) { equal(str); return; } int len = _tcslen(str); int newlen = m_len + len; LPTSTR newstr = (LPTSTR)malloc(sizeof(TCHAR) * (newlen + 1)); if (newstr == NULL) return; _tcscpy(newstr, m_str); _tcscat(newstr, str); Empty(); m_str = newstr; m_len = newlen; } LPTSTR AllocFlagStr(DWORD value, const AFS_FLAG flag[], int flags) { utilstr ret; // return string DWORD allknownbits = 0; // check value to see if there are any bits // set for which we don't have a define // handle each flag bool bflagfound = false; for (int i = 0; i < flags; i++) { // set bit for this flag in allknownbits allknownbits |= flag[i].value; // if this bit is set in the passed value, or the value // is zero and we're on the zero flag, // add the define for this bit/flag to the return string if (value ? value & flag[i].value : !flag[i].value) { // adding binary or operators between flags if (bflagfound) ret += _T(" | "); ret += flag[i].name; bflagfound = true; } } // now see if there are any unknown bits in passed flag DWORD unknownbits = value & ~allknownbits; if (unknownbits) { // add hex number for unknown bits utilstr unk; unk.Format(_T("0x%08X"), unknownbits); if (bflagfound) ret += _T(" | "); ret += unk; } // if value is zero (and no flags for zero) we should just set the string to "0" if (!value && !bflagfound) ret = _T("0"); // now the string should definitely not be empty, in any case assert(!ret.IsEmpty()); // finally, add a comment that has hex number for entire value // (for debugging) utilstr temp; temp.Format(_T(" /* 0x%08X */"), value); ret += temp; // done return ret.Eject(); } void PutLinePoint(HDC hDC, POINT p) { MoveToEx(hDC, p.x, p.y, NULL); LineTo(hDC, p.x + 1, p.y); } void PolyLineArrowShadow(HDC hDC, POINT *p, int i) { PolyLineArrow(hDC, p, i, TRUE); } void PolyLineArrow(HDC hDC, POINT *rgpt, int nPoints, BOOL bDoShadow) { int i; if (rgpt == NULL || nPoints < 1) return; if (nPoints > 1) for (i = 0; i < nPoints - 1; i++) { SPOINT a = rgpt[i], b = rgpt[i + 1]; if (bDoShadow) { int rise = abs(b.y - a.y), run = abs(b.x - a.x); bool vert = rise > run; int ord = vert ? 1 : 0; int nord = vert ? 0 : 1; for (int o = -1; o <= 1; o += 2) { SPOINT c(a), d(b); c.a[nord] += o; d.a[nord] += o; MoveToEx(hDC, c.x, c.y, NULL); LineTo(hDC, d.x, d.y); } bool reverse = a.a[ord] > b.a[ord]; SPOINT e(reverse ? b : a), f(reverse ? a : b); e.a[ord] -= 1; f.a[ord] += 1; PutLinePoint(hDC, e); PutLinePoint(hDC, f); } else { MoveToEx(hDC, a.x, a.y, NULL); LineTo(hDC, b.x, b.y); } } POINT z = rgpt[nPoints - 1]; if (bDoShadow) { POINT pt[5] = { {z.x, z.y + 2}, {z.x + 2, z.y}, {z.x, z.y - 2}, {z.x - 2, z.y}, }; pt[4] = pt[0]; Polyline(hDC, pt, 5); } else { MoveToEx(hDC, z.x - 1, z.y, NULL); LineTo(hDC, z.x + 2, z.y); MoveToEx(hDC, z.x, z.y - 1, NULL); LineTo(hDC, z.x, z.y + 2); } } BOOL bEq(BOOL a, BOOL b) { bool c = !a, d = !b; return (c == d) ? TRUE : FALSE; } void DrawArrow(HDC hDC, const RECT &rect, BOOL bVert, BOOL bUpLeft) { SRECT srect = rect; srect.right--; srect.bottom--; int ord = bVert ? 1 : 0; int nord = bVert ? 0 : 1; SPOINT p(!bUpLeft ? srect.lr : srect.ul), b(!bUpLeft ? srect.ul : srect.lr); b.a[ord] += bUpLeft ? -1 : 1; SPOINT t = p; t.a[nord] = (p.a[nord] + b.a[nord]) / 2; SPOINT u; u.a[ord] = b.a[ord]; u.a[nord] = p.a[nord]; POINT poly[] = { {t.x, t.y}, {u.x, u.y}, {b.x, b.y} }; Polygon(hDC, poly, 3); } BOOL ScreenToClient(HWND hWnd, LPRECT rect) { if (rect == NULL) return FALSE; SRECT sr = *rect; if (ScreenToClient(hWnd, &sr.ul.p) && ScreenToClient(hWnd, &sr.lr.p)) { *rect = sr; return TRUE; } return FALSE; } BOOL ClientToScreen(HWND hWnd, LPRECT rect) { if (rect == NULL) return FALSE; SRECT sr = *rect; if (ClientToScreen(hWnd, &sr.ul.p) && ClientToScreen(hWnd, &sr.lr.p)) { *rect = sr; return TRUE; } return FALSE; } #define z ((L"\0")[0]) int StrLen(LPCWSTR s) { if (s == NULL) return 0; return wcslen(s); } int StrLen(LPCSTR s) { if (s == NULL) return 0; return strlen(s); } //@@BEGIN_MSINTERNAL #ifdef DDKBUILD LPCTSTR GetOpenFileName(HINSTANCE hInst, HWND hWnd, LPCTSTR title, LPCTSTR filter, LPCTSTR defext, LPCTSTR inidir) { OPENFILENAME ofn; static TCHAR tszFile[MAX_PATH + 1] = _T(""); tszFile[MAX_PATH] = 0; ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hWnd; ofn.hInstance = hInst; ofn.lpstrFilter = filter; ofn.lpstrCustomFilter = NULL; ofn.nMaxCustFilter = 0; ofn.nFilterIndex = 0; ofn.lpstrFile = tszFile; ofn.nMaxFile = MAX_PATH; ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = inidir; ofn.lpstrTitle = title; ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST; ofn.lpstrDefExt = defext; ofn.lCustData = NULL; ofn.lpfnHook = NULL; ofn.lpTemplateName = NULL; if (!GetOpenFileName(&ofn)) return NULL; return tszFile; } #endif //@@END_MSINTERNAL