c++ com wchar-t bstr

c++ - ¿Cómo se puede copiar eficientemente BSTR a wchar_t[]?



com wchar-t (5)

Tengo un objeto BSTR que me gustaría convertir para copiar a un objeto wchar__t. Lo complicado es que la longitud del objeto BSTR puede ser de unos pocos kilobytes a unos pocos cientos de kilobytes. ¿Existe una forma eficiente de copiar los datos? Sé que podría simplemente declarar una matriz wchar_t y siempre asignar la máxima cantidad posible de datos que alguna vez necesitaría contener. Sin embargo, esto significaría asignar cientos de kilobytes de datos para algo que posiblemente solo requiera unos pocos kilobytes. ¿Alguna sugerencia?


Los objetos BSTR contienen un prefijo de longitud, por lo que conocer la longitud es barato. Averigüe la longitud, asigne una nueva matriz lo suficientemente grande como para contener el resultado, procese en eso y recuerde liberarlo cuando haya terminado.


Nunca hay necesidad de conversión. Un puntero BSTR apunta al primer carácter de la cadena y termina en nulo. La longitud se almacena antes del primer carácter en la memoria. BSTR s siempre son Unicode (UTF-16 / UCS-2). Hubo en un momento algo llamado ''ANSI BSTR'' - hay algunas referencias en API heredadas - pero puede ignorarlas en el desarrollo actual.

Esto significa que puede pasar un BSTR forma segura a cualquier función esperando un wchar_t .

En Visual Studio 2008 puede obtener un error de compilación, porque BSTR se define como un puntero al unsigned short , mientras que wchar_t es un tipo nativo. Puede activar o desactivar el cumplimiento de wchar_t con /Zc:wchar_t .


Use ATL y CStringT, entonces puede usar el operador de asignación. O puede usar las macros USES_CONVERSION, estas usan la asignación de montón, por lo que estará seguro de no perder memoria.


Una cosa a tener en cuenta es que las cadenas BSTR pueden, y a menudo lo hacen, contener nulos incorporados. Un nulo no significa el final de la cadena.


En primer lugar, es posible que en realidad no tenga que hacer nada en absoluto, si todo lo que necesita hacer es leer los contenidos. Un tipo BSTR es un puntero a una matriz wchar_t terminada en nulo ya. De hecho, si revisa los encabezados, encontrará que BSTR se define esencialmente como:

typedef BSTR wchar_t*;

Entonces, el compilador no puede distinguir entre ellos, a pesar de que tienen una semántica diferente.

Hay dos advertencias importantes.

  1. Se supone que los BSTR son inmutables. Nunca debe cambiar el contenido de un BSTR después de que se haya inicializado. Si lo "cambia", debe crear uno nuevo, asigne el nuevo y suelte el anterior (si es el propietario).
    [ ACTUALIZACIÓN : esto no es verdad; ¡lo siento! Puede modificar los BSTR en su lugar; Raramente he tenido la necesidad.]

  2. Los BSTR pueden contener caracteres nulos incorporados, mientras que las cadenas C / C ++ tradicionales no lo son.

Si tiene un buen control del origen del BSTR y puede garantizar que el BSTR no tiene NULL incorporados, puede leer del BSTR como si fuera un wchar_t y usar métodos de cadena convencionales (wcscpy, etc.) para acceder a él. Si no, tu vida se vuelve más difícil. Deberá manipular siempre sus datos como más BSTR o como una matriz de wchar_t asignada dinámicamente. La mayoría de las funciones relacionadas con cadenas no funcionarán correctamente.

Supongamos que controlas tus datos, o no te preocupes por los NULL. Supongamos también que realmente necesita hacer una copia y no puede simplemente leer el BSTR existente directamente. En ese caso, puedes hacer algo como esto:

UINT length = SysStringLen(myBstr); // Ask COM for the size of the BSTR wchar_t *myString = new wchar_t[lenght+1]; // Note: SysStringLen doesn''t // include the space needed for the NULL wcscpy(myString, myBstr); // Or your favorite safer string function // ... delete myString; // Done

Si está utilizando wrappers de clase para su BSTR, el contenedor debería tener una forma de llamar a SysStringLen () por usted. Por ejemplo:

CComBString use .Length(); _bstr_t use .length();

ACTUALIZACIÓN : Este es un buen artículo sobre el tema por alguien mucho más conocedor que yo:
"La guía completa de Eric [Lippert] para la semántica BSTR"

ACTUALIZACIÓN : reemplazó strcpy () con wcscpy () en el ejemplo