这里讲解的是针对vs2010之前的版本的(即vs2005,vs2008。因为vs2010对于这方面有了一些改动),并以CEGUI 0.7.9版本(因为这个版本的CEGUI的String对象采用统一utf32编码,调试时很难查看字符串信息)中的CEGUI::String类型为例讲解,
首先介绍一点此版本的CEGUI::String类需要注意的地方。
有一个很重要的地方需要注意,0.7.9的版本中CEGUI::String对于const char*,以及对于const utf8*(即const unsigned char*)的构造函数有区别。
很多时候我们想通过CEGUI::String::c_str()函数,让CEGUI::String返回c风格字符串,但是我要告诉你,CEGUI::String::c_str()是个文不达意的函数,其真正功能是将保存的utf32字符串转换成utf8编码的字符串。这对于ascii字符集中的字符没有什么问题,但是对非ASCII字符集的字符,你调用CEGUI::String::c_str()将会返回乱码。
CEGUI::String strTest = "中国"; std::cout << strTest.c_str() << std::endl;
这是为什么呢?这正是前面第一点提到的,因为CEGUI::String::String( const char* )构造函数,对于非ASCII字符集字符串的构造根本就是错误的。这点在CEGUI::String::Assign(const utf8*)中的注释中CEGUI已经考虑到了。但是未做过多处理。
然后我们来看一下如果让vs调试器帮你格式化显示CEGUI::String类型。
用过CEGUI.0.7.9的开发人员都知道,CEGUI::String类中直接将字符串全部保存到utf32(即一个字符为4个字节)的缓冲区中!这将意味着vs调试器不能直接查看CEGUI::String里面的字符,因为这个缓冲区里面到处都有c风格字符串的结尾符(即字节的值为0)。所以你很难查看到一个CEGUI::String对象的字符含义。当然如果你的CEGUI::String里面只保存的是ascii字符,那么有个简陋的方法是可以看到字符串。那就是使用VS的Memory查看器,我们将字符串头地址传给Memory查看器,Memory查看器会自动将能显示的ascii字符显示出来。这样能勉强能满足你的愿望。
但是,如果你的CEGUI::String对象,保存的是中文,那么没有任何简单的方法能让你再次看到其字符含义。要想让其格式化显示中文,我们必须给vs调试器写一个小插件(听着插件,似乎很麻烦,但实际上很简单,主要就牵扯到几个函数)。以下是具体的步骤:
HRESULT WINAPI CustomViewer( DWORD dwAddress, // low 32-bits of address DEBUGHELPER *pHelper, // callback pointer to access helper functions int nBase, // decimal or hex BOOL bIgnore, // not used char *pResult, // where the result needs to go size_t max, // how large the above buffer is DWORD dwReserved // always pass zero )只要函数类型符合就可以,函数名字随便。只要我们完成这个函数,然后调试器每次显示你的数据类型的对象的时候,就会调用这个接口,你所需要做的就是将想要显示的信息填充到pResult所指向的字符缓冲区中。这是我们的中心思想,但是为了完成这个任务,我们有不少困难需要克服。后面会一一列举。
typedef struct tagDEBUGHELPER { DWORD dwVersion; HRESULT (WINAPI *ReadDebuggeeMemory)( struct tagDEBUGHELPER *pThis, //DEBUGHELPER pointer DWORD dwAddr,//the address of object you want to show formatted prompt information DWORD nWant, //the object size in byte. VOID* pWhere, //the dest buffer for storing the object DWORD *nGot );//number bytes are transferred. // from here only when dwVersion >= 0x20000 DWORDLONG (WINAPI *GetRealAddress)( struct tagDEBUGHELPER *pThis ); //use for 64-bit system. HRESULT (WINAPI *ReadDebuggeeMemoryEx)( struct tagDEBUGHELPER *pThis, DWORDLONG qwAddr, DWORD nWant, VOID* pWhere, DWORD *nGot ); int (WINAPI *GetProcessorType)( struct tagDEBUGHELPER *pThis ); } DEBUGHELPER;
// CEGUIDbg.cpp : Defines the exported functions for the DLL application. //#include "stdafx.h" #include <Windows.h> #include "tchar.h" #include <string> #include <sstream> #include <vector> #include "ceguistring.h" #define ADDIN_API __declspec(dllexport) typedef struct tagDEBUGHELPER { DWORD dwVersion; HRESULT (WINAPI *ReadDebuggeeMemory)( struct tagDEBUGHELPER *pThis, //DEBUGHELPER pointer DWORD dwAddr,//the address of object you want to show formatted prompt information DWORD nWant, //the object size in byte. VOID* pWhere, //the dest buffer for storing the object DWORD *nGot );//number bytes are transferred. // from here only when dwVersion >= 0x20000 DWORDLONG (WINAPI *GetRealAddress)( struct tagDEBUGHELPER *pThis ); //use for 64-bit system. HRESULT (WINAPI *ReadDebuggeeMemoryEx)( struct tagDEBUGHELPER *pThis, DWORDLONG qwAddr, DWORD nWant, VOID* pWhere, DWORD *nGot ); int (WINAPI *GetProcessorType)( struct tagDEBUGHELPER *pThis ); } DEBUGHELPER; // 多字节编码转为UTF8编码 bool MultiByteToUtf8( char* pszDestUtf8, int iDestUtf8Size, const char* pszMultiByte, int iMultiByteSize = -1 ) { if( NULL == pszDestUtf8 || NULL == pszMultiByte ) { return false; } // convert an MBCS string to widechar int iWideCharSize = MultiByteToWideChar( CP_ACP, 0, pszMultiByte, iMultiByteSize, NULL, 0 ); std::vector< WCHAR > vctWideChar( iWideCharSize ); int iNumWritten = MultiByteToWideChar( CP_ACP, 0, pszMultiByte, iMultiByteSize, &vctWideChar.front(), iWideCharSize ); if( iNumWritten != iWideCharSize ) { return false; } // convert an widechar string to utf8 int iUtf8Size = WideCharToMultiByte(CP_UTF8, 0, &vctWideChar.front(), -1, NULL, 0, NULL, NULL); if ( iUtf8Size <= 0) { return false; } if( iUtf8Size > iDestUtf8Size ) { iUtf8Size = iDestUtf8Size; } iNumWritten = WideCharToMultiByte( CP_UTF8, 0, &vctWideChar.front(), -1, pszDestUtf8, iUtf8Size, NULL, NULL ); if ( iNumWritten != iUtf8Size ) { return false; } return true; } ADDIN_API HRESULT WINAPI CEGUIDbg_String(DWORD dwAddress, DEBUGHELPER *pHelper, int nBase, BOOL bUniStrings, char *pResult, size_t max, DWORD reserved ) { CEGUI::String strDebug; DWORD nGot; //get CEGUI::String data member. if (pHelper->ReadDebuggeeMemory(pHelper,dwAddress,sizeof( strDebug),&strDebug,&nGot) != S_OK) { return E_FAIL; } if( nGot != sizeof( strDebug ) ) { return E_FAIL; } const CEGUI::utf32* pszUtf32 = strDebug.ptr(); int iLength = strDebug.length(); std::vector< CEGUI::utf32 > vctBuffer; //if the string data is stored in a memory allocated by new(), we have to copy the data to out memory block. if( iLength > STR_QUICKBUFF_SIZE ) { vctBuffer.resize( iLength ); if( S_OK != pHelper->ReadDebuggeeMemory( pHelper, ( DWORD )pszUtf32, iLength * sizeof( CEGUI::utf32 ), &vctBuffer.front(), &nGot ) ) { return E_FAIL; } if( nGot != vctBuffer.size() * sizeof( CEGUI::utf32 ) ) { return E_FAIL; } pszUtf32 = &vctBuffer.front(); } //get ascii character. //although the data pointer is utf32*, but the data isn't encoded by utf32 if you pass const char* to CEGUI::String constructor. In contrary, it only store each ascii character //in a utf32-type element. int iSize = iLength + 1; if( iSize > max ) { iSize = max; iLength = iSize - 1; } std::vector< char > vctAscii( iSize ); for( int i = 0; i < iLength; ++i ) { vctAscii[ i ] = ( char )( unsigned char )pszUtf32[ i ]; } vctAscii[ iLength ] = 0; //convert ascii character set to utf8 character set. //Because debugger accepts utf8 character set. //If you pass ascii string to pResult, chinese character can't be shown. if( false == MultiByteToUtf8( pResult, max, &vctAscii.front() ) ) { return E_FAIL; } //set all data to 0, then CEGUI::String::~String won't delete anything should't be deleted. memset( &strDebug, 0, sizeof( strDebug ) ); return S_OK; }
[AutoExpand] CEGUI::String=$ADDIN(ceguidbg.dll,?CEGUIDbg_String@@YGJKPAUtagDEBUGHELPER@@HHPADIK@Z)
; $ADDIN allows external DLLs to be added to display even more complex ; types via the EE Add-in API. The first argument is the DLL name, the ; second argument is the name of the export from the DLL to use. For ; further information on this API see the sample called EEAddIn.
CEGUI::String strDebug; DWORD nGot; //get CEGUI::String data member. if (pHelper->ReadDebuggeeMemory(pHelper,dwAddress,sizeof( strDebug),&strDebug,&nGot) != S_OK) { return E_FAIL; } if( nGot != sizeof( strDebug ) ) { return E_FAIL; }
const CEGUI::utf32* pszUtf32 = strDebug.ptr(); int iLength = strDebug.length(); std::vector< CEGUI::utf32 > vctBuffer; //if the string data is stored in a memory allocated by new(), we have to copy the data to out memory block. if( iLength > STR_QUICKBUFF_SIZE ) { vctBuffer.resize( iLength ); if( S_OK != pHelper->ReadDebuggeeMemory( pHelper, ( DWORD )pszUtf32, iLength * sizeof( CEGUI::utf32 ), &vctBuffer.front(), &nGot ) ) { return E_FAIL; } if( nGot != vctBuffer.size() * sizeof( CEGUI::utf32 ) ) { return E_FAIL; } pszUtf32 = &vctBuffer.front(); }
//get ascii character. //although the data pointer is utf32*, but the data isn't encoded by utf32 if you pass const char* to CEGUI::String constructor. In contrary, it only store each ascii character //in a utf32-type element. int iSize = iLength + 1; if( iSize > max ) { iSize = max; iLength = iSize - 1; } std::vector< char > vctAscii( iSize ); for( int i = 0; i < iLength; ++i ) { vctAscii[ i ] = ( char )( unsigned char )pszUtf32[ i ]; } vctAscii[ iLength ] = 0;
//convert ascii character set to utf8 character set. //Because debugger accepts utf8 character set. //If you pass ascii string to pResult, chinese character can't be shown. if( false == MultiByteToUtf8( pResult, max, &vctAscii.front() ) ) { return E_FAIL; }
//set all data to 0, then CEGUI::String::~String won't delete anything should't be deleted. memset( &strDebug, 0, sizeof( strDebug ) );
终于搞定了,如果还有不明白的地方,请留言!
不想自己动手写的,可以直接下载我上传到csdn的资源:http://download.csdn.net/detail/xujiezhige/5740411