2010-01-18 13 views
6

Necesito convertir una instancia CString en un BSTR correctamente asignado y pasar ese BSTR en un método COM. Para tener un código que compila y funciona de manera idéntica tanto para ANSI como para Unicode, uso CString::AllocSysString() para convertir cualquier formato CString en un BSTR Unicode.¿Cómo convertir mejor CString a BSTR para pasarlo como un parámetro "in" en un método COM?

Como nadie posee el BSTR devuelto, tengo que encargarme de él y liberarlo después de que la llamada se realiza de la forma más segura posible y con el menor número posible de códigos.

Actualmente uso ATL::CComBSTR para la gestión de toda la vida:

ATL::CComBSTR converted; 
converted.Attach(sourceString.AllocSysString()); //simply attaches to BSTR, doesn't reallocate it 
interface->CallMethod(converted); 

lo que no me gusta aquí es que necesito dos estados separados a poco construir el ATL::CComBSTR unido al resultado de conversión.

¿Hay una manera mejor de realizar la misma tarea?

Respuesta

14

CComBSTR tiene constructores sobrecargados para char* y wchar_t*, que hacen la llamada a SysAllocString() en su nombre. Por lo tanto, la asignación explícita en su fragmento de código es realmente innecesaria. El siguiente funcionaría igual de bien:

ATL::CComBSTR converted = sourceString; 
interface->CallMethod(converted); 

Por otra parte, si usted no tiene necesidad de utilizar el BSTR convertido en otra parte de su código, puede realizar la construcción objeto in situ en la llamada al método, así:

interface->CallMethod(ATL::CComBSTR(sourceString)); 

lo mismo se aplica a la clase _bstr_t, que se puede utilizar en lugar de CComBSTR si no desea que una dependencia de la ATL.

+0

Eso definitivamente funcionará, excepto que con el uso del constructor CComBSTR tendré que verificar que la asignación de BSTR fue exitosa (CString :: AllocSysString() hace el control y lanza una excepción) y con _bstr_t tendré que ocuparme de _com_issue_error() función - anularlo o capturar _com_error lanzado desde él. – sharptooth

+0

¿Por qué no dejar que el método llamado sea responsable de verificar la validez de sus propios argumentos? Si la asignación falla, 'CComBSTR :: m_str' será nulo. Entonces, o el método llamado verificará nulo y devolverá 'E_INVALIDARG', o no, y el mismo' catch' que ya tiene para 'CString :: AllocSysString()' puede manejar la excepción por usted. Es un modismo más limpio que realizar el control de manera explícita, imho. –

+1

@Phil Booth: El método al que se llama podría interpretar un BSTR nulo como un caso especial. Por ejemplo, el significado podría ser "especifica un nombre de archivo, si se pasa una cadena vacía, se utiliza el nombre de archivo predeterminado". Por lo tanto, el método que se invoque podría no tener la oportunidad de saber que hay un problema. – sharptooth

2

Uno de los aspectos confusos de la programación de Windows es la gestión de la conversión de cadenas de estilo de Visual Basic a/desde cadenas de estilo de lenguaje C. No es que sea tan difícil, es difícil recordar los detalles. Por lo general, no se realiza con frecuencia, y la documentación de MSDN es tan voluminosa que es difícil encontrar respuestas a sus preguntas. Pero, la peor parte es que podría realizar algún tipo de conversión que compila bien, pero no funciona de la manera que esperaba. Esto da como resultado un código que no funciona, y los errores son difíciles de rastrear. Después de un poco de experiencia, aprendes a asegurarte de que tus conversiones de cadenas estén haciendo lo que esperas.

Las cadenas en C son matrices de caracteres terminados por un carácter NULO. Las cadenas de Visual Basic difieren en que la longitud de la cadena precede a los caracteres en la cadena. Entonces, una cadena VB conoce su propia longitud. Además, todas las cadenas de VB son Unicode (16 bits por carácter). tipos de cadenas

BSTR/conversiones C de cadena son necesarios si:

You are doing COM programming in C/C++ 
You are writing multiple language applications, such as C++ DLL's accessed by Visual Basic applications. 
1

Uno de _bstr_t constructores le permite simplemente conectar a la existente BSTR para que pueda tener la excepción de que usted quiere de CString::AllocSysString cuando BSTR asignación falla

// _bstr_t simply attaches to BSTR, doesn't reallocate it 
interface->CallMethod(_bstr_t(sourceString.AllocSysString(), false)); 

El _bstr_t constructor documentation dice:

_bstr_t(
    BSTR bstr, 
    bool fCopy 
); 

fCopy
Si es falso, el argumento bstr se une al nuevo objeto sin hacer una copia llamando SysAllocString.

Por otro lado, CComBSTR constructor no parece tener la firma correspondiente; aunque se puede utilizar también si la excepción de error de asignación BSTR no es realmente necesaria, como se menciona en Phil Booth en his answer.

Cuestiones relacionadas