R0 CREW

Вопрос про контролы windows и std::string

Может кто подскажет по типам данных .
Читаю я csv фаил в vector <wstring> . Потом хотел вывести в ListView через SendMessage . Думал все на мази , а вот хрен .


LV_ITEM lvitem;
...
lvitem.mask = LVIF_TEXT;
lvitem.iItem = n;
lvitem.iSubItem = 0;
lvitem.pszText = wdat->phone.c_str();     // Ошибка с типами данных
SendMessage(hListView,LVM_INSERTITEM,0,(LPARAM) &lvitem);

Проблема в том что структура lvitem в pszText хочет получить lpwstr . А wstring методом c_str() отдает lpcwstr . Т е константу .
И что делать я как-то недогоняю . Как корректно получить от std::wstring нужный неконстантный тип ? Или как конвертировать . Или , если никак , то в каком формате тогда хранить данные и как это обычно решают ?
Нагуглил пару вариантов , но они такие уродские . Должен же быть стандартный кошерный способ .

Ну, можно сделать, например, так:

LPCTSTR test = _T("Hello, World!");
LPTSTR pszText = (LPTSTR) test;

_T это макрос . Препроцессор просто добавляет L к строке “Hello, World!” .

#if defined(_UNICODE)
#define _T(x) L ##x
#else
#define _T(x) x
#endif

Он не может обрабатывать переменные . Препроцессор их не видит .

string str("hello world");
cout << _T(str.c_str());

Этот код не соберется с ошибкой Error:идентификатор “Lstr” не определен .

Но в целом мысль понятна . Да , я могу сделать что-то типа

string str("hello world");
string str2(str);
cout << (LPSTR)str2.c_str();

Т е явно привести тип . Наверно это лучшее, что я сейчас могу . Хотя придется добавлять + 1 строку при каждом получении данных . А у меня их сейчас 12 полей в ст-ре . А если не копировать , то вообще нет гарантии , что контролы не модифицируют данные в векторе .
Меня больше другое пузырит . Неужели нет строчного типа данных , который предусмотрено использовать с контролами по дефолту . Т е когда microsoft создавала api они же должны были понимать , что люди врядли будут хранить свои данные в char * ?

Мде… А кто сказал, что его надо как-то применять? Тем более в таком виде:

string str("hello world");
cout << _T(str.c_str());

_Т() - применяется только к литералам, т.е. к строкам.

В моем примере, строка кода:

LPCTSTR test = _T("Hello, World!");

Предназначена всего-лишь для НАГЛЯДНОГО создания переменной “test” типа LPCTSTR. Я бы мог выдать, что-то в этом роде:

LPCTSTR test = ptsHelloWorld;

Но, если кому-то вздумается проверить работу примера, все равно придется как-то создавать ptsHelloWorld.

Ну зачем добавлять еще одну строку?

Это само собой разумеется…

Все есть. Надо только больше думать и меньше бездумно копировать. Используемый тобой тип wstring вполне себе годится для твоих целей.

Вернемся к твоему вопросу:

LPWSTR тоже самое что и LPTSTR, а LPCWSTR тоже самое что LPCTSTR. Так как в MSDN, параметр pszText, в стуктуре LV_ITEM, задан как LPTSTR, то я составил следующий пример:

LPCTSTR test = _T("Hello, World!");
LPTSTR pszText = (LPTSTR) test;

Все что тебе нужно было сделать, это просто добавить “(LPTSTR)” в месте где происходила ошибка:

lvitem.pszText = [B](LPTSTR)[/B] wdat->phone.c_str();

И все должно работать.

Наверно я слишком буквально тебя понял .

Согласен . Но , как я понимаю , предварительно все-таки нужно переменную копировать .

string str("hello world");
string str2(str);
cout << (LPSTR)str2.c_str();

Ибо если привести тип оригинальной строки в неконстантный и отдать контролу , есть шанс что в дальнейшем она будет испорчена .

Не нужно ничего копировать. Конкретно для таких целей (убрать спецификатор const) есть конструкция const_cast. Описание на MSDN

Ну а вам надо сделать как-то так:

lvitem.pszText = const_cast< lpwstr > wdat->phone.c_str();

Преобразования в стиле С также работают здесь. Т.е. lvitem.pszText = (lpwstr) wdat->phone.c_str(); тоже даст желаемый результат, но первый вариант - более наглядный и правильный с точки зрения ООП.

lvitem.pszText = &(wdat->phone[0]);

UPD оффтоп:
блин ща скажут что археолог. =)

некрофил