版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/passFuHao/article/details/52926264
/*
stdex.h
c++标准库一些扩展函数或类。
注意:
1、在此文件中添加代码时不要产生c/c++标准库以外的依赖。
2、此文件中所有未注明异常安全等级的函数默认异常安全级别为“不抛出异常”或“提供基本的异常安全”保证。
< .fuhao >
< .2016年10月13日15时07分 >
< [email protected] >
< Copyright (C.) 2009-2016 fuhao software team., all rights reserved >
*/
#pragma once
// 屏蔽deprecated警告
__pragma (warning( push ));
__pragma(warning( disable:4996 ));
__pragma(warning( disable:4995 ));
// HttpTaskPool.h将FastFormat符号定义为宏
__pragma(push_macro("FastFormat"))
#undef FastFormat
#include <vector>
#include <assert.h>
#include <string.h>
#include <xstddef>
#include <xutility>
#include <memory>
#include <functional>
#include <Shlwapi.h>
__pragma(comment(lib, "Shlwapi.lib"))
#if defined( _AFX )
#include <afxstr.h>
#endif
#if defined( _ATL )
#include <atlstr.h>
#endif
#ifndef _FormatMessage_format_string_
#define _FormatMessage_format_string_
#endif
#if !defined( _STDEX )
#define _STDEX
#endif
#if !defined( _LOOPINDEX )
#define _LOOPINDEX
#endif
#if !defined( _STDEXSTRING )
#define _STDEXSTRING
#endif
namespace stdex
{
#if defined( WIN32 )
/*
ReadProcessString
ReadProcessMemory的读取字符串版。用来在无法得知字符串长度的情况下读取目标进程中的字符串。
模板参数:
_Cty,char或wchar_t或unsigned short类型。hProcess所描述的进程中lpBaseAddress指向的字符串类型。
参数:
hProcess,进程句柄。见ReadProcessMemory。
lpBaseAddress,字符串基址。见ReadProcessMemory函数lpBaseAddress参数。
lpNumberOfCharRead,读取的字符串长度。(不包括零结尾)。
返回值:
成功返回读取到当前进程中的字符串缓冲区,该缓冲区由VirtualAlloc 分配,用户在不需要使用后应调用VirtualFree
将其释放。
失败返回NULL,调用GetLastError可获得失败原因。
< .fuhao >
< .2017年5月6日18时29分 >
< [email protected] >
< Copyright (C.) 2009-2017 fuhao software team., all rights reserved >
*/
template< typename _Cty > _Cty* ReadProcessString( __in HANDLE hProcess, __in LPCVOID lpBaseAddress, __out SIZE_T *lpNumberOfCharRead )
{
// 不要退化 _Cty
static_assert(std::is_same< _Cty, CHAR >::value ||
std::is_same< _Cty, WCHAR >::value || std::is_same< _Cty, unsigned short >::value, "ReadProcessString只能读取由char[]或wchar_t[]组成的字符串");
struct /* 当前函数中无法确定该调用哪个strlen[A/W]来计算串长度,必须利用编译器自动匹配。 */
{
inline const size_t operator()( __in LPCSTR p )const
{ return (size_t )lstrlenA( p ); }
inline const size_t operator()( __in LPCWSTR p ) const
{ return (size_t)lstrlenW( p ); }
inline const size_t operator()( __in unsigned short *p ) const
{ return (size_t)lstrlenW( (LPCWSTR)p ); }
}CountString;
struct _CtyDx /* _Cty* 删除器 */
{ void operator()( const _Cty* p ){ VirtualFree( (LPVOID)p, IGNORE, MEM_RELEASE ); } };
typedef std::unique_ptr< _Cty, _CtyDx > _CtyPtr;
typedef std::list< std::pair< _CtyPtr, SIZE_T > > BufferChainType;
SYSTEM_INFO si;
BOOL bSucceeded = FALSE;
BufferChainType lstBufferChain;
_Cty *lpBuffer = NULL, *lpBasePtr = (_Cty*)lpBaseAddress;
SIZE_T cchNumberOfCharRead = 0, cchCountOfCharRead = 0;
LPVOID lpPageBaseAddress = NULL;
auto GetPageBaseAddress = []( LPCVOID lpAddress, DWORD dwPageSize )->LPVOID
{ return (LPVOID)(((DWORD)lpAddress) - (((DWORD)lpAddress) % dwPageSize)); };
*lpNumberOfCharRead = 0;
GetSystemInfo( &si );
lpPageBaseAddress = GetPageBaseAddress( lpBaseAddress, si.dwPageSize );
assert( lpBaseAddress >= lpPageBaseAddress );
/** 页面粒度一定是_Cty类型所占长度的整倍数,否则可能跨页。 lpBaseAddress
指向的地址也必须是经过对齐的,对齐粒度一定是_Cty类型长度,否则也可能跨页。*/
if( (DWORD)lpBaseAddress % sizeof( _Cty ) || si.dwPageSize % sizeof( _Cty ) ){
SetLastError( ERROR_MAPPED_ALIGNMENT );
return NULL;
}
/** 第一次读第一页剩余长度,往后每次读一页,但第一次分配内存时仍然分配一整页
内存,为了避免无法容纳零结尾符而产生额外的内存分配开销。*/
for( SIZE_T cbReadSize = si.dwPageSize - ((LPBYTE)lpBaseAddress - (LPBYTE)lpPageBaseAddress);; cbReadSize = si.dwPageSize )
{
lpBuffer = (_Cty*)VirtualAlloc( NULL, si.dwPageSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE );
if( lpBuffer == NULL )
{
break;
}
/** 把lpBuffer的最后一个字符设置为零,读完后检查最后一个字符是否还是零,如果仍然是
零则需要从头统计字符串长度,否则表示读取的字符串完全占满了缓冲区,不必再统计长度
直接进行下一次读取即可。*/
lpBuffer[cbReadSize / sizeof( _Cty ) - 1] = 0;
if( ReadProcessMemory( hProcess, (LPCVOID)lpBasePtr, lpBuffer, cbReadSize, NULL ) )
{
if( lpBuffer[cbReadSize / sizeof( _Cty ) - 1] == 0 ){
cchNumberOfCharRead = CountString( lpBuffer );
}
else {
cchNumberOfCharRead = cbReadSize / sizeof( _Cty );
}
// 如果push_back内抛出异常,此处的_CtyPtr(lpBuffer)会负责将lpBuffer删除。
lstBufferChain.push_back( std::make_pair( _CtyPtr( lpBuffer ), cchNumberOfCharRead ) );
lpBasePtr += cchNumberOfCharRead;
cchCountOfCharRead += cchNumberOfCharRead;
if( lpBuffer[cbReadSize / sizeof( _Cty ) - 1] == 0 )
{
bSucceeded = TRUE;
break;
}
}
else
{
VirtualFree( lpBuffer, 0, MEM_RELEASE );
break;
}
}
BufferChainType::iterator it( lstBufferChain.begin() ), ed( lstBufferChain.end() );
/** 一次也没读成功,或者内存分配失败。 */
if( !bSucceeded )
{
return NULL;
}
assert( lstBufferChain.size() != 0 );
if( lstBufferChain.size() == 1 /* 只读了一次 */ )
{
/**
it->first指向的字符串没有零结尾,但内存长度一定是si.dwPageSize所以,
也许剩余的内存应该能装下零结尾符。如果剩余的内存不足以容纳零结尾符,
则继续向下执行重新分配内存并拷贝……
*/
if( it->second < si.dwPageSize / sizeof( _Cty ) )
{
*lpNumberOfCharRead = cchCountOfCharRead;
lpBuffer = it->first.release();
lpBuffer[it->second] = 0;
return lpBuffer;
}
}
_Cty *pResult = (_Cty*)VirtualAlloc( NULL, cchCountOfCharRead * sizeof( _Cty ) + sizeof( _Cty ), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE );
if( pResult == NULL )
{
return NULL;
}
for( SIZE_T cchNumberOfWrited = 0; it != ed; it++ )
{
CopyMemory( &pResult[cchNumberOfWrited], it->first.get(), it->second * sizeof( _Cty ) );
cchNumberOfWrited += it->second;
}
*lpNumberOfCharRead = cchCountOfCharRead;
pResult[cchCountOfCharRead] = 0;
return pResult;
}
#endif // if defined( WIN32 )
/** std::[w]string不提供任何方法操作其内部对象,调API用std::[w]string极其不爽,还不支持Format。
CString没迭代器……用标准算法简直自讨苦吃还要MFC或ATL当累赘,以下字符串类既方便调API又
方便用标准算法,但阉割了部分CString功能。比如不支持BSTR……,以后再加吧。
以下配置信息写入 autoexp.dat 文件的Visualizer节并关闭VS调试选项中“在变量窗口中显示
对象原始结构”以支持调试时预览字符串;
[Visualizer]
stdex::StringT<char,*>{
preview ( #if (($e._Myres) < ($e._BUF_SIZE)) ( [$e._Bx._Buf,s] ) #else ( [$e._Bx._Ptr,s] ))
}
stdex::StringT<unsigned short,*>|stdex::StringT<wchar_t,*>{
preview ( #if (($e._Myres) < ($e._BUF_SIZE)) ( [$e._Bx._Buf,su] ) #else ( [$e._Bx._Ptr,su] ))
}
注意:
std::basic_string类没有虚析构函数,不要给 StringT 类增加任何成员变量和虚函数。
< .fuhao >
< .2016年10月25日14时56分 >
< [email protected] >
< Copyright (C.) 2009-2016 北京顺福群聚科技有限公司, all rights reserved >
*/
#if defined( _AFX ) || defined( _ATL )
template< class _StringType, class _MFCStringType, class StringTraits >
#else
template< class _StringType, class StringTraits >
#endif
class StringT : public std::basic_string < _StringType, std::char_traits<_StringType>, std::allocator<_StringType> >
{
public:
typedef std::basic_string < _StringType, std::char_traits<_StringType>, std::allocator<_StringType> > _BaseType;
#if defined( _AFX ) || defined( _ATL )
typedef StringT< _StringType, _MFCStringType, StringTraits > _MyType;
#else
typedef StringT< _StringType, StringTraits > _MyType;
#endif
/** 不继承构造函数;
using basic_string::basic_string; */
StringT() : _BaseType()
{ // 构造空字符串
};
StringT( const _MyType& _Right )
: _BaseType( _Right )
{ // 拷贝构造
}
StringT( const _BaseType& _Right )
: _BaseType( _Right )
{ // _Right参数是 std::[w]string 类型
}
StringT( const _BaseType& _Right, size_type _Roff,
size_type _Count = npos )
: _BaseType( _Right, _Roff, _Count )
{ // _Right参数是 std::[w]string 类型
}
StringT( const _StringType *_Ptr, size_type _Count )
: _BaseType( _Ptr, _Count )
{ // 用字符指针和长度构造,能接受空指针
}
StringT( const _StringType *_Ptr )
: _BaseType( _Ptr )
{ // 用字符指针构造,能接受空指针
}
StringT( size_type _Count, _StringType _Ch )
: _BaseType( _Count, _Ch )
{ // 串长度为 _Count,内容为 _Ch
}
#if defined( _AFX ) || defined( _ATL )
StringT( const _MFCStringType &_Right )
: StringT( (const _StringType*)_Right )
{ // 接受CString或CAtlString类型的构造函数;
// 接受CString或CAtlString类型的拷贝赋值也是此函数;
}
#endif
template<class _Iter >
StringT( _Iter _First, _Iter _Last )
: _BaseType( _First, _Last )
{ // 通过两个指针或迭代器构造
}
StringT( _MyType&& _Right ) _NOEXCEPT
: _BaseType( _Right )
{ // 移动构造
}
StringT( _BaseType&& _Right ) _NOEXCEPT
: _BaseType( _Right )
{ // 移动构造
}
#if defined( WIN32 )
/** 此函数有设计缺陷,当ReadProcessString失败时会抛出std::runtime_error异常,
而导致ReadProcessString失败的原因可能由目标进程退出或hProcess无效(或失效)
引起。VirtualAlloc失败也会导致ReadProcessString失败。又因构造函数无法向调用
者传递失败原因,所以只能抛出异常……
该函数暂被声名为弃用。
*/
__declspec(deprecated("String类中带HANDLE参数的构造函数有设计缺陷已被弃用,但尚无代替函数。请直接调用ReadProcessString从目标进程读取字符串"))
StringT( HANDLE hProcess, const _StringType *_Ptr )
: _BaseType()
{ // 从hProcess进程中读取_Ptr指向的字符串来构造
assert( hProcess && _Ptr );
SIZE_T cchStringSize = 0;
_StringType *lpString = ReadProcessString<_StringType>( hProcess, (LPCVOID)_Ptr, &cchStringSize );
if( !lpString ){
std::_Xruntime_error( "ReadProcessString没能正确读取目标进程中的字符串" );
}
assign( lpString, (typename size_type)cchStringSize );
if( !VirtualFree( lpString, 0, MEM_RELEASE ) ){
std::_Xruntime_error( "无法调用VirtualFree释放由ReadProcessString分配的内存。" );
}
}
#endif
_MyType &operator =( const _MyType & ) = default;
operator _StringType *() const
{
return GetBuffer();
}
operator const _StringType *() const
{
return GetBuffer();
}
inline void __cdecl FormatV( _In_z_ _Printf_format_string_ const _StringType *pszFormat, _In_ va_list args )
{
assert( pszFormat != NULL );
if( pszFormat == NULL ){
std::_Xinvalid_argument( __FUNCTION__"函数的pszFormat参数不能为NULL" );
}
const int nLength = StringTraits::GetFormattedLength( pszFormat, args );
if( nLength < 0 ){
std::_Xinvalid_argument( __FUNCTION__"函数的args参数有误" );
}
std::shared_ptr< _StringType >
pszBuffer( new _StringType[nLength + 1], []( const _StringType *p ){ delete[] p; } );
StringTraits::Format( pszBuffer.get(), nLength + 1, pszFormat, args );
// 赋值,不是 append
assign( pszBuffer.get() );
}
void __cdecl AppendFormatV(
_In_z_ _Printf_format_string_ const _StringType *pszFormat,
_In_ va_list args )
{
assert( pszFormat != NULL );
if( pszFormat == NULL ){
std::_Xinvalid_argument( __FUNCTION__"函数的pszFormat参数不能为NULL" );
}
const int nLength = StringTraits::GetFormattedLength( pszFormat, args );
if( nLength < 0 ){
std::_Xinvalid_argument( __FUNCTION__"函数的args参数有误" );
}
std::shared_ptr< _StringType >
pszBuffer( new _StringType[nLength + 1], []( const _StringType *p ){ delete[] p; } );
StringTraits::Format( pszBuffer.get(), nLength + 1, pszFormat, args );
// append,不是赋值
append( pszBuffer.get() );
}
inline void __cdecl Format( _In_z_ _FormatMessage_format_string_ const _StringType *pszFormat, ... )
{
va_list argList;
va_start( argList, pszFormat );
FormatV( pszFormat, argList );
va_end( argList );
}
inline void __cdecl AppendFormat(
_In_z_ _Printf_format_string_ const _StringType *pszFormat,
... )
{
assert( pszFormat != NULL );
va_list argList;
va_start( argList, pszFormat );
AppendFormatV( pszFormat, argList );
va_end( argList );
}
static _MyType __cdecl FastFormat( _In_z_ _Printf_format_string_ const _StringType *pszFormat,
... )
{
assert( pszFormat != NULL );
_MyType s;
va_list argList;
va_start( argList, pszFormat );
s.FormatV( pszFormat, argList );
va_end( argList );
return s;
}
static _MyType FormatMessage( _In_z_ _FormatMessage_format_string_ DWORD dwMessageId )
{
_MyType _Result;
_StringType * lpMessage = StringTraits::FormatMessage( dwMessageId );
if( lpMessage == NULL ){
return _Result;
}
_Result = lpMessage;
if( LocalFree( (HLOCAL)lpMessage ) != NULL ){
std::_Xruntime_error( __FUNCTION__"无法调用LocalFree释放占用的空间" );
}
return _Result;
}
_StringType *GetBuffer() const
{
return const_cast< _StringType*>( data() );
}
_Ret_cap_( nLength + 1 ) _StringType *GetBufferReserveLength( __in int nLength )
{
reserve( nLength ); // reserve后,对象可以容纳nLength个字符和一个零结尾符
return GetBuffer();
}
_Ret_cap_( nLength + 1 ) _StringType *GetBufferSetLength( _In_ int nLength )
{
SetLength( nLength );
return GetBuffer();
}
void ReleaseBuffer( _In_ int nNewLength = -1 )
{
if( nNewLength < 0 ) {
nNewLength = StringTraits::StringLengthN( GetBuffer(), capacity() );
}
/**
如果nNewLength >= size(),而且capacity() >= nNewLength则直接
修改内部变量_Mysize的值为nNewLength。避免resize内部调用append
把尾部覆盖成0,可能还会略微提升效率。
另外,如果不这么做,以下示例代码将会导致错误:
String s;
lstrcpyn( s.GetBufferReserveLength( 10 ), _T("1234567890") );
s.ReleaseBuffer();
以上代码中,s.ReleaseBuffer内部调用SetLength,若SetLength直接调用
resize,resize内部检查到size() < nLength则调用append(nLength-_Mysize,0)
向后增加nLength-_Mysize个0符号导致lstrcpyn向对象内写入的内容丢失。
< .fuhao >
< .2017年2月19日14时53分 >
< [email protected] >
< Copyright (C.) 2009-2017 fuhao software team., all rights reserved >
*/
if( capacity() >= (size_type)nNewLength && (size_type)nNewLength >= size() ){
/** c++ 标准并未规定 string 必须有_Mysize。_Mysize是VS2003里string的实现,
所以,修改 string::_Mysize 的代码实际通过 append函数完成的。当然,是个不
寻常的 append 。*/
size_type Excess = (size_type)nNewLength - size();
append( data() + size(), Excess );
}
else{
SetLength( nNewLength );
}
}
void SetLength( _In_ int nLength )
{
assert( nLength >= 0 );
resize( (size_type)nLength, 0 );
}
int GetLength() const _NOEXCEPT
{
return (int)size();
}
bool IsEmpty() const _NOEXCEPT
{
return(GetLength() == 0);
}
/** 此函数效率极低,若需高效替换,请自行实现替换算法。该函数仅为提供方便,对效率不敏感之处使用。*/
void Replace( _In_z_ const _StringType *pszOld, _In_z_ const _StringType *pszNew )
{
const size_type cchOld = StringTraits::StringLengthN( pszOld, (size_type)~0 ),
cchNew = StringTraits::StringLengthN( pszNew, (size_type)~0 );
for( size_type pos = 0; (pos = find( pszOld, pos )) != npos; pos += cchNew ){
replace( pos, cchOld, pszNew, cchNew );
}
}
void Replace( _In_ const _StringType chOld, _In_ const _StringType chNew )
{
std::replace( begin(), end(), chOld, chNew );
}
bool Trim() /* 剪除前后的空格、制表、回车、换行符 */
{
if( StringTraits::Trim( GetBuffer() ) )
{
ReleaseBuffer();
return true;
}
return false;
}
bool Trim( _In_ const _StringType * pszTrimChar )
{
if( StringTraits::Trim( GetBuffer(), pszTrimChar ) )
{
ReleaseBuffer();
return true;
}
return false;
}
int CompareNumber( _In_ const _StringType *lpStr2, int nChar )
{
return StringTraits::CompareNumber( data(), lpStr2, nChar );
}
int CompareIgnore( _In_ const _StringType *lpStr2 )
{
return StringTraits::CompareIgnore( data(), lpStr2 );
}
int CompareNumberIgnore( _In_ const _StringType *lpStr2, int nChar )
{
return StringTraits::CompareNumberIgnore( data(), lpStr2, nChar );
}
// 从pszSource中移除未包含在pszCharSet中的串。(该函数仅支持宽串)
void RemoveSpanExcluding( _In_z_ const wchar_t *pszCharSet )
{
StringTraits::RemoveSpanExcluding( GetBuffer(), GetLength(), pszCharSet );
ReleaseBuffer();
}
// 从pszSource中移除包含在pszCharSet中的串。(该函数仅支持宽串)
void RemoveSpanIncluding( _In_z_ const wchar_t *pszCharSet )
{
StringTraits::RemoveSpanIncluding( GetBuffer(), GetLength(), pszCharSet );
ReleaseBuffer();
}
// 以 _Ch 为分隔符拆分字符串为一组字符串。返回拆分后的一组字符串。用户可通过模板参数
// _Rty 指定接收返回的字符串组的容器,通常是 vector< String > 或 list< String > 和 [d]queue< String > 等。
template< typename _Rty > _Rty Split( const _StringType _Ch ) const
{
return StringTraits::SplitString< _Rty >( GetBuffer(), _Ch );
}
};
template< class _Cty > class StringTraitsBase
{
public:
static_assert(std::is_same< _Cty, wchar_t >::value || std::is_same< _Cty, char >::value || std::is_same< _Cty, unsigned short >::value,
"StringTraitsT只接受 wchar_t、char和unsigned short类型的模板参数");
typedef _Cty* _CtyPtr;
/*
RemoveIf
从字符串中移除满足 _Pred 条件的字符。
参数:
pszSource,零结尾字符串,移除操作在该字符串上进行。
cchSizeOfSource,pszSource指向的字符串长度。(不包括零结尾符在内的长度,既,如果有字符串 "123",其长度为3)
_Pred,谓词,用以表达是否应当移除某个字符。
返回值:
无意义。
注意:
cchSizeOfSource的值通常由strlen或其它统计字符串长度的函数获得,而非 _countof 或 sizeof 获得。
警告:
RemoveIf<char>版本将不保证对中文作正确处理。
*/
template< typename _Pr > static inline void __cdecl RemoveIf(
_Inout_cap_( cchSizeOfSource ) _CtyPtr pszSource, _In_ size_t cchSizeOfSource, _Pr _Pred )
{
_CtyPtr pszBegin = pszSource, pszPtr = pszSource,
pszEnd = pszSource + cchSizeOfSource;
for( ; pszBegin != pszEnd && *pszBegin; pszBegin++ )
{
if( _Pred( *pszBegin ) )
{
*pszPtr++ = *pszBegin;
}
}
*pszPtr = 0;
}
};
class StringWTraits : public StringTraitsBase< wchar_t >
{
public:
static bool __cdecl Trim( __inout LPWSTR psz, __in LPCWSTR pszTrimChars = L" \t\r\n" )
{
return !!StrTrimW( psz, pszTrimChars );
}
static int __cdecl CompareNumber( __in LPCWSTR lpStr1, __in LPCWSTR lpStr2, int nChar )
{
return StrCmpNW( lpStr1, lpStr2, nChar );
}
static int __cdecl CompareIgnore( __in LPCWSTR lpStr1, __in LPCWSTR lpStr2 )
{
return StrCmpIW( lpStr1, lpStr2 );
}
static int __cdecl CompareNumberIgnore( __in LPCWSTR lpStr1, __in LPCWSTR lpStr2, int nChar )
{
return StrCmpNIW( lpStr1, lpStr2, nChar );
}
static int __cdecl GetFormattedLength(
_In_z_ _Printf_format_string_ LPCWSTR pszFormat, va_list args ) throw()
{
return _vscwprintf( pszFormat, args );
}
static int __cdecl Format(
_Out_writes_( nLength ) LPWSTR pszBuffer,
_In_ size_t nLength,
_In_ _Printf_format_string_ LPCWSTR pszFormat, va_list args ) throw()
{
return vswprintf_s( pszBuffer, nLength, pszFormat, args );
}
static int __cdecl StringLengthN(
_In_reads_opt_z_( sizeInXChar ) const wchar_t* psz,
_In_ size_t sizeInXChar ) throw()
{
if( psz == NULL )
{
return(0);
}
return(int( wcsnlen( psz, sizeInXChar ) ));
}
#if defined( WIN32 )
static __success( return != NULL ) LPWSTR FormatMessage( _In_z_ _FormatMessage_format_string_ DWORD dwMessageId )
{
LPWSTR lpResult = NULL;
if( !::FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, dwMessageId, GetThreadLocale(),
(LPWSTR)&lpResult, 0, (va_list*)NULL ) ){
return NULL;
}
// LocalFree( (HLOCAL)lpResult );
return lpResult;
}
#endif
// 从pszSource中移除未包含在pszCharSet中的串。
static void __cdecl RemoveSpanExcluding(
_Inout_cap_( cchSizeOfSource ) wchar_t *pszSource, _In_ size_t cchSizeOfSource, _In_z_ const wchar_t *pszCharSet )
{
return RemoveIf( pszSource, cchSizeOfSource, [pszCharSet]( wchar_t ch ){ return wcschr( pszCharSet, ch ); } );
}
// 从pszSource中移除包含在pszCharSet中的串。
static void __cdecl RemoveSpanIncluding(
_Inout_cap_( cchSizeOfSource ) wchar_t *pszSource, _In_ size_t cchSizeOfSource, _In_z_ const wchar_t *pszCharSet )
{
return RemoveIf( pszSource, cchSizeOfSource, [pszCharSet]( wchar_t ch ){ return !wcschr( pszCharSet, ch ); } );
}
static const wchar_t *_StrChr( __in const wchar_t *Src, __in const wchar_t _Ch )
{
if( !Src || !*Src )
return NULL;
const wchar_t *Ptr( Src );
for( ; *Ptr && *Ptr != _Ch; ++Ptr );
return Ptr;
}
template< typename _Rty > static _Rty SplitString( __in const wchar_t *Src, __in const wchar_t _Ch )
{
_Rty rs;
const wchar_t *Ptr( Src ), *Next( NULL );
while( Next = _StrChr( Ptr, _Ch ) )
{
rs.push_back( { Ptr, (size_t)(Next - Ptr) } );
Ptr = Next + !!(*Next);
}
if( Ptr && !*Ptr && *(Ptr - 1) == _Ch )
rs.push_back( { (const wchar_t*)nullptr, 0 } );
return std::move( rs );
}
};
class StringATraits : public StringTraitsBase< char >
{
public:
static bool __cdecl Trim( __inout LPSTR psz, __in LPCSTR pszTrimChars = " \t\r\n" )
{
return !!StrTrimA( psz, pszTrimChars );
}
static int __cdecl CompareNumber( __in LPCSTR lpStr1, __in LPCSTR lpStr2, int nChar )
{
return StrCmpNA( lpStr1, lpStr2, nChar );
}
static int __cdecl CompareIgnore( __in LPCSTR lpStr1, __in LPCSTR lpStr2)
{
return StrCmpIA( lpStr1, lpStr2 );
}
static int __cdecl CompareNumberIgnore( __in LPCSTR lpStr1, __in LPCSTR lpStr2, int nChar )
{
return StrCmpNIA( lpStr1, lpStr2, nChar );
}
static int __cdecl GetFormattedLength(
_In_z_ _Printf_format_string_ LPCSTR pszFormat, va_list args ) throw()
{
return _vscprintf( pszFormat, args );
}
static int __cdecl Format(
_Out_writes_to_( nlength, return ) LPSTR pszBuffer,
_In_ size_t nlength,
_In_z_ _Printf_format_string_ LPCSTR pszFormat, va_list args ) throw()
{
return vsprintf_s( pszBuffer, nlength, pszFormat, args );
}
static int __cdecl StringLengthN(
_In_reads_opt_z_( sizeInXChar ) const char* psz,
_In_ size_t sizeInXChar ) throw()
{
if( psz == NULL )
{
return(0);
}
return(int( strnlen( psz, sizeInXChar ) ));
}
#if defined( WIN32 )
static __success( return != NULL ) LPSTR FormatMessage( _In_z_ _FormatMessage_format_string_ DWORD dwMessageId )
{
LPSTR lpResult = NULL;
if( !::FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, dwMessageId, GetThreadLocale(),
(LPSTR)&lpResult, 0, NULL ) ){
return NULL;
}
// LocalFree( (HLOCAL)lpResult );
return lpResult;
}
#endif
// 从pszSource中移除未包含在pszCharSet中的串。
static void __cdecl RemoveSpanExcluding(
_Inout_cap_( cchSizeOfSource ) char *pszSource, _In_ size_t cchSizeOfSource, _In_z_ const char *pszCharSet )
{
return RemoveIf( pszSource, cchSizeOfSource, [pszCharSet]( char ch ){ return strchr( pszCharSet, ch ); } );
}
// 从pszSource中移除包含在pszCharSet中的串。
static void __cdecl RemoveSpanIncluding(
_Inout_cap_( cchSizeOfSource ) char *pszSource, _In_ size_t cchSizeOfSource, _In_z_ const char *pszCharSet )
{
return RemoveIf( pszSource, cchSizeOfSource, [pszCharSet]( char ch ){ return !strchr( pszCharSet, ch ); } );
}
static const char *_StrChr( __in const char *Src, __in const char _Ch )
{
if( !Src || !*Src )
return NULL;
const char *Ptr( Src );
for( ; *Ptr && *Ptr != _Ch; ++Ptr );
return Ptr;
}
template< typename _Rty > static _Rty SplitString( __in const char *Src, __in const char _Ch )
{
_Rty rs;
const char *Ptr( Src ), *Next( NULL );
while( Next = _StrChr( Ptr, _Ch ) )
{
rs.push_back( { Ptr, (size_t)(Next - Ptr) } );
Ptr = Next + !!(*Next);
}
if( Ptr && !*Ptr && *(Ptr - 1) == _Ch )
rs.push_back( { (const char*)nullptr, 0 } );
return std::move( rs );
}
};
#if defined( _UNICODE )
typedef StringWTraits StringTTraits;
#else
typedef StringATraits StringTTraits;
#endif // end if defined( _UNICODE )
#if defined( _ATL )
typedef StringT < wchar_t, ATL::CAtlStringW, StringWTraits > AtlStringW;
typedef StringT< char, ATL::CAtlStringA, StringATraits > AtlStringA;
typedef StringT< TCHAR, ATL::CAtlString, StringTTraits > AtlString;
#if !defined( _AFX ) // 只有ATL没有MFC
typedef AtlStringW StringW;
typedef AtlStringA StringA;
typedef AtlString String;
#endif // endif !defined( _AFX )
#endif // endif defiend( _ATL )
#if defined( _AFX ) // 如果有MFC
typedef StringT < wchar_t, CStringW, StringWTraits > StringW;
typedef StringT< char, CStringA, StringATraits > StringA;
typedef StringT< TCHAR, CString, StringTTraits > String;
#endif
#if !defined( _AFX ) && !defined( _ATL ) // 如果既没MFC也没ATL
typedef StringT < wchar_t, StringWTraits > StringW;
typedef StringT< char, StringATraits > StringA;
#if defined( _UNICODE )
typedef StringW String;
#else
typedef StringA String;
#endif // end if defined( _UNICODE )
#endif // end #if defined( _AFX ) || defined( _ATL )
}
/* 特化两个hash函数以支持标准库容器。
注意:
不要去掉以下代码中std::hash和stdex::StringW以及stdex::StringA前的std和stdex
作用域限定符。该限定符用于强调此hash函数针对stdex作用域下的StringW或StringA
类型,而非用户代码环境中当前可见的StringW或StringA类型。
*/
template<>
struct std::hash < stdex::StringW >
: public std::hash< std::wstring >{
};
template<>
struct std::hash < stdex::StringA >
: public std::hash< std::string > {
};
__pragma(pop_macro( "FastFormat" ));
// assert里写了 warning pop 了。
__pragma(warning( disable:4193 ))
__pragma(warning( pop ));
注意:
不要在不同模块(DLL或静态库模块)间传递String类的对象,如果必须,请保证当前模块与被调模块有相同的MFC、ATL和C++环境并保证两模块间使用的MFC、ATL以及C++版本相同。
2017年6月27日11时11分更新:
在String类中增加RemoveSpanExcluding和RemoveSpanIncluding函数,用以从String对象中移除包含(或不含)在某个集合内的字符。
在stdex空间中增加ReadProcessString函数,用以从其它进程读取字符串。
修改FormatV和AppendFormatV函数,使符合异常安全之最高标准。