Сущность технологии СОМ. Библиотека программиста

ОглавлениеДобавить в закладки К обложке

Одним из подходов к упрощению преобразования текста является применение системы типов C++ и использование перегрузки функций для выбора нужной строковой процедуры, построенной на типах параметров. Заголовочный файл ustring.h из приложения к этой книге содержит семейство библиотечных строковых процедур, аналогичных стандартным библиотечным процедурам С, которые находятся в файле string.h. Например, функция strncpy имеет четыре соответствующих процедуры, зависящие от каждого из параметров, которые могут быть одного из двух символьных типов (wchar_t или char):

// 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:

HRESULT IIDFromHWND(HWND hwnd, IID& riid)

{

TCHAR szEditText[1024];

// call a TCHAR-based Win32 routine

// вызываем TCHAR-процедуру Win32

GetWindowText(hwnd, szEditText, 1024);

// call an OLECHAR-based СОМ routine

// вызываем OLECHAR-процедуру СОМ

return IIDFromString(szEditText, &riid);

}

Допуская, что этот код скомпилирован с указанным символом С-препроцессора UNICODE; он работает безупречно, так как TCHAR и OLECHAR являются просто псевдонимами wchar_t и никакого преобразования не требуется. Если же функция скомпилирована с версией Win32 API, не поддерживающей Unicode, то TCHAR является псевдонимом для char, и первый параметр для IIDFromString имеет неправильный тип. Чтобы решить эту проблему, нужно провести условную компиляцию:

HRESULT IIDFromHWND(HWND hwnd, IID& riid)

{

TCHAR szEditText[1024];

GetWindowText(hwnd, szEditText, 1024);

#ifdef UNICODE return IIDFromString(szEditText, &riid);

#else OLECHAR wszEditText[l024];

ustrncpy(wszEditText, szEditText, 1024);

return IIDFromString(wszEditText, &riid);

#endif

}

Хотя этот фрагмент и генерирует оптимальный код, очень утомительно применять эту технику всякий раз, когда символьный параметр имеет неверный тип. Можно справиться с этой проблемой, если использовать промежуточный (shim) класс с конструктором, принимающим в качестве параметра любой тип символьной строки. Этот промежуточный класс должен также содержать в себе операторы приведения типа, что позволит использовать его в обоих случаях: когда ожидается const char * или const wchar_t *. В этих операциях приведения промежуточный класс либо выделяет резервный буфер и производит необходимое преобразование, либо просто возвращает исходную строку, если преобразования не требовалось. Деструктор промежуточного класса может затем освободить все выделенные буферы. Заголовочный файл ustring.h содержит два таких промежуточных класса: _U и _UNCC. Первый предназначен для нормального использования; второй используется с функциями и методами, тип аргументов которых не включает спецификатора const[2] (таких как IIDFromString). При возможности применения двух промежуточных классов предыдущий фрагмент кода может быть значительно упрощен:


Логин
Пароль
Запомнить меня