2 votos

¿Cómo convierto una cadena std::wstring en una cadena LSA_UNICODE_STRING?

Hoy he podido escribir un sencillo programa en C++ que otorgara a un usuario el privilegio "Conectarse como servicio . Parte de esto implicaba la conversión entre un LPCWSTR y un LSA_UNICODE_STRING . El código para hacerlo está aquí:

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

Cuando tuve algunos pequeños errores en esta función, mi llamada a LsaLookupNames2() falló con un código 87(hex 0x57) "El parámetro es incorrecto". Estoy intentando hacer esta llamada en una aplicación C++ que utiliza std::wstring y está fallando. Mi función actual es la siguiente:

#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

¿Qué estoy haciendo mal?

4voto

DRH Puntos 3773

Es probable que te encuentres con un problema de por vida con el wchar_t* devuelto de str.c_str() . str.c_str() devolverá un puntero a una cadena subyacente cuyo tiempo de vida se rige por str . Desde str se pasa por-valor, se destruirá al final de la operación toLsaUnicodeString que devuelve la función LSA_UNICODE_STRING apuntando a la memoria que ha sido reasignada. Para evitar esto, tendrá que hacer una copia de la cadena subyacente en el archivo toLsaUnicodeString y asociar la copia con la función LSA_UNICODE_STRING Algo así:

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

Dado que la memoria está ahora asignada en el heap, eres responsable de asegurarte de que se desasigna. Para ello, puede utilizar una función como la siguiente.

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

Aún mejor sería utilizar RAII para gestionar la memoria y garantizar que se libera cuando la variable ya no está en uso. Véase la respuesta de Mr_C64 para más detalles sobre este enfoque.

3voto

Creo que la forma correcta de hacer esto en C++ es escribir una directiva Envoltorio RAII en torno a la estructura C bruta LSA_UNICODE_STRING.

Las sobrecargas del constructor de esta clase la inicializan adecuadamente, el destructor libera los recursos asignados (ayudando a escribir código a prueba de excepciones), y puedes proporcionar algunas sobrecargas operator= para hacer copias profundas adecuadas.

En lugar de utilizar explícitamente new[] y delete[], el buffer WCHAR asignado dinámicamente es gestionado por una instancia de std::vector, lo que simplifica el código (por ejemplo, el destructor de std::vector liberará automáticamente la memoria asignada).

Algo así:

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

1voto

Norbert Willhelm Puntos 1449

Puede utilizar la función RtlInitUnicodeString para inicializar una cadena unicode. Después de utilizar la llamada UNICODE_STRING RtlFreeUnicodeString .

UNICODE_STRING y LSA_UNICODE_STRING son idénticos.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X