atlmisc.h
来自「一个与传统电子字典不同的字典」· C头文件 代码 · 共 2,853 行 · 第 1/5 页
H
2,853 行
// width indicated by
nWidth = _cstrtoi(lpsz);
for (; *lpsz != _T('\0') && _cstrisdigit(*lpsz); lpsz = ::CharNext(lpsz))
;
}
ATLASSERT(nWidth >= 0);
int nPrecision = 0;
if (*lpsz == _T('.'))
{
// skip past '.' separator (width.precision)
lpsz = ::CharNext(lpsz);
// get precision and skip it
if (*lpsz == _T('*'))
{
nPrecision = va_arg(argList, int);
lpsz = ::CharNext(lpsz);
}
else
{
nPrecision = _cstrtoi(lpsz);
for (; *lpsz != _T('\0') && _cstrisdigit(*lpsz); lpsz = ::CharNext(lpsz))
;
}
ATLASSERT(nPrecision >= 0);
}
// should be on type modifier or specifier
int nModifier = 0;
if(lpsz[0] == _T('I') && lpsz[1] == _T('6') && lpsz[2] == _T('4'))
{
lpsz += 3;
nModifier = FORCE_INT64;
}
else
{
switch (*lpsz)
{
// modifiers that affect size
case _T('h'):
nModifier = FORCE_ANSI;
lpsz = ::CharNext(lpsz);
break;
case _T('l'):
nModifier = FORCE_UNICODE;
lpsz = ::CharNext(lpsz);
break;
// modifiers that do not affect size
case _T('F'):
case _T('N'):
case _T('L'):
lpsz = ::CharNext(lpsz);
break;
}
}
// now should be on specifier
switch (*lpsz | nModifier)
{
// single characters
case _T('c'):
case _T('C'):
nItemLen = 2;
va_arg(argList, TCHAR);
break;
case _T('c') | FORCE_ANSI:
case _T('C') | FORCE_ANSI:
nItemLen = 2;
va_arg(argList, char);
break;
case _T('c') | FORCE_UNICODE:
case _T('C') | FORCE_UNICODE:
nItemLen = 2;
va_arg(argList, WCHAR);
break;
// strings
case _T('s'):
{
LPCTSTR pstrNextArg = va_arg(argList, LPCTSTR);
if (pstrNextArg == NULL)
{
nItemLen = 6; // "(null)"
}
else
{
nItemLen = lstrlen(pstrNextArg);
nItemLen = max(1, nItemLen);
}
break;
}
case _T('S'):
{
#ifndef _UNICODE
LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
if (pstrNextArg == NULL)
{
nItemLen = 6; // "(null)"
}
else
{
nItemLen = (int)wcslen(pstrNextArg);
nItemLen = max(1, nItemLen);
}
#else // _UNICODE
LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
if (pstrNextArg == NULL)
{
nItemLen = 6; // "(null)"
}
else
{
#if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800)
nItemLen = ATL::lstrlenA(pstrNextArg);
#else
nItemLen = lstrlenA(pstrNextArg);
#endif
nItemLen = max(1, nItemLen);
}
#endif // _UNICODE
break;
}
case _T('s') | FORCE_ANSI:
case _T('S') | FORCE_ANSI:
{
LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
if (pstrNextArg == NULL)
{
nItemLen = 6; // "(null)"
}
else
{
#if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800)
nItemLen = ATL::lstrlenA(pstrNextArg);
#else
nItemLen = lstrlenA(pstrNextArg);
#endif
nItemLen = max(1, nItemLen);
}
break;
}
case _T('s') | FORCE_UNICODE:
case _T('S') | FORCE_UNICODE:
{
LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
if (pstrNextArg == NULL)
{
nItemLen = 6; // "(null)"
}
else
{
nItemLen = (int)wcslen(pstrNextArg);
nItemLen = max(1, nItemLen);
}
break;
}
}
// adjust nItemLen for strings
if (nItemLen != 0)
{
nItemLen = max(nItemLen, nWidth);
if (nPrecision != 0)
nItemLen = min(nItemLen, nPrecision);
}
else
{
switch (*lpsz)
{
// integers
case _T('d'):
case _T('i'):
case _T('u'):
case _T('x'):
case _T('X'):
case _T('o'):
if (nModifier & FORCE_INT64)
va_arg(argList, __int64);
else
va_arg(argList, int);
nItemLen = 32;
nItemLen = max(nItemLen, nWidth + nPrecision);
break;
#ifndef _ATL_USE_CSTRING_FLOAT
case _T('e'):
case _T('E'):
case _T('f'):
case _T('g'):
case _T('G'):
ATLASSERT(!"Floating point (%%e, %%E, %%f, %%g, and %%G) is not supported by the WTL::CString class.");
#ifndef _DEBUG
::OutputDebugString(_T("Floating point (%%e, %%f, %%g, and %%G) is not supported by the WTL::CString class."));
#ifndef _WIN32_WCE
::DebugBreak();
#else // CE specific
DebugBreak();
#endif // _WIN32_WCE
#endif // !_DEBUG
break;
#else // _ATL_USE_CSTRING_FLOAT
case _T('e'):
case _T('E'):
case _T('g'):
case _T('G'):
va_arg(argList, double);
nItemLen = 128;
nItemLen = max(nItemLen, nWidth + nPrecision);
break;
case _T('f'):
{
double f = va_arg(argList, double);
// 312 == strlen("-1+(309 zeroes).")
// 309 zeroes == max precision of a double
// 6 == adjustment in case precision is not specified,
// which means that the precision defaults to 6
int cchLen = max(nWidth, 312 + nPrecision + 6);
CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;
LPTSTR pszTemp = buff.Allocate(cchLen);
if(pszTemp != NULL)
{
SecureHelper::sprintf_x(pszTemp, cchLen, _T("%*.*f"), nWidth, nPrecision + 6, f);
nItemLen = (int)_tcslen(pszTemp);
}
else
{
nItemLen = cchLen;
}
}
break;
#endif // _ATL_USE_CSTRING_FLOAT
case _T('p'):
va_arg(argList, void*);
nItemLen = 32;
nItemLen = max(nItemLen, nWidth + nPrecision);
break;
// no output
case _T('n'):
va_arg(argList, int*);
break;
default:
ATLASSERT(FALSE); // unknown formatting option
}
}
// adjust nMaxLen for output nItemLen
nMaxLen += nItemLen;
}
if(GetBuffer(nMaxLen) == NULL)
return FALSE;
#ifndef _ATL_USE_CSTRING_FLOAT
int nRet = SecureHelper::wvsprintf_x(m_pchData, GetAllocLength() + 1, lpszFormat, argListSave);
#else // _ATL_USE_CSTRING_FLOAT
int nRet = SecureHelper::vsprintf_x(m_pchData, GetAllocLength() + 1, lpszFormat, argListSave);
#endif // _ATL_USE_CSTRING_FLOAT
nRet; // ref
ATLASSERT(nRet <= GetAllocLength());
ReleaseBuffer();
va_end(argListSave);
return TRUE;
}
// formatting for localization (uses FormatMessage API)
// formatting (using FormatMessage style formatting)
BOOL __cdecl FormatMessage(LPCTSTR lpszFormat, ...)
{
// format message into temporary buffer lpszTemp
va_list argList;
va_start(argList, lpszFormat);
LPTSTR lpszTemp;
BOOL bRet = TRUE;
if (::FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
lpszFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0 || lpszTemp == NULL)
bRet = FALSE;
// assign lpszTemp into the resulting string and free the temporary
*this = lpszTemp;
LocalFree(lpszTemp);
va_end(argList);
return bRet;
}
BOOL __cdecl FormatMessage(UINT nFormatID, ...)
{
// get format string from string table
CString strFormat;
BOOL bRetTmp = strFormat.LoadString(nFormatID);
bRetTmp; // ref
ATLASSERT(bRetTmp != 0);
// format message into temporary buffer lpszTemp
va_list argList;
va_start(argList, nFormatID);
LPTSTR lpszTemp;
BOOL bRet = TRUE;
if (::FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
strFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0 || lpszTemp == NULL)
bRet = FALSE;
// assign lpszTemp into the resulting string and free lpszTemp
*this = lpszTemp;
LocalFree(lpszTemp);
va_end(argList);
return bRet;
}
// Windows support
BOOL LoadString(UINT nID) // load from string resource (255 chars max.)
{
#ifdef _UNICODE
const int CHAR_FUDGE = 1; // one TCHAR unused is good enough
#else
const int CHAR_FUDGE = 2; // two BYTES unused for case of DBC last char
#endif
// try fixed buffer first (to avoid wasting space in the heap)
TCHAR szTemp[256];
int nCount = sizeof(szTemp) / sizeof(szTemp[0]);
int nLen = _LoadString(nID, szTemp, nCount);
if (nCount - nLen > CHAR_FUDGE)
{
*this = szTemp;
return (nLen > 0);
}
// try buffer size of 512, then larger size until entire string is retrieved
int nSize = 256;
do
{
nSize += 256;
LPTSTR lpstr = GetBuffer(nSize - 1);
if(lpstr == NULL)
{
nLen = 0;
break;
}
nLen = _LoadString(nID, lpstr, nSize);
} while (nSize - nLen <= CHAR_FUDGE);
ReleaseBuffer();
return (nLen > 0);
}
#ifndef _UNICODE
// ANSI <-> OEM support (convert string in place)
void AnsiToOem()
{
CopyBeforeWrite();
::AnsiToOem(m_pchData, m_pchData);
}
void OemToAnsi()
{
CopyBeforeWrite();
::OemToAnsi(m_pchData, m_pchData);
}
#endif
#ifndef _ATL_NO_COM
// OLE BSTR support (use for OLE automation)
BSTR AllocSysString() const
{
#if defined(_UNICODE) || defined(OLE2ANSI)
BSTR bstr = ::SysAllocStringLen(m_pchData, GetData()->nDataLength);
#else
int nLen = MultiByteToWideChar(CP_ACP, 0, m_pchData,
GetData()->nDataLength, NULL, NULL);
BSTR bstr = ::SysAllocStringLen(NULL, nLen);
if(bstr != NULL)
MultiByteToWideChar(CP_ACP, 0, m_pchData, GetData()->nDataLength, bstr, nLen);
#endif
return bstr;
}
BSTR SetSysString(BSTR* pbstr) const
{
#if defined(_UNICODE) || defined(OLE2ANSI)
::SysReAllocStringLen(pbstr, m_pchData, GetData()->nDataLength);
#else
int nLen = MultiByteToWideChar(CP_ACP, 0, m_pchData,
GetData()->nDataLength, NULL, NULL);
if(::SysReAllocStringLen(pbstr, NULL, nLen))
MultiByteToWideChar(CP_ACP, 0, m_pchData, GetData()->nDataLength, *pbstr, nLen);
#endif
ATLASSERT(*pbstr != NULL);
return *pbstr;
}
#endif // !_ATL_NO_COM
// Access to string implementation buffer as "C" character array
LPTSTR GetBuffer(int nMinBufLength)
{
ATLASSERT(nMinBufLength >= 0);
if (GetData()->nRefs > 1 || nMinBufLength > GetData()->nAllocLength)
{
// we have to grow the buffer
CStringData* pOldData = GetData();
int nOldLen = GetData()->nDataLength; // AllocBuffer will tromp it
if (nMinBufLength < nOldLen)
nMinBufLength = nOldLen;
if(!AllocBuffer(nMinBufLength))
return NULL;
SecureHelper::memcpy_x(m_pchData, (nMinBufLength + 1) * sizeof(TCHAR), pOldData->data(), (nOldLen + 1) * sizeof(TCHAR));
GetData()->nDataLength = nOldLen;
CString::Release(pOldData);
}
ATLASSERT(GetData()->nRefs <= 1);
// return a pointer to the character storage for this string
ATLASSERT(m_pchData != NULL);
return m_pchData;
}
void ReleaseBuffer(int nNewLength = -1)
{
CopyBeforeWrite(); // just in case GetBuffer was not called
if (nNewLength == -1)
nNewLength = lstrlen(m_pchData); // zero terminated
ATLASSERT(nNewLength <= GetData()->nAllocLength);
GetData()->nDataLength = nNewLength;
m_pchData[nNewLength] = _T('\0');
}
LPTSTR GetBufferSetLength(int nNewLength)
{
ATLASSERT(nNewLength >= 0);
if(GetBuffer(nNewLength) == NULL)
return NULL;
GetData()->nDataLength = nNewLength;
m_pchData[nNewLength] = _T('\0');
return m_pchData;
}
void FreeExtra()
{
ATLASSERT(GetData()->nDataLength <= GetData()->nAllocLength);
if (GetData()->nDataLength != GetData()->nAllocLength)
{
CStringData* pOldData = GetData();
if(AllocBuffer(GetData()->nDataLength))
{
SecureHelper::memcpy_x(m_pchData, (GetData()->nAllocLength + 1) * sizeof(TCHAR), pOldData->data(), pOldData->nDataLength * sizeof(TCHAR));
ATLASSERT(m_pchData[GetData()->nDataLength] == _T('\0'));
CString::Release(pOldData);
}
}
ATLASSERT(GetData() != NULL);
}
// Use LockBuffer/UnlockBuffer to turn refcounting off
LPTSTR LockBuffer()
{
LPTSTR lpsz = GetBuffer(0);
if(lpsz != NULL)
GetData()->nRefs = -1;
return lpsz;
}
void UnlockBuffer()
{
ATLASSERT(GetData()->nRefs == -1);
if (GetData() != _atltmpDataNil)
GetData()->nRefs = 1;
}
// Implementation
public:
~CString() // free any attached data
{
if (GetData() != _atltmpDataNil)
{
if (InterlockedDecrement(&GetData()->nRefs) <= 0)
delete[] (BYTE*)GetData();
}
}
int GetAllocLength() const
{
return GetData()->nAllocLength;
}
static BOOL __stdcall _IsValidString(LPCTSTR lpsz, int /*nLength*/ = -1)
{
return (lpsz != NULL) ? TRUE : FALSE;
}
protected:
LPTSTR m_pchData; // pointer to ref counted string data
// implementation helpers
CStringData* GetData() const
{
ATLASSERT(m_pchData != NULL);
return ((CStringData*)m_pchData) - 1;
}
void Init()
{
m_pchData = _GetEmptyString().m_pchData;
}
BOOL AllocCopy(CString& dest, int nCopyLen, int nCopyIndex, int nExtraLen) const
{
// will clone the data attached to this string
// allocating 'nExtraLen' characters
// Places results in uninitialized string 'dest'
// Will copy the part or all of original data to start of new string
BOOL bRet = FALSE;
int nNewLen = nCopyLen + nExtraLen;
if (nNewLen == 0)
{
dest.Init();
bRet = TRUE;
}
else if(nNewLen >= nCopyLen)
{
if(dest.AllocBuffer(nNewLen))
{
SecureHelper::memcpy_x(dest.m_pchData, (nNewLen + 1) * sizeof(TCHAR), m_pchData + nCopyIndex, nCopyLen * sizeof(TCHAR));
bRet = TRUE;
}
}
return bRet;
}
// always allocate one extra character for '\0' termination
// assumes [optimistically] that data length will equal allocation length
BOOL AllocBuffer(int nLen)
{
ATLASSERT(nLen >= 0);
ATLASSERT(nLen <= INT_MAX - 1); // max size (enough room for 1 extra)
if (nLen == 0)
{
Init();
}
else
{
CStringData* pData = NULL;
ATLTRY(pData = (CStringData*)new BYTE[sizeof(CStringData) + (nLen + 1) * sizeof(TCHAR)]);
if(pData == NULL)
return FALSE;
pData->nRefs = 1;
pData->data()[nLen] = _T('\0');
pData->nDataLength = nLen;
pData->nAllocLength = nLen;
m_pchData = pData->data();
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?