Любителям совмещать STL и COM
От: Аноним  
Дата: 09.10.02 12:52
Оценка:
// conversion_error
class conversion_error
{};

// no_convert
template<typename dest_char, typename src_char>
class no_convert
{
private: // Нельзя использовать
    no_convert(const src_char*, unsigned) {}

    operator const dest_char*() const { return 0; }

    unsigned size() const { return 0; }
};

// identity_convert<ch>
template<typename ch>
class identity_convert
{
public:
    identity_convert(const ch* psSource, unsigned nSize) : m_psData(psSource), m_nSize(nSize) {}

    operator const ch*() const { return m_psData; }

    unsigned size() const { return m_nSize; }

private:
    const ch* m_psData;
    unsigned m_nSize;
};

// a2w_convert
class a2w_convert
{
public:
    a2w_convert(const char* psSource, unsigned nSize)
    {
        if (nSize == 0)
        {
            m_nSize = 0;
            m_psData = new wchar_t[0];
        } else
        {
            unsigned nRequestedSize =
                ::MultiByteToWideChar(CP_ACP, 0, psSource, nSize, NULL, 0);

            if (!nRequestedSize)
                throw conversion_error();

            m_psData = new wchar_t[nRequestedSize];

            unsigned nTranslatedSize =
                ::MultiByteToWideChar(
                    CP_ACP, 0, psSource, nSize, m_psData, nRequestedSize);

            if (nRequestedSize != nTranslatedSize)
            {
                delete[] m_psData;
                throw conversion_error();
            }

            m_nSize = nTranslatedSize;
        }
    }

    ~a2w_convert() { delete[] m_psData; }

    operator const wchar_t*() const { return m_psData; }

    unsigned size() const { return m_nSize; }

private:
    wchar_t* m_psData;
    unsigned m_nSize;
};

// w2a_convert
class w2a_convert
{
public:
    w2a_convert(const wchar_t* psSource, unsigned nSize)
    {
        if (nSize == 0)
        {
            m_nSize = 0;
            m_psData = new char[0];
        } else
        {
            unsigned nRequestedSize =
                ::WideCharToMultiByte(
                    CP_ACP, 0, psSource, nSize, NULL, 0, NULL, NULL);

            if (!nRequestedSize)
                throw conversion_error();

            m_psData = new char[nRequestedSize];

            unsigned nTranslatedSize =
                ::WideCharToMultiByte(
                    CP_ACP, 0, psSource, nSize, m_psData, nRequestedSize, NULL,
                    NULL);

            if (nRequestedSize != nTranslatedSize)
            {
                delete[] m_psData;
                throw conversion_error();
            }

            m_nSize = nTranslatedSize;
        }
    }

    ~w2a_convert() { delete[] m_psData; }

    operator const char*() const { return m_psData; }

    unsigned size() const { return m_nSize; }

private:
    char* m_psData;
    unsigned m_nSize;
};

// str_convert_traits<dest_char, src_char>
template<typename dest_char, typename src_char>
class str_convert_traits
{
public:
    typedef no_convert<dest_char, src_char> convert;
};

// специализация: str_convert_traits<char, char>
template<>
class str_convert_traits<char, char>
{
public:
    typedef identity_convert<char> convert;
};

// специализация: str_convert_traits<wchar_t, wchar_t>
template<>
class str_convert_traits<wchar_t, wchar_t>
{
public:
    typedef identity_convert<wchar_t> convert;
};

// специализация: str_convert_traits<wchar_t, char>
template<>
class str_convert_traits<wchar_t, char>
{
public:
    typedef a2w_convert convert;
};

// специализация: str_convert_traits<char, wchar_t>
template<>
class str_convert_traits<char, wchar_t>
{
public:
    typedef w2a_convert convert;
};

// converting_string<string, convert>
template<typename string, typename convert>
class converting_string :
    public string
{
public:
    converting_string(const convert& convert) : string(convert, convert.size()) {}
};

// bstr_converting_string<string, tr>
template<typename string, typename tr = str_convert_traits<string::value_type, OLECHAR> >
class bstr_converting_string : public converting_string<string, tr::convert>
{
public:
    bstr_converting_string(const OLECHAR* psSource, UINT nSourceSize) :
    converting_string<string, tr::convert>(tr::convert(psSource, nSourceSize)) {}
};

////////////////////////////////////////////////////////////////////////////////
// basic_bstr_in_string<string>
template<typename string>
class basic_bstr_in_string : public bstr_converting_string<string>
{
public:
    basic_bstr_in_string(BSTR bstrInParameter) : bstr_converting_string<string>(bstrInParameter, ::SysStringLen(bstrInParameter)) {}

    string& operator=(const string& rhs) { return string::operator=(rhs); }

    string& operator=(const string::value_type* s) { return string::operator=(s); }

    string& operator=(string::value_type c) { return string::operator=(c); }
};

typedef basic_bstr_in_string<std::wstring> bstr_in_wstring;
typedef basic_bstr_in_string<std::string> bstr_in_string;

typedef basic_bstr_in_string<std::basic_string<TCHAR> > bstr_in_tstring;

////////////////////////////////////////////////////////////////////////////////
// basic_bstr_out_string<string>
template<typename string>
class basic_bstr_out_string : public string
{
public:
    basic_bstr_out_string(BSTR* pbstrOutParameter, const string::value_type *s, const string::allocator_type& a = string::allocator_type()) :
        m_pbstrOutParameter(pbstrOutParameter), string(s, a) {}

    basic_bstr_out_string(BSTR* pbstrOutParameter, const string::value_type *s, string::size_type n, const string::allocator_type& a = string::allocator_type()) :
        m_pbstrOutParameter(pbstrOutParameter), string(s, n, a) {}

    basic_bstr_out_string(BSTR* pbstrOutParameter, const string& rhs) :
        m_pbstrOutParameter(pbstrOutParameter), string(rhs) {}

    basic_bstr_out_string(BSTR* pbstrOutParameter, const string& rhs, string::size_type pos, string::size_type n, const string::allocator_type& a = string::allocator_type()) :
        m_pbstrOutParameter(pbstrOutParameter), string(rhs, pos, n, a) {}

    basic_bstr_out_string(BSTR* pbstrOutParameter, string::size_type n, string::value_type c, const string::allocator_type& a = string::allocator_type()) :
        m_pbstrOutParameter(pbstrOutParameter), string(n, c, a) {}

    basic_bstr_out_string(BSTR* pbstrOutParameter, const string::allocator_type& a = string::allocator_type()) :
        m_pbstrOutParameter(pbstrOutParameter), string(a) {}

    template<typename CInIt>
    basic_bstr_out_string(BSTR* pbstrOutParameter, CInIt first, CInIt last, const string::allocator_type& a = string::allocator_type()) :
        m_pbstrOutParameter(pbstrOutParameter), string(first, last, a) {}

    ~basic_bstr_out_string()
    {
        if (!length())
        {
            *m_pbstrOutParameter = NULL;
            return;
        }

        try
        {
            str_convert_traits<OLECHAR, value_type>::convert convert(
                data(), length());
            *m_pbstrOutParameter = ::SysAllocStringLen(convert, convert.size());
        } catch (...)
        {
            *m_pbstrOutParameter = NULL;
        }
    }

    string& operator=(const string& rhs) { return string::operator=(rhs); }

    string& operator=(const string::value_type* s) { return string::operator=(s); }

    string& operator=(string::value_type c) { return string::operator=(c); }

private:
    BSTR* m_pbstrOutParameter;
};

typedef basic_bstr_out_string<std::wstring> bstr_out_wstring;
typedef basic_bstr_out_string<std::string> bstr_out_string;
typedef basic_bstr_out_string<std::basic_string<TCHAR> > bstr_out_tstring;


Впервые написано около двух лет назад, сейчас восстановлено по памяти, кажется, должно работать. "Заточено" под MSVC++. Единственное серьезное "но", как мне кажется, — традиционный для MSVC++ вопрос с bad_alloc.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.