将char*转换为LPWSTR

49

我正在尝试将一个多字节字符程序转换为Unicode。

我已经检查过程序,并在字符串文字前加上了 L,使其看起来像这样L"string"

虽然这个方法起作用了,但现在我面临的问题是有一个C风格的字符串不符合要求。我尝试使用 L 并将其放入 TEXT() 中,但如果我使用 TEXT()L 会被添加到变量名称中而不是字符串中。

我尝试将它变成 TCHAR,但是它抱怨无法将 TCHAR 转换为 char *

我还有什么选择吗?

我知道 C 和 C++ 是不同的。这是一种老旧的内部 C 库,已在 C++ 项目中使用了好几年。


1
下投票的主要原因可能更多是,我认为,你的问题中缺少源代码。一张图片胜过千言万语,同样地,一段代码也是如此。即使只是一个微不足道的代码片段。 - ereOn
无论编译器设置如何,您都可以编写与“TCHAR”配合使用的代码,只需创建正确的基础设施即可。在C++中,重载为您完成了所有繁重的工作。 - Kerrek SB
可能是如何将char*转换为LPCWSTR?的重复问题。 - Rusty Nail
5个回答

60

std::mbstowcs函数是你需要寻找的:

 char text[] = "something";
 wchar_t wtext[20];
 mbstowcs(wtext, text, strlen(text)+1);//Plus null
 LPWSTR ptr = wtext;

对于 string(字符串),

 string text = "something";
 wchar_t wtext[20];
 mbstowcs(wtext, text.c_str(), text.length());//includes null
 LPWSTR ptr = wtext;

--> ED: "L"前缀只适用于字符串字面量,而不适用于变量。<--


1
这个已经过时了,你应该使用 mbstowcs_s() - Olipro
1
@Olipro:这只在Windows世界中被“弃用”。OP没有说明他的目标平台。 - ereOn
7
这句话的含义相当明显,即这个平台是Windows,但如果你持不同意见,请继续并证明我是错的。 - Olipro
@Olipro:_s版本有什么优势?据我所知,您会传递另一个计数参数,该参数指示要写出的最多字符数,但这有什么帮助呢?您已经在另一个参数中指定了输出缓冲区的大小,这只是为了终止零的缘故吗? - Kerrek SB
http://msdn.microsoft.com/en-us/library/8ef0s5kh%28v=vs.80%29.aspx - Olipro
1
我理解得对吗,只有在已知char*的长度时,才能将其转换为LPWSTR?如果不是这样,为什么会假设20个字符就足够了呢? - masiton

12

使用mbstowcs的正确方式是调用两次以查找结果的长度:

  const char * cs = <your input char*>
  size_t wn = mbsrtowcs(NULL, &cs, 0, NULL);

  // error if wn == size_t(-1)

  wchar_t * buf = new wchar_t[wn + 1]();  // value-initialize to 0 (see below)

  wn = mbsrtowcs(buf, &cs, wn + 1, NULL);

  // error if wn == size_t(-1)

  assert(cs == NULL); // successful conversion

  // result now in buf, return e.g. as std::wstring

  delete[] buf;

别忘了在程序开头调用 setlocale(LC_CTYPE, "");

与 Windows 的 MultiByteToWideChar 相比,这个方法完全符合标准 C,但在 Windows 上你可能仍然更喜欢使用 Windows API 函数。

通常我会将这个方法和相反的方法一起封装在两个转换函数中,分别是 string->wstringwstring->string。如果你还添加了一些微不足道的重载,例如 string->stringwstring->wstring,你就可以轻松编写支持 Winapi TCHAR typedef 的代码了。

[编辑:] 我将零初始化添加到了 buf 中,以防您计划直接使用 C 数组。不过,我通常会将结果作为 std::wstring(buf, wn) 返回,但如果您计划使用 C 风格的空结尾数组,请注意。

在多线程环境下,应该将一个线程本地的转换状态作为最终参数传递给该函数(目前该参数不可见)。

这里有一篇我关于这个主题的小发牢骚


2
展示如何调用函数两次以获取输出缓冲区的长度,+1。 - David Heffernan
干杯。在我自己的思想隐私中,我实际上使用了一个可变长度数组来存储buf,但是考虑到被SO审查而避免使用它。 - Kerrek SB
更新:现在我会寻找codecvt,它包装了mbsrtowcs/wcsrtombs - Kerrek SB

5

这个版本使用Windows API的MultiByteToWideChar()函数,可以处理任意长度的输入字符串,并且处理内存分配问题。

int lenA = lstrlenA(input);
int lenW = ::MultiByteToWideChar(CP_ACP, 0, input, lenA, NULL, 0);
if (lenW>0)
{
    output = new wchar_t[lenW];
    ::MultiByteToWideChar(CP_ACP, 0, input, lenA, output, lenW);
} 

@Kerrek 为了简洁起见,我省略了调用 free 的代码;-) - David Heffernan
1
我宁愿让它保持原样,也不要调用 free()!这绝对是使用备受赞誉的 delete[] 表达式的情况 :-) - Kerrek SB
@kerrek 确实如此!从一个问题到另一个问题,跟踪 C 和 C++ 是如此困难。 - David Heffernan
似乎不需要调用'lstrlenA(input)'。请参阅MSDN。_cbMultiByte:由lpMultiByteStr参数指示的字符串的大小(以字节为单位)。或者,如果字符串以null结尾,则可以将此参数设置为-1。_只需使用-1而不是lenA。 - Alan Kazbekov
@Alan 这样做是可行的,但另一方面这种方式意味着长度只计算一次,而不是两次。我想这是个人选择的问题。 - David Heffernan

5

我在使用VC++中的以下代码,对我来说非常好用。

CA2CT(charText)

4
请记得在宏中包含 #include <atlstr.h>。 - Dino Dini

2
你可以使用 CStringCStringACStringW 来进行自动转换并在这些类型之间进行转换。此外,你还可以使用 CStrBufCStrBufACStrBufW 来获取 RAII 模式可修改字符串。

请注意,它们是针对ATL/MFC特定的。 - JBES
@JBES,是的。我在6年前回答过这个问题,当时ATL/MFC被广泛使用。现在,甚至C ++语言也具备了转换的库特性。 - Ajay

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接