[WinAPI] Cum convertesc de la LPCWSTR la std::string?

Folosire Windows API in programe C/C++ (forum moderat)
Post Reply
User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

[WinAPI] Cum convertesc de la LPCWSTR la std::string?

Post by Ovidiu Cucu » 13 Jul 2008, 13:20

Problema
Am un sir de caractere tip LPCWSTR si trebuie sa-l trimit la o functie care are ca parametru tipul std::string.
Simplificat, programul meu arata cam asa

Code: Select all

#include <windows.h>
#include <iostream>
#include <string>
void PrintBaba(const std::string& str)
{
   std::cout << str << std::endl;
}
int main(int argc, char* argv[])
{
   LPCWSTR wcsBaba = L"babasafta"; 
   PrintBaba(wcsBaba);
   return 0;
}
Compilatorul da eroarea

Code: Select all

cannot convert parameter 1 from 'LPCWSTR' to 'const std::string &'
Am incercat mai multe cast-uri, de exemplu

Code: Select all

PrintBaba(reinterpret_cast<const std::string&>(wcsBaba));
Nu mai da eroare de compilare dar la iesire apare un sir de "carcalaci" si "piuituri".
Exista vreo cale de a face corect conversia de la LPCWSTR la std::string?

Raspuns
Tipul LPCWSTR este un pointer la un sir (NUL-terminated) constant, reprezentat in caractere UNICODE pe 16 biti (contine elemente tip wchar_t). Altfel spus, pointeaza la un sir de wide characters.
std::string este o specializare a clasei STL basic_string avand elemente tip char (fiecare pe 1 byte). De asemenea, un sir de char-uri se mai numeste si multibyte character string.
In nici un caz nu e corecta conversia prin cast-ul mentionat mai sus.
Pentru conversia de la wide character string la multibyte character string (sau invers) exista functii de conversie atat in biblioteca C (wcstombs, mbstowcs, etc.) cat si in Windows API (WideCharToMultiByte si MultiByteToWideChar).
Vezi si acest FAQ: Cum trec de la wide char la multi byte si viceversa
Deci s-ar putea "converti" LPCWSTR la un std::string ca in FAQ-ul mentionat sau folosind wcstombs ca in exemplul urmator:

Exemplu 1

Code: Select all

#include <windows.h>
#include <iostream>
#include <string>

void PrintBaba(const std::string& str)
{
   std::cout << str << std::endl;
}
int main(int argc, char* argv[])
{
   LPCWSTR baba = L"babasafta"; 

   // convert wide char string to multibyte string (std::string).
   size_t size = wcslen(baba) + 1;
   std::string str;
   str.resize(size);
   wcstombs(&str[0], baba, size);

   PrintBaba(str);
   return 0;
}
Pana aici problema pare ca si rezolvata.
Totusi este important de mentionat ca, intr-o aplicatie bine scrisa, ocaziile cand chiar trebuie neaparat sa facute aceste conversii sunt sau ar trebui sa fie rare (folosim apeluri la functii dintr-o biblioteca third-party, ne-am procopsit cu niste functii de "interfata" rau scrise pe care nu avem voie sa le schimbam, etc).
Motivul e clar: aceste conversii introduc overhead atat la marimea cat si la performanta aplicatiei si in plus, codul devine mai stufos, mai greu de mentinut si mai susceptibil de erori.

Exista trei posibilitati de a rezolva elegant si inginereste aceasta problema:
  1. folosim numai tipurile/functiile/clasele corespunzatoare pentru multibyte character string: "babasafta", LPCSTR, main, std::string, etc (exeplul 2).
  2. folosim numai tipurile/functiile/clasele corespunzatoare pentru wide character string: L"babasafta", LPCWSTR, wmain, std::wstring, etc (exeplul 3).
  3. (ultima dar cea mai buna) folosim macrouri care permit sa compilam aplicatia atat non-UNICODE (utilizand multibyte character strings) cat si UNICODE (utilizand wide character strings): _T("babasafta"), LPCTSTR, _tmain, etc (exeplul 4).
Exemplu 2

Code: Select all

#include <windows.h>
#include <iostream>
#include <string>
void PrintBaba(const std::string& str)
{
   std::cout << str << std::endl;
}
int main(int argc, char* argv[])
{
   LPCSTR baba = "babasafta"; 
   PrintBaba(baba);
   return 0;
}
Exemplu 3

Code: Select all

#include <windows.h>
#include <iostream>
#include <string>
void PrintBaba(const std::wstring& str)
{
   std::wcout << str << std::endl;
}
int wmain(int argc, wchar_t* argv[])
{
   LPCWSTR baba = L"babasafta"; 
   PrintBaba(baba);
   return 0;
}
Exemplu 4

Code: Select all

#include <windows.h>
#include <iostream>
#include <string>
#include <tchar.h>

#ifdef UNICODE
   #define t_string wstring
   #define t_cout wcout
#else
   #define t_string string
   #define t_cout cout
#endif // UNICODE

void PrintBaba(const std::t_string& str)
{
   std::t_cout << str << std::endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
   LPCTSTR baba = _T("babasafta"); 
   PrintBaba(baba);
   return 0;
}
Note:
<< Back to Windows API Index



Post Reply