2011-03-10 28 views
9

¿Es legal enviar un LPTSTR directamente a un BSTR?¿Puedes lanzar un LPTSTR a un BSTR?

Basado en mi understanding of BSTR, el envío de un LPTSTR directamente a un BSTR lo dejará con un prefijo de longitud dañado. El código de ejemplo establece explícitamente que un literal de cadena no se puede almacenar en un BSTR. ¿Alguien puede confirmarme que un LPTSTR/LPCTSTR no puede ser lanzado directamente a un BSTR sin corromper el prefijo de longitud?

EDIT:

Mi confusión es de ver esto se utiliza en una llamada a un objeto COM. Resulta que al compilar el dll COM, se genera un archivo .tli que crea un método intermedio. Este método toma el tipo _bstr_t. El _bstr_t puede tomar LPTSTR en su constructor, por lo que todo funciona sin problemas.

Respuesta

8

Si su programa es unicode y su LPTSTR por lo tanto, es un LPWSTR, puede utilizar SysAllocString convertir de un puntero a una cadena de caracteres anchos a BSTR.

No se puede realizar una conversión directa porque las dos tienen diferentes representaciones de memoria.

Si usa C++, puede usar la clase _bstr_t para simplificar el uso de las cadenas BSTR.

1

No puede ser, porque los cuatro bytes en la memoria que preceden a LPTSTR se considerarán como la longitud del resultado BSTR. Esto podría causar una falla de protección de memoria en el lugar (no muy probable), pero sin duda resultaría en un BSTR con una longitud que podría ser mucho mayor que la longitud del original LPTSTR. Entonces, cuando alguien intenta leer o escribir, pueden acceder a la memoria no válida.

+3

Los datos de cadena no se interpretarán como longitud. Los bytes inmediatamente anteriores serían. Un BSTR apunta a la parte de cadena de la estructura de longitud + cadena. –

+0

@Ben: Gracias por la aclaración, no lo sabía. Revisaré la respuesta en consecuencia. – Jon

0

No, no puede transmitirlos directamente. Sin embargo, puede hacer una cadena que haga ambas cosas. Una C-String no tiene un encabezado de 4 bytes. Sin embargo, el bit en el medio es el mismo, por lo que si necesita ambas representaciones, cree una clase contenedora que construya una cadena con un encabezado de 4 bytes y un terminador nulo, pero puede devolver los descriptores de acceso a la parte BSTR y al C-String.

Este código está destinado a ser un ejemplo incompleto, ¡no lo he compilado!

class YetAnotherStringType //just what the world needs 
{ 
    public: 
    YetAnotherStringType(const char *str) 
    { 
    size_t slen = strlen(str); 
    allocate(slen); 
    set_size_dword(slen); 
    copy_cstr(str, slen);  
    } 

    const char *get_cstr() const 
    { 
    return &m_data[4]; 
    } 

    const BSTR get_bstr() const 
    { 
    return (BSTR*)m_data; 
    } 

    void copy_cstr(const char *cstr, int size = -1) 
    { 
     if (size == -1) 
     size = strlen(cstr); 
     memcpy(&m_data[4], cstr, size + 1); //also copies first null terminator 
     m_data[5 + size] = 0; //add the second null terminator 
    } 

    void set_size_dword(size_t size) 
    { 
    *((unsigned int*)m_data) = size; 
    } 

    void allocate(size_t size) 
    { 
    m_data = new char[size + 6]; //enough for double terminator 
    } 

    char *m_data; 
}; 
+0

'BSTR's tienen un terminador doble nulo. – Jon

+0

@Jon: Ah, lo siento. Leí la página aquí y leí que no, estaba malinterpretando. Parecen estar diciendo que el encabezado no contiene un terminador nulo (!?) – Luther

+0

Ya existe una cadena que hace las dos cosas: '_bstr_t' de' ' –

1

A LPTSTR es un puntero a una matriz de caracteres (o TCHAR para ser exactos) BSTR es un structur (o de datos compuesto) consisten en * Longitud prefijo * cadena de datos * Terminator

por lo que la fundición no funcionará

0

No, no se puede - si el código que cree que es un BSTR llama al SysStringLen() se ejecutará en un comportamiento indefinido ya que esa función se basa en algunos datos de servicio específicos de la implementación.

0

No puede transmitir, debe convertir. Puede usar el compilador incorporado intrínseco _bstr_t (desde comutil.h) para ayudarle a hacer esto fácilmente. Muestra:

#include <Windows.h> 
#include <comutil.h> 

#pragma comment(lib, "comsuppwd.lib") 

int main() 
{ 
    LPTSTR p = "Hello, String"; 
    _bstr_t bt = p; 
    BSTR bstr = bt; 
    bstr; 
} 
+0

@John Dibling: Hola. ¿No funcionaría el ejemplo que di? Si no, ¿podría explicar por qué por favor? – Luther

+1

@Luther: dos cosas. 1) ¿Por qué escribir un montón de código cuando MS ya proporciona una clase para hacer esto por usted (_bstr_t)? 2) El código que escribió puede o no funcionar; No estoy seguro. Se supone que debes llamar a 'SysAllocString' para crear un BSTR, pero estás tratando de utilizar tu conocimiento del funcionamiento interno de un BSTR para construir uno tú mismo. Además, la porción de cadena de un BSTR es Unicode.La tuya, creo, no lo es. –

+0

@John Dibling: gracias por la respuesta. No estoy tratando de reinventar la rueda, el código fue solo para ilustrar un punto. Nuestro hombre aquí estaba preguntando sobre el casting, en lugar de construir y copiar, un BSTR. Puede tener una buena razón para lanzar en lugar de reconstruir (requisitos estrictos de memoria, muchas llamadas dentro de un bucle interno, no quiere tocar el montón, etc.) y la clase que esbocé allí * debería * lograr eso. Si BSTRs son UniCode, entonces reemplace el char * con wchar_t *. A veces es mejor escribir un poco de código si las formas estándar no hacen el trabajo como a usted le gustaría. – Luther

0

En términos generales no, pero hay maneras de hacerlos compatibles en cierta medida a través de clases de ayuda y macros (véase más adelante).

La razón principal por la que un mapeado 1: 1 nunca será posible es que un BSTR (y por lo tanto CComBSTR puede contener '\0' en la cadena, porque en última instancia es un tipo de cadena contado


Su mejor. elección cuando se utiliza C++ sería ir para la clase ATL CComBSTR en lugar de BSTR adecuada. en cualquiera de los casos se puede hacer uso de la ATL/macros de conversión MFC CW2A y amigos.

también tenga en cuenta que la documentación (MSDN) dice :

La forma recomendada de convertir a y de BSTR cuerdas es utilizar la clase CComBSTR. Para convertir a BSTR, pase la cadena existente al constructor de CComBSTR. Para convertir desde un BSTR, use COLE2 [C] DestinationType [EX], como COLE2T.

... que se aplica a su caso de uso.

Consulte la respuesta de John Dibling para obtener una alternativa (_bstr_t).

4

Si usted está tratando de pasar LPCTSTR s como BSTR s usted encontrará que usted azar estallar en cualquier código de clasificación de interoperabilidad llegar cerca. La clasificación extraerá el prefijo de 4 bytes (que es datos aleatorios) para un LPCTSTR e intenta y Marshall la cadena.

Encontrará que el prefijo de 4 bytes resulta ser el contenido de la pila antes de su búfer, o incluso mejores datos de caracteres de la cadena anterior. A continuación, tratar de ordenar megabytes de datos ... :-)

utilizan los CComBSTR envoltorios y utilizar .Detach() si es necesario para mantener el puntero BSTR.

Se bueno si el compilador escupe una advertencia en este caso.

+0

Acabo de ser mordido por esto, pasando tres parámetros L "My String" a un método COM de .Net esperando 3 BSTRs y solo uno sobrevivió la interoperabilidad de interoperabilidad. No hay advertencias del compilador VS2008/W4 – Lallen

+0

El prefijo de 4 bytes representa la longitud de BSTR. – lsalamon

Cuestiones relacionadas