zoukankan      html  css  js  c++  java
  • ATL字符串转换类

    字符串的ASCII和UNICODE之间的转换很常用,Win32提供了API函数MultiByteToWideChar和WideCharToMultiByte来提供这种功能。但凡Win32的API,参数调用都不会少,因此使用起来也就觉得有点繁琐。ATL3中提供了字符串转换宏,如T2W、A2T等,不过使用它们需要借助本地变量,因此在使用之前需要声明USES_CONVERSION宏来声明本地变量.而且还有个很大的缺陷:转换宏总是使用栈存储,它们在运行时调用_alloca在本地栈上分配额外的空间,如果在函数中循环地进行转换,很可能因为栈空间用尽而崩溃,因为栈空间在函数退出后才能释放。还有个很严重的问题:若在C++ catch块中使用转换宏,_alloca调用会搅乱栈上的异常跟踪信息而使程序崩溃。

    ATL还提供了另一套转换宏:_Ex系列,使用如刚才提到的一样,使用前需声明本地变量,通过USES_CONVERSION_EX宏声明,继而调用T2W_EX、W2A_EX等宏,不过这些宏需要提供2个参数,第一个参数同上,第二个参数指定一个界值,如果转换缓冲小于这个值,则通过_alloca在栈上分配内存,若缓冲大于指定的值,则在堆上分配,因此可以避免栈溢出。但其在C++ catch块中仍然无能为力.

    在ATL7中引入了字符串转换类,所有的类采用统一的命名格式:C<源格式简写>2<目标格式简写>,如CA2W用于将ASCII格式的字符串转换为UNICODE格式.具体的有:CA2W、CA2T、CA2WEX、CA2CT、CW2T、CW2A、CW2AWX等等,实际上真正完成ASCII到UNICODE之间的转换的只有CA2WEX和CW2AEX两个类,以CW2AEX为例简单地介绍一下,首先看其源码:

    template< int t_nBufferLength = 128 >
    class CW2AEX
    {
    public:
        CW2AEX( __in_opt LPCWSTR psz ) 
    throw() :
            m_psz( m_szBuffer )
        {
            Init( psz, _AtlGetConversionACP() );
        }
        CW2AEX( __in_opt LPCWSTR psz, UINT nCodePage ) 
    throw() :
            m_psz( m_szBuffer )
        {
            Init( psz, nCodePage );
        }
        
    ~CW2AEX() throw()
        {        
            AtlConvFreeMemory(m_psz,m_szBuffer,t_nBufferLength);
        }

        
    operator LPSTR() const throw()
        {
            
    return( m_psz );
        }

    private:
        
    void Init( __in_opt LPCWSTR psz, __in UINT nConvertCodePage ) throw()
        {
            
    if (psz == NULL)
            {
                m_psz 
    = NULL;
                
    return;
            }
            
    int nLengthW = lstrlenW( psz )+1;         
            
    int nLengthA = nLengthW*4;
            
            AtlConvAllocMemory(
    &m_psz,nLengthA,m_szBuffer,t_nBufferLength);

            BOOL bFailed
    =(0 == ::WideCharToMultiByte( nConvertCodePage, 0, psz, nLengthW, m_psz, nLengthA, NULL, NULL ));
            
    if (bFailed)
            {
                
    if (GetLastError()==ERROR_INSUFFICIENT_BUFFER)
                {
                    nLengthA 
    = ::WideCharToMultiByte( nConvertCodePage, 0, psz, nLengthW, NULL, 0, NULL, NULL );
                    AtlConvAllocMemory(
    &m_psz,nLengthA,m_szBuffer,t_nBufferLength);
                    bFailed
    =(0 == ::WideCharToMultiByte( nConvertCodePage, 0, psz, nLengthW, m_psz, nLengthA, NULL, NULL ));
                }            
            }
            
    if (bFailed)
            {
                AtlThrowLastWin32();
            }
        }

    public:
        LPSTR m_psz;
        
    char m_szBuffer[t_nBufferLength];

    private:
        CW2AEX( 
    const CW2AEX& ) throw();
        CW2AEX
    & operator=const CW2AEX& ) throw();
    };

    其有个模板参数t_nBufferLength用于指定缓冲的字符数组的大小,在Init方法中调用AtlConvAllocMemory方法来分配缓冲内存,如果所需的缓冲大小超过了t_nBufferLength设定的值,那么将调用calloc/_recalloc在堆上分配内存缓冲。

    使用这些转换类十分方便,不在需要本地变量,Demo如下:

        void  testDemo( LPCTSTR lpszDemo ){}

        
    //调用
        testDemo( CW2T( L"test string" ) );

    参考资料: 《深入解析ATL(第2版)》

  • 相关阅读:
    【LSA推荐算法】简单理解
    【数据分析案例】用户消费行为
    【Django】rest_framework 序列化自定义替换返回值
    【Django+Element UI】使用一个接口文件,搞定分页获取数据,模糊查询后分页获取数据
    【Django后端分离】使用element-ui文件上传
    JavaScript数组去重方法总结
    MySQL索引优化--对前缀索引使用like模糊匹配时的实际索引选择
    Linux命令--top
    Linux命令--free
    MySQL中的表的列设置为varchar(0)或char(0)
  • 原文地址:https://www.cnblogs.com/fangkm/p/1439493.html
Copyright © 2011-2022 走看看