Как эффективно копировать BSTR в wchar_t []?

У меня есть объект BSTR, который я хотел бы преобразовать для копирования в объект wchar__t. Сложность заключается в том, что длина объекта BSTR может составлять от нескольких килобайт до нескольких сотен килобайт. Есть ли эффективный способ копирования данных? Я знаю, что могу просто объявить массив wchar_t и всегда выделять максимально возможные данные, которые ему когда-либо понадобятся. Однако это означало бы выделение сотен килобайт данных для чего-то, для чего потенциально может потребоваться всего несколько килобайт. Какие-либо предложения?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
0
19 420
5

Ответы 5

Объекты BSTR содержат префикс длины, поэтому определение длины обходится недорого. Определите длину, выделите новый массив, достаточно большой, чтобы вместить результат, обработайте его и не забудьте освободить его, когда закончите.

Используйте ATL и CStringT, тогда вы можете просто использовать оператор присваивания. Или вы можете использовать макросы USES_CONVERSION, они используют выделение кучи, поэтому вы можете быть уверены, что у вас не будет утечки памяти.

Нет необходимости в преобразовании. Указатель BSTR указывает на первый символ строки и заканчивается нулем. Длина сохраняется перед первым символом в памяти. BSTR всегда использует Unicode (UTF-16 / UCS-2). На каком-то этапе существовало нечто, называемое «ANSI BSTR» - в устаревших API есть некоторые ссылки, но вы можете игнорировать их в текущей разработке.

Это означает, что вы можете безопасно передать BSTR любой функции, ожидающей wchar_t.

В Visual Studio 2008 вы можете получить ошибку компилятора, потому что BSTR определен как указатель на unsigned short, а wchar_t - это собственный тип. Вы можете использовать или отключить соответствие wchar_t с /Zc:wchar_t.

wchar_t не может быть точно такого же размера, как короткий.

ben 16.09.2008 20:29

Я считаю, что эта операция всегда безопасна, но не всегда может дать ожидаемый результат. BSTR может содержать нулевые символы в своем теле (отсюда и префикс длины), тогда как функция, ожидающая wchar_t *, будет интерпретировать первый нулевой символ как конец строки.

Martin 29.09.2008 16:42

Вы не можете «безопасно передать BSTR любой функции, ожидающей wchar_t *». Сравните SysStringLen (NULL) и wcslen (NULL).

Constantin 04.10.2008 02:38

Просто чтобы расширить комментарий Константина - BSTR может действительно быть NULL, что определенный эквивалентно пустой строке (""). Напротив, большинство функций, ожидающих wchar_t * явно не будет, обрабатывают NULL так же, как указатель на пустую строку ...

Spike0xff 01.02.2012 22:47

Следует иметь в виду, что строки BSTR могут содержать и часто содержат встроенные нули. Нулевое значение не означает конец строки.

Во-первых, возможно, вам вообще ничего не придется делать, если все, что вам нужно сделать, это прочитать содержимое. Тип BSTR уже является указателем на массив wchar_t с завершающим нулем. Фактически, если вы проверите заголовки, вы обнаружите, что BSTR по существу определяется как:

typedef BSTR wchar_t*;

Таким образом, компилятор не может их различить, даже если они имеют разную семантику.

Есть два важных нюанса.

  1. Предполагается, что BSTR неизменяемы. Вы никогда не должны изменять содержимое BSTR после его инициализации. Если вы «измените его», вам придется создать новый, назначить новый указатель и освободить старый (если он у вас есть).
    [ОБНОВИТЬ: это неправда; Извините! Вы можете изменить BSTR на месте; У меня очень редко была потребность.]

  2. BSTR могут содержать встроенные нулевые символы, тогда как традиционные строки C / C++ - нет.

Если у вас есть достаточный контроль над источником BSTR и вы можете гарантировать, что BSTR не имеет встроенных NULL, вы можете читать из BSTR, как если бы это был wchar_t, и использовать обычные строковые методы (wcscpy и т. д.) Для получить доступ к нему. В противном случае ваша жизнь станет тяжелее. Вам всегда придется манипулировать своими данными как с другими BSTR, так и с динамически выделяемым массивом wchar_t. Большинство функций, связанных со строками, не будут работать правильно.

Предположим, вы контролируете свои данные или не беспокоитесь о NULL. Предположим также, что вам действительно нужно сделать копию, и вы не можете просто прочитать существующий BSTR напрямую. В этом случае вы можете сделать что-то вроде этого:

UINT length = SysStringLen(myBstr);        // Ask COM for the size of the BSTR
wchar_t *myString = new wchar_t[lenght+1]; // Note: SysStringLen doesn't 
                                           // include the space needed for the NULL

wcscpy(myString, myBstr);                  // Or your favorite safer string function

// ...

delete myString; // Done

Если вы используете оболочки классов для своего BSTR, оболочка должна иметь возможность вызывать для вас SysStringLen (). Например:

CComBString    use .Length();
_bstr_t        use .length();

ОБНОВИТЬ: Хорошая статья на эту тему написана кем-то гораздо более осведомленным, чем я:
"Полное руководство Эрика [Липперта] по семантике BSTR"

ОБНОВИТЬ: в примере заменена strcpy () на wcscpy ()

AFAIK, BSTR должны быть неизменными нет. Вот почему они не объявлены как const *.

Constantin 25.02.2009 14:20

Хммм ... Я не могу найти никаких ссылок, подтверждающих мою позицию. О чем я только думал? Я исправлю это.

Euro Micelli 25.02.2009 19:38

не следует ли вам использовать wcscpy вместо strcpy?

arolson101 07.08.2009 19:39

@ arolson101 (на wcscpy): вы, конечно, правы. Спасибо, что заметили мою ошибку.

Euro Micelli 08.08.2009 06:43

Другие вопросы по теме