棘手的UNICODE

项目中要处理一些欧洲的杂志,西欧字体的显示全部是乱码,升级了richedit宽字符版本,但是仍然无效,richedit2.0只能在unicode环境下才能正常工作。这个项目前前后后很多人接手,后来没人敢接了,里面代码也杂乱无章,不知为什么当初他们没用unicode,现在太庞大了,改成unicode显得很不现实(大概有一二十万行代码),也只好硬着头皮手动去改。

 

1. Find & Replace

微软的IDE还是不错的,Find & Replace 结合正则表达式,替换每个" "加上_T(""),省了很多手动查找的工夫。

// 所有字符串

/("[^"]*"/)             ----> _T(/1)

 

// 前后无括号的字符串

/([^(]/)/("[^"]*"/)  ---->  /1_T(/2)

 

// 所有char、char * 声明

char                      -----> TCHAR

char *                   -----> TCHAR *

 

2. String Function

C库中所有多字节处理函数都要改成mb/wc格式的(_t开头的), 能同时处理宽字节和多字节的字符串,msdn上都有一一对应。

 

3. CString

对CString印象一直很不好,效率是一方面, 在底层实现上也是很不雅,STL感觉好些。下面是CString封装的数据块:

struct CStringData
{
    long nRefs;             // reference count
    int nDataLength;        // length of data (including terminator)
    int nAllocLength;       // length of allocation
    // TCHAR data[nAllocLength]

    TCHAR* data()           // TCHAR* to managed data
        { return (TCHAR*)(this+1); }
};

 

工程中使用大量CString的GetBuffer(), 其实它返回的就是这个TCHAR* data,而工程中很多底层模块是用多字节实现的,这些已经不可能改成unicode的了, 还是需要用到char * 类型的buffer, 只好将GetBuffer()获取的宽字节buffer转变一下,用WideCharToMultiByte和

MultiByteToWideChar可以简单实现,为了方便期间,写了个CString的委托类,也是个智能指针,将buffer自由转换,自动释放buffer。

// StringW
class StringW
{
public:
    // constructors
    StringW():m_nLength(0) {
        m_pData = new wchar_t[1];
        m_pData[0] = 0;
    }
    StringW(LPCWSTR lpsz) {
        int nSrcLen = lpsz != NULL ? wcslen(lpsz) : 0;
        m_nLength = nSrcLen;
        m_pData = new wchar_t[m_nLength+1];
        m_pData[m_nLength] = 0;
        memcpy(m_pData,lpsz,nSrcLen * sizeof(wchar_t));
    }
    StringW(LPCSTR lpsz) {
        int nSrcLen = lpsz != NULL ? lstrlenA(lpsz) : 0;
        if (nSrcLen)
        {
            m_nLength = ::MultiByteToWideChar(CP_ACP, 0, lpsz, nSrcLen, NULL,
                0);
            m_pData = new wchar_t[m_nLength+1];
            m_pData[m_nLength] = 0;
            ::MultiByteToWideChar(CP_ACP, 0, lpsz, nSrcLen, m_pData,
                m_nLength+1);   
        }
        else {
            m_pData = new wchar_t[1];
            m_pData[0] = 0;
        }
    }
    StringW(CString& strSrc) {
        int nSrcLen = strSrc.GetLength();
        if (m_nLength) {
            LPTSTR lpsz = strSrc.GetBuffer(nSrcLen);
#ifndef _UNICODE
            m_nLength = ::MultiByteToWideChar(CP_ACP, 0, lpsz, nSrcLen, NULL,
                0);
            m_pData = new wchar_t[m_nLength+1];
            m_pData[m_nLength] = 0;
            ::MultiByteToWideChar(CP_ACP, 0, lpsz, nSrcLen, m_pData,
                m_nLength+1);       
#else
            m_nLength = nSrcLen;
            m_pData = new wchar_t[m_nLength+1];
            m_pData[m_nLength] = 0;
            memcpy(m_pData,lpsz,nSrcLen * sizeof(wchar_t));
#endif
        } else {
            m_pData = new wchar_t[1];
            m_pData[0] = 0;
        }
    }
   
    // attributes and member functions
    inline wchar_t * GetBuffer() { return m_pData; }
    inline int GetLength() { return m_nLength; }
    operator wchar_t* () const {
        return m_pData;
    }
    operator LPCWSTR() const {
        return m_pData;
    }
    friend CString operator+(const CString& string, const StringW& stringW) {
        ASSERT((LPCWSTR)stringW!=NULL);
        CString s(string);
        s += (LPCWSTR)stringW;
        return s;
    }
public:
    ~StringW()
    {
        if (m_pData) {
            delete [] m_pData;
            m_pData = NULL;
            m_nLength = 0;
        }
    }
   
private:
    wchar_t * m_pData;
    int m_nLength;
};

// StringA
class StringA
{
public:
    // constructors
    StringA():m_nLength(0) {
        m_pData = new char[1];
        m_pData[0] = 0;
    }
    StringA(LPCWSTR lpsz) {
        int nSrcLen = lpsz != NULL ? wcslen(lpsz) : 0;
        if (nSrcLen)
        {
            m_nLength = ::WideCharToMultiByte(CP_ACP, 0, lpsz, nSrcLen, NULL,
                0, NULL, NULL);
            m_pData = new char[m_nLength+1];
            m_pData[m_nLength] = 0;
            ::WideCharToMultiByte(CP_ACP, 0, lpsz, nSrcLen, m_pData,
                m_nLength+1, NULL, NULL);   
        }
        else {
            m_pData = new char[1];
            m_pData[0] = 0;
        }
    }
    StringA(LPCSTR lpsz) {
        int nSrcLen = lpsz != NULL ? lstrlenA(lpsz) : 0;
        m_nLength = nSrcLen;
        m_pData = new char[m_nLength+1];
        m_pData[m_nLength] = 0;
        memcpy(m_pData,lpsz,nSrcLen);
    }
    StringA(CString& strSrc) {
        int nSrcLen = strSrc.GetLength();
        if (m_nLength) {
            LPTSTR lpsz = strSrc.GetBuffer(nSrcLen);
#ifndef _UNICODE
            m_nLength = nSrcLen;
            m_pData = new char[m_nLength+1];
            m_pData[m_nLength] = 0;
            memcpy(m_pData,lpsz,nSrcLen);
#else
            m_nLength = ::WideCharToMultiByte(CP_ACP, 0, lpsz, nSrcLen, NULL,
                0, NULL, NULL);
            m_pData = new char[m_nLength+1];
            m_pData[m_nLength] = 0;
            ::WideCharToMultiByte(CP_ACP, 0, lpsz, nSrcLen, m_pData,
                m_nLength+1, NULL, NULL);   
#endif
        } else {
            m_pData = new char[1];
            m_pData[0] = 0;
        }
    }

    // attributes and member functions
    inline char * GetBuffer() { return m_pData; }
    inline int GetLength() { return m_nLength; }
    operator char* () const {
        return m_pData;
    }
    operator LPCSTR() const {
        return m_pData;
    }
    friend CString operator+(const CString& string, const StringA& stringA) {
        ASSERT((LPCSTR)stringA!=NULL);
        CString s(string);
        s += (LPCSTR)stringA;
        return s;
    }
public:
    ~StringA()
    {
        if (m_pData) {
            delete [] m_pData;
            m_pData = NULL;
            m_nLength = 0;
        }
    }

private:
    char * m_pData;
    int m_nLength;
};

 

在用到需要字节转换的时候,调用一下就行了。

StringA strA(L"宽字节");
DWORD dwBytesWritten;
if ( ! ::WriteFile(hFile, strA, strA.GetLength(), &dwBytesWritten, NULL) )
    return ::GetLastError();

 

先行这样处理,还要接着改,遇到什么问题再添加上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值