views:

50

answers:

1

I have some code in a library which has to internally work with wstring, that's all nice and fine. But it's called with a TCHAR string parameter, from both unicode and non-unicode projects, and I'm having trouble finding a neat conversion for both cases.

I see some ATL conversions and so on but can't see the right way, without defining multiple code paths using #define

+3  A: 

Assuming TCHAR expands to wchar_t in Unicode builds:

inline std::wstring convert2widestr(const wchar_t* const psz)
{
  return psz;
}
inline std::wstring convert2widestr(const char* const psz)
{
  std::size_t len = std::strlen(psz);
  if( psz.empty() ) return std::wstring();
  std::vector<wchar_t> result;
  const int len = WideCharToMultiByte( CP_ACP
                                     , 0
                                     , reinterpret_cast<LPCWSTR>(psz)
                                     , static_cast<int>(len)
                                     , NULL
                                     , 0
                                     , NULL
                                     , NULL
                                     );

  result.resize( len );
  if(result.empty()) return std::wstring();
  const int cbytes = WideCharToMultiByte( CP_ACP
                                        , 0
                                        , reinterpret_cast<LPCWSTR>(psz)
                                        , static_cast<int>(len)
                                        , reinterpret_cast<LPSTR>(&result[0])
                                        , static_cast<int>(result.size())
                                        , NULL
                                        , NULL
                                        );
  assert(cbytes);
  return std::wstring( result.begin(), result.begin() + cbytes );
}

Use like this:

void f(const TCHAR* psz)
{
   std::wstring str = convert(psz);
   // ...
}
sbi
eeeeeeeeeeeeeew! Although, nice use of overloading to avoid `#define`.
John
CP_UTF8 is *very* unlikely in legacy Windows programs. Use CP_ACP instead. Or just use mbstowcs().
Hans Passant
@Hans: That was a copy'n'paste error. `:(`
sbi
@John: I'm not sure what you're trying to tell me. Anyway, the overload has the advantage that both versions are available in Unicode and non-Unicode programs.
sbi
@sbi: it just seems a lot of code. I've seen this type of thing before but was hoping for something that does it for me.
John
@John: In fact `WideCharToMultiByte()` does it for you. But it's a C API function, and with C's inability to handle resources, it's a pain in the neck to call it. However, if this seems too complicated, you can always use the first version of my answer. `:)`
sbi
@sbi: I ended up letting _bstr_t do it for me, I'm sure internally it's no less messy though.
John
@John: That's fine if you can use that. The main idea was in the overloading anyway.
sbi