简体   繁体   English

WIndows API中的“L”和“LPCWSTR”

[英]The 'L' and 'LPCWSTR' in WIndows API

I've found that 我发现了

NetUserChangePassword(0, 0, L"ab", L"cd");

changes the user password from ab to cd. 将用户密码从ab更改为cd。 However, 然而,

NetUserChangePassword(0, 0, (LPCWSTR) "ab", (LPCWSTR) "cd");

doesn't work. 不起作用。 The returned value indicates invalid password. 返回的值表示密码无效。

I need to pass const char* as last two parameters for this function call. 我需要传递const char*作为此函数调用的最后两个参数。 How can I do that? 我怎样才能做到这一点? For example, 例如,

NetUserChangePassword(0, 0, (LPCWSTR) vs[0].c_str(), (LPCWSTR) vs[1].c_str());

Where vs is std::vector<std::string> . 其中vsstd::vector<std::string>

You have two problems. 你有两个问题。

The first is the practical problem - how to do this. 首先是实际问题 - 如何做到这一点。 You are confusing wide and narrow strings and casting from one to the other. 你混淆宽窄的弦乐,从一个到另一个。 A string with an L prefix is a wide string, where each character is two bytes (a wchar_t ). 带有L前缀的字符串是一个宽字符串,其中每个字符都是两个字节( wchar_t )。 A string without the L is a single byte (a char ). 没有L的字符串是单个字节( char )。 You cannot cast from one to the other using the C-style cast (LPCWSTR) "ab" because you have an array of char s, and are casting it to a pointer to wide chars. 你不能使用C风格的转换 (LPCWSTR) "ab" 从一个转换为另一个,因为你有一个char数组,并将它转换为指向宽字符的指针。 It is simply changing the pointer type, not the underlying data. 它只是更改指针类型,而不是基础数据。

To convert from a narrow string to a wide string, you would normally use MultiByteToWideChar . 要从窄字符串转换为宽字符串,通常使用MultiByteToWideChar You don't mention what code page your narrow strings are in; 你没有提到你的窄字符串所在的代码页; you would probably pass in CP_ACP for the first parameter. 你可能会传入CP_ACP作为第一个参数。 However, since you are converting between a string and a wstring, you might be interested in other ways to convert ( one , two ). 但是,由于您在字符串和wstring之间进行转换,因此您可能对其他转换方法感兴趣( )。 This will give you a wstring with your characters, not a string , and a wstring 's .c_str() method returns a pointer to wchar_t s. 这将为您提供带有字符的wstring ,而不是string ,并且wstring.c_str()方法返回指向wchar_t的指针。

The second is the following misunderstanding: 第二个是以下误解:

I need to pass const char* as last two parameters for this function call. 我需要传递const char *作为此函数调用的最后两个参数。 How can I do that? 我怎样才能做到这一点?

No you don't. 不,你没有。 You need to pass a wide string, which you got above. 你需要传递一个宽字符串,你在上面。 Your approach to this (casting the pointer) indicates you probably don't know about different string types and character encodings, and this is something every software developer should know. 你的方法(转换指针)表明你可能不知道不同的字符串类型和字符编码,这是每个软件开发人员都应该知道的。 So, on the assumption you're interested, hopefully you'll find the following references handy: 因此,假设您有兴趣,希望您能找到以下参考资料:

I'd recommend you investigate recompiling your application with UNICODE and using wide strings. 我建议您调查使用UNICODE重新编译应用程序并使用宽字符串。 Many APIs are defined in both narrow and wide versions, and normally this would mean you access the narrow version by default (you can access either the ANSI (narrow) or Wide versions of these APIs by directly calling the A or W version - they have A or W appended to their name, such as CreateWindowW - see the bottom of that page for the two names. You normally don't need to worry about this.) As far as I can tell, this API is always available as-is regardless of UNICODE , it's just it's only prototyped as wide. 许多API都是在窄版本和宽版本中定义的,通常这意味着您默认访问窄版本(您可以通过直接调用A或W版本来访问这些API的ANSI(窄版)或宽版本 - 它们具有A或W附加到它们的名称,例如CreateWindowW - 请参见该页面底部的两个名称。您通常不需要担心这一点。)据我所知,此API始终可用。无论UNICODE如何,它只是它的原型。

Those are two totally different L 's. 那是两个完全不同的L '。 The first is a part of the C++ language syntax. 第一部分是C ++语言语法的一部分。 Prefix a string literal with L and it becomes a wide string literal; L前缀一个字符串文字,它变成一个字符串文字; instead of an array of char , you get an array of wchar_t . 而不是char数组,你得到一个wchar_t数组。

The L in LPCWSTR doesn't describe the width of the characters, though. 但是, LPCWSTR中的L不描述字符的宽度。 Instead, it describes the size of the pointer . 相反,它描述了指针的大小。 Or, at least, it used to . 或者,至少,它曾经用过 The L abbreviation on type names is a relic of 16-bit Windows, when there were two kinds of pointers. 类型名称上的L缩写是16位Windows的遗留物,当有两种指针时。 There were near pointers, where the address was somewhere within the current 64 KB segment, and there were far , or long pointers, which could point beyond the current segment. 指针,其中地址位于当前64 KB段内的某个位置,并且存在指针,它们可能指向当前段之外。 The OS required callers to provide the latter to its APIs, so all the pointer-type names use LP . 操作系统要求调用者将后者提供给其API,因此所有指针类型名称都使用LP Nowadays, there's only one type of pointer; 如今,只有一种指针; Microsoft keeps the same type names so that old code continues to compile. Microsoft保留相同的类型名称,以便旧代码继续编译。

The part of LPCWSTR that specifies wide characters is the W . 指定宽字符的LPCWSTR部分是W But merely type-casting a char string literal to LPCWSTR is not sufficient to transform those characters into wide characters. 但仅仅型铸造一个char字符串文本LPCWSTR不足以这些字符转换成宽字符。 Instead, what happens is the type-cast tells the compiler that what you wrote really is a pointer to a wide string, even though it really isn't. 相反,会发生什么是类型转换告诉编译器你写的东西一个指向宽字符串的指针,即使它确实不是。 The compiler trusts you. 编译器信任你。 Don't type-cast unless you really know better than the compiler what the real types are. 除非你真的比编译器更了解真实类型,否则不要进行类型转换。

If you really need to pass a const char* , then you don't need to type-cast anything, and you don't need any L prefix. 如果你真的需要传递一个const char* ,那么你不需要输入任何东西,并且你不需要任何L前缀。 A plain old string literal is sufficient. 一个普通的旧字符串文字就足够了。 (If you really want to cast to a Windows type, use LPCSTR — no W .) But it looks like what you really need to pass in is a const wchar_t* . (如果你真的想要转换为Windows类型,请使用LPCSTR - 没有W )但是看起来你真正需要传递的是const wchar_t* As we learned above, you can get that with the L prefix on the string literal. 如上所述,您可以在字符串文字上使用L前缀。

In a real program, you probably don't have a string literal. 在实际程序中,您可能没有字符串文字。 The user will provide a password, or you'll read a password from some other external source. 用户将提供密码,或者您将从其他外部源读取密码。 Ideally, you would store that password in a std::wstring , which is like std::string but for wchar_t instead of char . 理想情况下,您可以将该密码存储在std::wstring ,这类似于std::string但是对于wchar_t而不是char The c_str() method of that type returns a const wchar_t* . 该类型的c_str()方法返回const wchar_t* If you don't have a wstring , a plain array of wchar_t might be sufficient. 如果你没有wstringwchar_t的普通数组可能就足够了。

But if you're storing the password in a std::string , then you'll need to convert it into wide characters some other way. 但是如果你将密码存储在std::string ,那么你需要以其他方式将其转换为宽字符。 To do a conversion, you need to know what code page the std::string characters use. 要进行转换,您需要知道std::string字符使用的代码页 The "current ANSI code page" is usually a safe bet; “当前的ANSI代码页”通常是一个安全的赌注; it's represented by the constant CP_ACP . 它由常量CP_ACP表示。 You'll use that when calling MultiByteToWideString to have the OS convert from the password's code page into Unicode. 您将在调用MultiByteToWideString时将其用于将操作系统从密码的代码页转换为Unicode。

int required_size = MultiByteToWideChar(CP_ACP, 0, vs[0].c_str(), vs[0].size(), NULL, 0);
if (required_size == 0)
  ERROR;
// We'll be storing the Unicode password in this vector. Reserve at
// least enough space for all the characters plus a null character
// at the end.
std::vector<wchar_t> wv(required_size);
int result = MultiByteToWideChar(CP_ACP, 0, vs[0].c_str(), vs[0].size(), &wv[0], required_size);
if (result != required_size - 1)
  ERROR;

Now, when you need a wchar_t* , just use a pointer to the first element of that vector: &wv[0] . 现在,当你需要一个wchar_t* ,只需使用指向该向量的第一个元素的指针: &wv[0] If you need it in a wstring , you can construct it from the vector in a few ways: 如果你需要在wstring ,你可以通过几种方式从向量构造它:

// The vector is null-terminated, so use "const wchar_t*" constructor
std::wstring ws1 = &wv[0];
// Use iterator constructor. The vector is null-terminated, so omit
// the final character from the iterator range.
std::wstring ws2(wv.begin(), wv.end() - 1);
// Use pointer/length constructor.
std::wstring ws3(&wv[0], wv.size() - 1);

C style casts as you've used here are a very blunt instrument. 你在这里使用的C风格演员是一种非常生硬的乐器。 They assume you know exactly what you're doing. 他们假设你确切地知道你在做什么。

You'll need to convert your ASCII or multi-byte strings into Unicode strings for the API. 您需要将ASCII或多字节字符串转换为API的Unicode字符串。 There might be a NetUserChangePasswordA function that takes the char * types you're trying to pass, try that first. 可能有一个NetUserChangePasswordA函数接受您尝试传递的char *类型,首先尝试。

LPWSTR定义为wchar_t *(whcar_T是2字节char类型),其解释方式与正常的1字节字符不同。

LPCWSTR means you need to pass a wchar_t*. LPCWSTR意味着您需要传递wchar_t *。

if you change vs to std::vector<std::wstring> that will give you a wide char when you pass vs[0].c_str() 如果你更改vs到std::vector<std::wstring> ,当你传递vs [0] .c_str()时会给你一个宽字符

if you look at the example at http://msdn.microsoft.com/en-us/library/aa370650(v=vs.85).aspx you can see that they define UNICODE which is why they use the wchar_t. 如果你看看http://msdn.microsoft.com/en-us/library/aa370650(v=vs.85).aspx上的例子,你可以看到他们定义了UNICODE,这就是他们使用wchar_t的原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM