Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

497 lines
9.8 KiB

//
// TSTR - represents a writable position in a string.
//
// Has methods to safely append to the string. Will not overrun buffer,
// truncates if reaches the end.
//
//
// Sample usage:
//
// void SomeFunc( TSTR & str )
// {
// int i = 42;
// str << TEXT("Value is: ") << i;
// }
//
// Can be used with TCHAR*-style APIs, by using the ptr(), left() and
// advance() members. ptr() returns pointer to current write position,
// left() returns number of chars left, and advance() updates the write
// position.
//
// void MyGetWindowText( StrWrPos & str )
// {
// int len = GetWindowText( hWnd, str.ptr(), str.left() );
// str.advance( len );
// }
//
// This makes sure that the text will not be truncated
// void MyGetWindowText( StrWrPos & str )
// {
// str.anticipate( GetWindowTextLength( hWnd );
// int len = GetWindowText( hWnd, str.ptr(), str.left() );
// str.advance( len );
// }
//
// Sample usage:
//
// void Func( TSTR & str );
//
// TSTR s(128);
// s << TEXT("Text added: [");
// Func( s ); // add more text to string
// s << TEXT("]");
//
// SetWindowText( hwnd, s );
//
//
// WriteHex - helper class to output hex values:
//
// Sample usage:
//
// str << TEXT("Value is:") << WriteHex( hwnd, 8 );
//
// Can optionally specify number of digits to output. (result will be
// 0-padded.)
//
//
// WriteError - helper class to output COM error values:
//
// Sample usage:
//
// hr = ProcessData();
// if( hr != S_OK )
// {
// str << WriteError( hr, TEXT("in ProcessData()");
// LogError( str.str() );
// }
//
#ifndef _TSTR_H_
#define _TSTR_H_
#if ! defined( _BASETSD_H_ ) || defined( NEED_BASETSD_DEFINES )
// These allow us to compile with the pre-Win64 SDK (eg. using visual studio)
typedef unsigned long UINT_PTR;
typedef DWORD DWORD_PTR;
#define PtrToInt (int)
#endif
#define LONG_TEXT_LENGTH 40
#include <oaidl.h>
#include <crtdbg.h>
#include <string>
typedef std::basic_string<TCHAR> tstring;
typedef std::string ASTR; // save these names for where we expand
typedef std::wstring WSTR; // the usage of this stuff to include them
class TSTR : public tstring
{
// this is only used for ptr, left and advance functions.
ULONG m_lTheRealSize;
public:
TSTR() : m_lTheRealSize(-1) { }
TSTR(const TCHAR *s) : tstring(s, static_cast<size_type>(lstrlen(s))), m_lTheRealSize(-1) { }
TSTR(const TCHAR *s, size_type n) : tstring(s, n), m_lTheRealSize(-1) { }
TSTR(const tstring& rhs) : tstring(rhs), m_lTheRealSize(-1) { }
TSTR(const tstring& rhs, size_type pos, size_type n) : tstring(rhs, pos, n), m_lTheRealSize(-1) { }
TSTR(size_type n, TCHAR c) : tstring(n, c), m_lTheRealSize(-1) { }
TSTR(size_type n) : tstring(), m_lTheRealSize(-1) { reserve( n + 1 ); }
TSTR(const_iterator first, const_iterator last) : tstring(first, last), m_lTheRealSize(-1) { }
operator const TCHAR * ()
{
return c_str();
}
TCHAR * ptr()
{
_ASSERT(m_lTheRealSize == -1);
m_lTheRealSize = size();
TCHAR *pEnd = &(*end());
resize(capacity());
return pEnd;
}
unsigned int left()
{
unsigned int left;
if (m_lTheRealSize == -1)
left = ( capacity() - size() ) - 1;
else
left = ( capacity() - m_lTheRealSize ) - 1;
return left;
}
void advance( unsigned int c )
{
_ASSERT(m_lTheRealSize != -1); // ptr has not been called so we should not need to advance
if (m_lTheRealSize != -1)
{
at( m_lTheRealSize + c ) = NULL; // make sure this stays null terminated
resize(m_lTheRealSize + c);
m_lTheRealSize = -1;
}
}
void reset()
{
resize(0);
m_lTheRealSize = -1;
}
void anticipate( unsigned int c )
{
if ( c > 0 )
{
unsigned int cSize;
if ( m_lTheRealSize == -1 )
cSize = size();
else
cSize = m_lTheRealSize;
const unsigned int i = capacity() - cSize;
if ( i < c )
reserve( cSize + c + 1 );
}
}
};
inline
TSTR & operator << ( TSTR & str, const TCHAR * obj )
{
if ( obj )
str.append( obj );
return str;
}
inline
TSTR & operator << ( TSTR & str, TCHAR obj )
{
str.append( &obj, 1 );
return str;
}
inline
TSTR & operator << ( TSTR & str, long obj )
{
TCHAR sz[LONG_TEXT_LENGTH];
#ifdef UNICODE
str.append(_ltow( obj, sz, 10 ));
return str;
#else
str.append(_ltoa( obj, sz, 10 ));
return str;
#endif
}
inline
TSTR & operator << ( TSTR & str, unsigned long obj )
{
TCHAR sz[LONG_TEXT_LENGTH];
#ifdef UNICODE
str.append(_ultow( obj, sz, 10 ));
return str;
#else
str.append(_ultoa( obj, sz, 10 ));
return str;
#endif
}
inline
TSTR & operator << ( TSTR & str, int obj )
{
TCHAR sz[LONG_TEXT_LENGTH];
#ifdef UNICODE
str.append(_itow( obj, sz, 10 ));
return str;
#else
str.append(_itoa( obj, sz, 10 ));
return str;
#endif
}
inline
TSTR & operator << ( TSTR & str, unsigned int obj )
{
TCHAR sz[LONG_TEXT_LENGTH];
#ifdef UNICODE
str.append(_ultow( static_cast<unsigned long>(obj), sz, 10 ));
return str;
#else
str.append(_ultoa( static_cast<unsigned long>(obj), sz, 10 ));
return str;
#endif
}
#ifndef UNICODE
inline
TSTR & operator << ( TSTR & str, const WCHAR * obj )
{
if ( obj )
{
str.anticipate( wcslen( obj ) + 1 );
int len = WideCharToMultiByte( CP_ACP, 0, obj, -1, str.ptr(), str.left(), NULL, NULL );
// Len, in this case, includes the terminating NUL - so subtract it, if
// we got one...
if( len > 0 )
len--;
str.advance( len );
}
return str;
}
#endif
//
// WriteHex - helper class to output hex values:
//
// See top of file for usage notes.
//
class WriteHex
{
DWORD_PTR m_dw;
int m_Digits;
public:
// If Digits not specified, uses only as many as needed.
WriteHex( DWORD dw, int Digits = -1 ) : m_dw( dw ), m_Digits( Digits ) { }
// For pointer, pads if necessary to get std. ptr size.
// (sizeof(ptr)*2, since 2 digits per byte in ptr).
WriteHex( const void * pv, int Digits = sizeof(void*)*2 ) : m_dw( (DWORD_PTR)pv ), m_Digits( Digits ) { }
void Write( TSTR & str ) const
{
static const TCHAR * HexChars = TEXT("0123456789ABCDEF");
//str << TEXT("0x");
int Digit;
if( m_Digits == -1 )
{
// Work out number of digits...
Digit = 0;
DWORD test = m_dw;
while( test )
{
Digit++;
test >>= 4;
}
// Special case for 0 - still want one digit.
if( Digit == 0 )
Digit = 1;
}
else
Digit = m_Digits;
while( Digit )
{
Digit--;
str << HexChars[ ( m_dw >> (Digit * 4) ) & 0x0F ];
}
}
};
inline
TSTR & operator << ( TSTR & s, const WriteHex & obj )
{
obj.Write( s );
return s;
}
//
// WriteError - helper class to output COM error values:
//
// See top of file for usage notes.
//
class WriteError
{
HRESULT m_hr;
LPCTSTR m_pWhere;
public:
WriteError( HRESULT hr, LPCTSTR pWhere = NULL )
: m_hr( hr ),
m_pWhere( pWhere )
{ }
void Write( TSTR & str ) const
{
str << TEXT("[Error");
if( m_pWhere )
str << TEXT(" ") << m_pWhere;
str << TEXT(": hr=0x") << WriteHex( m_hr ) << TEXT(" - ");
if( m_hr == S_FALSE )
{
str << TEXT("S_FALSE");
}
else
{
int len = FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
m_hr,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
str.ptr(),
str.left(),
NULL );
if( len > 2 )
len -= 2; // Ignore trailing /r/n that FmtMsg() adds...
str.advance( len );
}
str << TEXT("]");
}
};
inline
TSTR & operator << ( TSTR & s, const WriteError & obj )
{
obj.Write( s );
return s;
}
inline
TSTR & operator << ( TSTR & s, const GUID & guid )
{
s << TEXT("{") << WriteHex( guid.Data1, 8 ) // DWORD
<< TEXT("-") << WriteHex( guid.Data2, 4 ) // WORD
<< TEXT("-") << WriteHex( guid.Data3, 4 ) // WORD
<< TEXT("-")
<< WriteHex( guid.Data4[ 0 ], 2 )
<< WriteHex( guid.Data4[ 1 ], 2 )
<< TEXT("-");
for( int i = 2 ; i < 8 ; i++ )
{
s << WriteHex( guid.Data4[ i ], 2 ); // BYTE
}
s << TEXT("}");
return s;
}
inline
TSTR & operator << ( TSTR & s, const VARIANT & var )
{
s << TEXT("[");
switch( var.vt )
{
case VT_EMPTY:
{
s << TEXT("VT_EMPTY");
break;
}
case VT_I4:
{
s << TEXT("VT_I4=0x");
s << WriteHex( var.lVal );
break;
}
case VT_I2:
{
s << TEXT("VT_I2=0x");
s << WriteHex( var.iVal );
break;
}
case VT_BOOL:
{
s << TEXT("VT_BOOL=");
if( var.boolVal == VARIANT_TRUE )
s << TEXT("TRUE");
else if( var.boolVal == VARIANT_FALSE )
s << TEXT("FALSE");
else
s << TEXT("?") << var.boolVal;
break;
}
case VT_R4:
{
float fltval = var.fltVal;
int x = (int)(fltval * 100);
s << TEXT("VT_R4=") << x/100 << TEXT(".")
<< x/10 % 10
<< x % 10;
break;
}
case VT_BSTR:
{
s << TEXT("VT_BSTR=\"") << var.bstrVal << TEXT("\"");
break;
}
case VT_UNKNOWN:
{
s << TEXT("VT_UNKNOWN=0x") << WriteHex( var.punkVal, 8 );
break;
}
case VT_DISPATCH:
{
s << TEXT("VT_DISPATCH=0x") << WriteHex( var.pdispVal, 8 );
break;
}
default:
{
s << TEXT("VT_? ") << (long)var.vt;
break;
}
}
s << TEXT("]");
return s;
}
inline
TSTR & operator << ( TSTR & s, const POINT & pt )
{
s << TEXT("{x:") << pt.x
<< TEXT(" y:") << pt.y
<< TEXT("}");
return s;
}
inline
TSTR & operator << ( TSTR & s, const RECT & rc )
{
s << TEXT("{l:") << rc.left
<< TEXT(" t:") << rc.top
<< TEXT(" r:") << rc.right
<< TEXT(" b:") << rc.bottom
<< TEXT("}");
return s;
}
#endif // _TSTR_H_