Сущность технологии СОМ. Библиотека программиста
Шрифт:
const wchar_t *pwsz = L"Hello";
Первый вариант предпочтительней, так как он будет надежно компилироваться на всех платформах.
Поскольку часто возникает необходимость копировать строки на основе типа wchar_t в обычные буфера на основе char, то динамическая библиотека С предлагает две процедуры для преобразования типов:
size_t mbstowcs(wchar_t *pwsz, const char *psz, int cch);
size_t wcstombs(char *psz, const wchar_t *pwsz, int cch);
Эти
class BigDog : public ILabrador
{
char m_szName[1024] ;
public:
STDMETHODIMP SetName(/* [in,string]*/ const OLECHAR *pwsz)
{
HRESULT hr = S_OK;
size_t cb = wcstombs(m_szName, pwsz, 1024);
// check for buffer overflow or bad conversion
// проверяем переполнение буфера или неверное преобразование
if (cb == sizeof(m_szName) || cb == (size_t)-1)
{
m_szName[0] = 0; hr = E_INVALIDARG;
}
return hr;
}
};
Этот код является довольно простым, хотя программист должен осознавать, что используются два различных типа символов. Несколько более сложный (и чаще встречающийся) случай – преобразование между типами данных OLECHAR и TCHAR из Win32. Так как OLECHAR условно компилируется как char или wchar_t, то при реализации метода необходимо должным образом рассмотреть оба сценария:
class BigDog : public ILabrador
{
TCHAR m_szName[1024];
// note TCHAR-based string
// отметим строку типа TCHAR
public:
STDMETHODIMP SetName( /*[in,string]*/ const OLECHAR *pwsz)
{
HRESULT hr = S_OK;
#ifdef UNICODE
// Unicode build (TCHAR == wchar_t)
// конструкция Unicode (TCHAR == wchar_t)
wcsncpy(m_szName, pwsz, 1024);
// check for buffer overflow
// проверка на переполнение буфера
if (m_szName[1023] != 0)
{
m_szName[0] = 0;
hr = E_INVALIDARG;
}
#else
// Non-Unicode build (TCHAR == char)
// не является конструкцией Unicode (TCHAR == char)
size_t cb = wcstombs(m_szName, pwsz, 1024);
// check for buffer overflow or bad conversion
// проверка переполнения буфера или ошибки преобразования
if (cb == sizeof(m_szName) || cb == (size_t)-1)
{
m_szName[0] =0;
hr = E_INVALIDARG;
}
#endif return hr;
}
};
Очевидно, операции с преобразованиями OLECHAR в TCHAR значительно сложнее. Но, к сожалению, это самый распространенный сценарий при программировании в СОМ на базе Win32.
Одним из подходов к упрощению преобразования текста является применение системы типов C++ и использование
// from ustring.h (book-specific header)
// из ustring.h (заголовок, специфический для данной книги)
inline bool ustrncpy(char *p1, const wchar_t *p2, size_t c)
{
size_t cb = wcstombs(p1, p2, c);
return cb != c && cb != (size_t)-1;
};
inline bool ustrncpy(wchar_t *p1, const wchar_t *p2, size_t c)
{
wcsncpy(p1, p2, c);
return p1[c – 1] == 0;
};
inline bool ustrncpy(char *p1, const char *p2, size_t c)
{
strncpy(p1, p2, c);
return p1[c – 1] == 0;
};
inline bool ustrncpy(wchar_t *p1, const char *p2, size_t c)
{
size_t cch = mbstowcs(p1, p2, c);
return cch != c && cch != (size_t)-1;
}
Отметим, что для любого сочетания типов идентификаторов может быть найдена соответствующая перегруженная функция ustrncpy, причем результат показывает, была или нет вся строка целиком скопирована или преобразована. Поскольку эти процедуры определены как встраиваемые (inline) функции, их использование не внесет никаких затрат при выполнении. С этими процедурами предыдущий фрагмент кода станет значительно проще и не потребует условной компиляции:
class BigDog : public ILabrador
{
TCHAR m_szName[1024];
// note TCHAR-based string
// отметим строку типа TCHAR
public:
STDMETHODIMP SetName(/* [in,string] */ const OLECHAR *pwsz)
{
HRESULT hr = S_OK;
// use book-specific overloaded ustrncpy to copy or convert
// используем для копирования и преобразования
// перегруженную функцию ustrncpy, специфическую для данной книги
if (!ustrncpy(m_szName, pwsz, 1024))
{
m_szName[0] = 0;
hr = E_INVALIDARG;
} return hr;
}
};
Соответствующие перегруженные функции для процедур strlen, strcpy и strcat также включены в заголовочный файл ustring.h.
Использование перегрузки библиотечных функций для копирования строк из одного буфера в другой, как это показано выше, обеспечивает лучшее качество исполнения, уменьшает размер кода и непроизводительные издержки программиста. Однако часто возникает ситуация, когда одновременно используются СОМ и API-функции Win32, что не дает возможности применить эту технику. Рассмотрим следующий фрагмент кода, читающий строку из элемента редактирования и преобразующий ее в IID: