mirror of https://github.com/tongzx/nt5src
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
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_
|