Должна ли быть разница между пустым BSTR и NULL BSTR?
При поддержании COM
интерфейс должен быть пустым BSTR
относиться так же, как NULL
? Другими словами, должны ли эти два вызова функций давать одинаковый результат?
// Empty BSTR
CComBSTR empty(L""); // Or SysAllocString(L"")
someObj->Foo(empty);
// NULL BSTR
someObj->Foo(NULL);
2 ответа
Да, NULL BSTR - это то же самое, что и пустой. Я помню, у нас были всевозможные ошибки, которые были обнаружены, когда мы перешли с VS6 на 2003 - класс CComBSTR изменил конструктор по умолчанию, который выделил его, используя NULL, а не пустую строку. Это происходит, когда вы, например, рассматриваете BSTR как обычную строку в стиле C и передаете ее какой-либо функции, например strlen
или попробуйте инициализировать std::string
с этим.
Эрик Липперт подробно описывает BSTR в Полном руководстве Эрика по семантике BSTR:
Позвольте мне сначала перечислить различия, а затем обсудить каждый пункт в мучительных деталях.
1) BSTR должен иметь одинаковую семантику для NULL и для "". У PWSZ часто есть различная семантика для тех.
2) BSTR должен быть выделен и освобожден с помощью семейства функций SysAlloc*. PWSZ может быть буфером автоматического хранения из стека или выделяться с помощью malloc, new, LocalAlloc или любого другого распределителя памяти.
3) BSTR имеет фиксированную длину. PWSZ может иметь любую длину, ограниченную только объемом действительной памяти в своем буфере.
4) BSTR всегда указывает на первый действительный символ в буфере. PWSZ может быть указателем на середину или конец строкового буфера.
5) При выделении n-байтового BSTR у вас есть место для n/2 широких символов. Когда вы выделяете n байтов для PWSZ, вы можете хранить n / 2 - 1 символов - вы должны оставить место для нуля.
6) BSTR может содержать любые данные Unicode, включая нулевой символ. PWSZ никогда не содержит нулевой символ кроме как маркер конца строки. И BSTR, и PWSZ всегда имеют нулевой символ после их последнего действительного символа, но в BSTR действительный символ может быть нулевым символом.
7) BSTR может фактически содержать нечетное число байтов - его можно использовать для перемещения двоичных данных. PWSZ почти всегда является четным числом байтов и используется только для хранения строк Unicode.
Самый простой способ справиться с этой дилеммой - использовать CComBSTR и проверить, что.Length() равен нулю. Это работает как для пустых, так и для пустых значений.
Однако имейте в виду, что пустой BSTR должен быть освобожден, иначе произойдет утечка памяти. Я недавно видел некоторые из них в коде другого. Довольно трудно найти, если вы не смотрите внимательно.