如何将 std::wstring 转换为 LSA_UNICODE_STRING

发布于 2024-12-27 15:59:22 字数 1371 浏览 2 评论 0原文

今天,我能够编写一个简单的 C++ 程序,该程序授予用户“作为服务登录”权限 。其中一部分涉及在 LPCWSTRLSA_UNICODE_STRING。执行此操作的代码如下:

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;
}

当我在此函数中出现一些小错误时,我调用 LsaLookupNames2() 失败,代码为 87(十六进制 0x57)“参数不正确。”我试图在使用 std::wstring 的 C++ 应用程序中进行此调用,但失败了。我当前的功能如下:

#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

我做错了什么?

Today I was able to write a simple C++ program that granted a user the "Log on as a service" privilege. Part of this involved converting between a LPCWSTR and an 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." I am trying to make this call in a C++ app that uses std::wstring and it is failing. 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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

忘东忘西忘不掉你 2025-01-03 15:59:22

您可能会遇到从 str.c_str() 返回的 wchar_t* 的生命周期问题。 str.c_str() 将返回一个指向底层字符串的指针,该字符串的生命周期由 str 控制。由于 str 是按值传递的,因此它将在 toLsaUnicodeString 函数末尾被销毁,导致返回的 LSA_UNICODE_STRING 指向内存已被解除分配。为了避免这种情况,您需要在 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;
}

:现在内存已在堆上分配,您有责任确保它已被释放。您可以使用如下所示的函数来处理此问题。

void freeLsaUnicodeString(LSA_UNICODE_STRING& str) {
    delete [] str.Buffer;
    str.Buffer = 0;
    str.Length = 0;
    str.MaximumLength = 0;
}

更好的是使用 RAII 来管理内存并保证当变量不再使用时将其释放。有关此方法的详细信息,请参阅 Mr_C64 的回答。

You're likely encountering a lifetime issue with the wchar_t* returned from str.c_str(). str.c_str() will return a pointer to an underlying string whose lifetime is governed by 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. 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:

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. See Mr_C64's answer for details on this approach.

紫竹語嫣☆ 2025-01-03 15:59:22

我认为在 C++ 中执行此操作的正确方法是围绕原始 C 结构 LSA_UNICODE_STRING 编写一个 RAII 包装器 类。

此类的构造函数重载正确地初始化它,析构函数释放分配的资源(帮助编写异常安全代码),并且您可以提供一些operator=重载来执行正确的深层复制。

动态分配的WCHAR缓冲区不是使用显式的new[]和delete[],而是由std::vector的实例管理,这简化了代码(例如std::vector的析构函数将自动释放分配的内存)。

像这样的东西:

#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];
    }
};

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.

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.

Instead of using explicit new[] and delete[], the dynamically-allocated WCHAR buffer is managed by an instance of std::vector, which simplifies the code (e.g. std::vector's destructor will automatically release the allocated memory).

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];
    }
};
世俗缘 2025-01-03 15:59:22

您可以使用 RtlInitUnicodeString 函数命令初始化一个 unicode 字符串。使用 UNICODE_STRING 调用 RtlFreeUnicodeString< /a>.

UNICODE_STRING 和 LSA_UNICODE_STRING 相同。

You can use the RtlInitUnicodeString function in order to initialize a unicode string. After using the UNICODE_STRING call RtlFreeUnicodeString.

The UNICODE_STRING and LSA_UNICODE_STRING are identical.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文