[英]How do I convert a std::wstring to an LSA_UNICODE_STRING
Today I was able to write a simple C++ program that granted a user the "Log on as a service" privilege . 今天我能够编写一个简单的C ++程序,授予用户“作为服务登录”权限 。 Part of this involved converting between a LPCWSTR
and an LSA_UNICODE_STRING
. 部分内容涉及在LPCWSTR
和LSA_UNICODE_STRING
之间进行转换。 The code to do that is here: 这样做的代码在这里:
LSA_UNICODE_STRING StringToLsaUnicodeString(LPCWSTR string) {
LSA_UNICODE_STRING lsaString;
DWORD dwLen = 0;
dwLen = wcslen(string);
lsaString.Buffer = (LPWSTR) string;
lsaString.Length = (USHORT)((dwLen) * sizeof(WCHAR));
lsaString.MaximumLength = (USHORT)((dwLen + 1) * sizeof(WCHAR));
return lsaString;
}
When I had some small errors in this function, my call to LsaLookupNames2()
failed with a code 87(hex 0x57) "The parameter is incorrect." 当我在这个函数中遇到一些小错误时,我对LsaLookupNames2()
调用失败,代码为87(十六进制0x57)“参数不正确”。 I am trying to make this call in a C++ app that uses std::wstring
and it is failing. 我试图在使用std::wstring
的C ++应用程序中进行此调用,但它失败了。 My current function there is as follows: 我目前的功能如下:
#if defined(_UNICODE)
LSA_UNICODE_STRING toLsaUnicodeString (std::wstring str) {
LSA_UNICODE_STRING lsaWStr;
DWORD len = 0;
LPWSTR cstr = (LPWSTR)str.c_str();
len = wcslen(cstr);
lsaWStr.Buffer = cstr;
lsaWStr.Length = (USHORT)((len) * sizeof(WCHAR));
lsaWStr.MaximumLength = (USHORT)((len + 1) * sizeof(WCHAR));
return lsaWStr;
}
#endif
What am I doing wrong? 我究竟做错了什么?
You're likely encountering a lifetime issue with the wchar_t*
returned from str.c_str()
. 您可能会遇到str.c_str()
返回的wchar_t*
的生命周期问题。 str.c_str()
will return a pointer to an underlying string whose lifetime is governed by str
. str.c_str()
将返回一个指向基础字符串的指针,该字符串的生命周期由str
。 Since str
is passed by-value, it will be destroyed at the end of the toLsaUnicodeString
function, resulting in the returned LSA_UNICODE_STRING
pointing at memory that has been deallocated. 由于str
是按值传递的,因此它将在toLsaUnicodeString
函数的末尾被销毁,从而导致返回的LSA_UNICODE_STRING
指向已解除分配的内存。 In order to avoid this, you'll need to make a copy of the underlying string in the toLsaUnicodeString
function, and associate the copy with the returned LSA_UNICODE_STRING
, something like: 为了避免这种情况,您需要在toLsaUnicodeString
函数中复制基础字符串,并将副本与返回的LSA_UNICODE_STRING
相关联,如:
LSA_UNICODE_STRING toLsaUnicodeString (const std::wstring& str) {
LSA_UNICODE_STRING lsaWStr;
DWORD len = 0;
len = str.length();
LPWSTR cstr = new WCHAR[len + 1];
memcpy(cstr, str.c_str(), (len + 1) * sizeof(WCHAR));
lsaWStr.Buffer = cstr;
lsaWStr.Length = (USHORT)((len) * sizeof(WCHAR));
lsaWStr.MaximumLength = (USHORT)((len + 1) * sizeof(WCHAR));
return lsaWStr;
}
Since the memory is now allocated on the heap, you are responsible for making sure it is deallocated. 由于内存现在已在堆上分配,因此您有责任确保将其释放。 You can use a function like the following to take care of this. 您可以使用以下功能来处理此问题。
void freeLsaUnicodeString(LSA_UNICODE_STRING& str) {
delete [] str.Buffer;
str.Buffer = 0;
str.Length = 0;
str.MaximumLength = 0;
}
Even better would be to use RAII to manage the memory and guarantee that it is released when the variable is no longer in use. 更好的方法是使用RAII来管理内存,并保证在变量不再使用时释放内存。 See Mr_C64's answer for details on this approach. 有关此方法的详细信息,请参阅Mr_C64的答案。
I think the correct way of doing this in C++ is to write a RAII wrapper class around the raw C structure LSA_UNICODE_STRING. 我认为在C ++中执行此操作的正确方法是围绕原始C结构LSA_UNICODE_STRING编写RAII包装类。
The constructor overloads of this class properly initialize it, the destructor releases allocated resources (helping writing exception-safe code), and you can provide some operator= overloads to do proper deep-copies. 这个类的构造函数重载正确地初始化它,析构函数释放分配的资源(帮助编写异常安全的代码),并且你可以提供一些operator =重载来做适当的深拷贝。
Instead of using explicit new[] and delete[], the dynamically-allocated WCHAR buffer is managed by an instance of std::vector, which simplifies the code (eg std::vector's destructor will automatically release the allocated memory). 而不是使用显式的new []和delete [],动态分配的WCHAR缓冲区由std :: vector的实例管理,这简化了代码(例如std :: vector的析构函数将自动释放分配的内存)。
Something like this: 像这样的东西:
#include <windows.h> // Win32 SDK header
#include <LsaLookup.h> // LSA_UNICODE_STRING
#include <vector> // std::vector
#include <string> // std::wstring
//
// C++ RAII wrapper to LSA_UNICODE_STRING
//
class LsaUnicodeString
{
public:
LsaUnicodeString()
{
SetEmpty();
}
LsaUnicodeString(const LsaUnicodeString & source)
{
CopyFrom(source);
}
explicit LsaUnicodeString(const std::wstring & source)
{
CopyFrom(source);
}
~LsaUnicodeString()
{
// Nothing to do:
// the string buffer is managed by std::vector data member
}
LsaUnicodeString & operator=(const LsaUnicodeString & source)
{
if (&source != this)
{
CopyFrom(source);
}
return *this;
}
LsaUnicodeString & operator=(const std::wstring & source)
{
CopyFrom(source);
return *this;
}
const LSA_UNICODE_STRING & Get() const
{
return m_us;
}
//
// Implementation
//
private:
LSA_UNICODE_STRING m_us; // raw C structure
std::vector<WCHAR> m_buffer; // string content
void SetEmpty()
{
m_buffer.resize(1);
m_buffer[0] = L'\0'; // end-of-string
m_us.Length = 0;
m_us.MaximumLength = sizeof(WCHAR);
m_us.Buffer = &m_buffer[0];
}
void CopyFrom(const std::wstring & source)
{
if ( source.empty() )
{
SetEmpty();
return;
}
const int len = source.length();
m_buffer.resize(len + 1);
::CopyMemory(&m_buffer[0], source.c_str(), (len+1)*sizeof(WCHAR));
m_us.Length = len * sizeof(WCHAR);
m_us.MaximumLength = m_us.Length + sizeof(WCHAR);
m_us.Buffer = &m_buffer[0];
}
void CopyFrom(const LsaUnicodeString & source)
{
if (source.m_us.Length == 0)
{
SetEmpty();
return;
}
m_buffer = source.m_buffer;
m_us.Length = source.m_us.Length;
m_us.MaximumLength = source.m_us.MaximumLength;
m_us.Buffer = &m_buffer[0];
}
};
You can use the RtlInitUnicodeString function in order to initialize a unicode string. 您可以使用RtlInitUnicodeString函数来初始化unicode字符串。 After using the UNICODE_STRING call RtlFreeUnicodeString . 使用UNICODE_STRING后调用RtlFreeUnicodeString 。
The UNICODE_STRING and LSA_UNICODE_STRING are identical. UNICODE_STRING和LSA_UNICODE_STRING是相同的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.