字符串。 TCHAR LPWCS LPCTSTR CString。什么在这里,简单快捷

时间:2013-04-17 13:24:03

标签: c++ string winapi

TCHAR szExeFileName[MAX_PATH]; 
GetModuleFileName(NULL, szExeFileName, MAX_PATH);

CString tmp;
lstrcpy(szExeFileName, tmp);
CString out;
out.Format("\nInstall32 at %s\n", tmp);
TRACE(tmp);

错误(格式化):

error C2664: 'void ATL::CStringT<BaseType,StringTraits>::Format(const wchar_t 
*,...)' : cannot convert parameter 1 from 'const char [15]' to 'const wchar_t

我只想获取启动此程序的当前路径并将其复制到CString中,以便我可以在其他地方使用它。我目前正试图通过TRACE来看看它的路径。但字符串,字符,字符数组,我不可能得到所有的海峡。有人可以给我一个指针吗?

2 个答案:

答案 0 :(得分:9)

接受的答案解决了这个问题。但问题还要求更好地理解Windows上所有字符类型之间的差异。

<强>编码

Windows上的char(几乎所有其他系统)都是单字节。一个字节通常被解释为无符号值[0..255]或有符号值[-128..127]。 (较旧的C ++标准保证只有[-127..127]的有符号范围,但大多数实现给出[-128..127]。我相信C ++ 11保证更大的范围。)

ASCII是[0..127]范围内的值到特定字符的字符映射,因此您可以将ASCII字符存储在有符号字节或无符号字节中,因此它始终适合{{ 1}}。

但ASCII并不具备大多数语言所需的所有字符,因此通常使用字节中可用的其余值来扩展字符集,以表示某些语言(或某些语言)所需的其他字符。语言)。因此,虽然[0..127]几乎总是意味着相同的东西,但像150这样的值只能在特定编码的上下文中解释。对于单字节字母表,这些编码称为代码页。

代码页有所帮助,但它们并没有解决所有问题。您始终必须知道特定文档使用哪个代码页才能正确解释它。此外,您通常无法编写使用不同语言的单个文档。

此外,某些语言的字符数超过256个,因此无法将一个char映射到一个字符。这导致了多字节字符编码的发展,其中[0..127]仍然是ASCII,但是其他一些值是&#34;转义&#34;这意味着你必须查看一些以下char来确定你真正拥有的角色。 (最好将多字节视为变量 - 字节,因为有些字符只需要一个字节,而其他字符只需要两个或更多字节。)多字节有效,但它可以使用多字节。为代码而痛苦。

与此同时,内存变得越来越丰富,因此许多组织聚集在一起创建了Unicode,其目标是将值通用映射到字符(对于#34;字符&#34;的适当模糊定义)。最初,人们相信所有角色(或者至少是所有人都会使用的角色)都适合16位值,这很好,因为你不必处理多字节编码 - 你&# 39; d每个字符只使用两个字节而不是一个字节。大约在这个时候,微软决定采用Unicode作为Windows中文本的内部表示。

<强> WCHAR

因此,Windows有一个名为char的类型,一个双字节值,表示&#34; Unicode&#34; &#34;字符&#34 ;.我在这里使用引号因为Unicode已经过了原始的双字节编码,所以Windows调用了什么&#34; Unicode&#34;今天并不是真正的Unicode - 它实际上是Unicode的特定编码,称为UTF-16。一个&#34;字符&#34;在Unicode中并不像在ASCII中那样简单,因为在某些语言中,字符以有趣的方式组合或以其他方式影响相邻字符。

较新版本的Windows在内部使用了这些16位WCHAR值的文本,但是仍有大量代码用于单字节代码页,甚至还有一些代码用于多字节编码。这些程序仍然使用WCHAR而不是char s。其中许多程序必须与使用旧版Windows的人一起使用,这些Windows仍在内部使用WCHAR以及使用char的新版本。因此,设计了一种使用C宏和typedef的技术,以便您可以以一种方式编写代码,并在编译时选择使用WCHARchar

<强> TCHAR

为了实现这种灵活性,您可以使用WCHAR作为&#34;文本字符&#34;。在某些头文件(通常为TCHAR)中,<tchar.h>可以是TCHARchar的typedef,具体取决于编译时环境。 Windows标头采用了这样的约定:

  • WCHAR是指向LPTSTR s。
  • 字符串的(长)指针
  • TCHAR是指向LPWSTR s。
  • 字符串的(长)指针
  • WCHAR是指向LPSTR s。
  • 字符串的(长)指针

char for&#34; long&#34;是16位日的剩余时间,当时我们有长,远,近指针。这些都已经过时,但是{{1前缀倾向于保留。)

获取和返回字符串的大多数Windows API函数实际上都替换为两个版本:L版本(用于&#34; ANSI&#34;字符)和L版本(用于广泛的人物)。 (同样,历史遗留在这些中显示。代码页方案通常被称为ANSI代码页,尽管我们从来都不清楚它们是否真的被ANSI标准所统治。)

因此,当您调用这样的Windows API时:

A

您真正在做的是调用扩展为WSetWindowText(hwnd, lptszTitle); 的预处理器宏。它应该与SetWindowTextA定义一致。也就是说,如果您想要SetWindowTextW个字符串,那么您将获得TCHAR版本,如果您想要char个字符串,则可以获得A版本

但由于字符串文字,它有点复杂。如果你这样写:

WCHAR

然后只有在您定位W版本时才会编译,因为SetWindowText(hwnd, "Hello World"); // works only in "ANSI" mode char s的字符串,所以它只与"Hello World"兼容char版本。如果您想要SetWindowTextA版本,则必须写:

WCHAR

此处SetWindowText(hwnd, L"Hello World"); // only works in "Unicode" mode 表示您需要宽字符。 (L实际上代表很长,但它与上面的长指针有着不同的长度感。)当编译器在字符串上看到L前缀时,它知道该字符串应该是编码为一系列L而不是wchar_t s。

(针对Windows的编译器使用char的双字节值,这恰好与Windows定义的wchar_t相同。针对其他系统的编译器通常使用{{1}的四字节值1}},这是保存单个Unicode代码点所需要的。)

因此,如果您想要能够以任何方式编译的代码,则需要另一个宏来包装字符串文字。有两种选择:WCHARwchar_t。它们的工作方式完全相同。第一个来自编译器库,第二个来自OS的库。所以你写这样的代码:

_T()

如果您定位TEXT(),则该宏是一个只返回常规字符串文字的无操作。如果您定位SetWindowText(hwnd, TEXT("Hello World")); // compiles in either mode ,则宏会预先设置char

那么如何告诉编译器你想要定位WCHAR?您可以定义LWCHAR。前者用于Windows API,后者用于编译器库。确保你永远不要定义另一个。

答案 1 :(得分:3)

我的猜测是你在Unicode模式下编译。

尝试将格式字符串括在_T宏中,该宏旨在提供始终正确的方法来提供常量字符串参数,无论您是以Unicode还是ANSI模式进行编译:

out.Format(_T("\nInstall32 at %s\n"), tmp);