|
|
//-----------------------------------------------------------------------------
// 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 <windows.h>
#include <tchar.h>
#include <wchar.h>
#include <stdio.h>
#include <stdarg.h>
// assert include (make sure assert actually works with build)
#ifdef DBG
#undef NDEBUG
#endif
#include <assert.h>
#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
|