2010-01-18 12 views
6

Ho bisogno di convertire un'istanza CString in una BSTR allocata correttamente e passare tale BSTR in un metodo COM. Per avere il codice che compila e lavora indenticamente sia per ANSI che per Unicode, utilizzo CString::AllocSysString() per convertire qualsiasi formato CString in un BSTR Unicode.Come convertire CString in BSTR per passarlo come parametro "in" in un metodo COM?

Dal momento che nessuno possiede il BSTR restituito, devo occuparmene e rilasciarlo dopo che la chiamata è stata eseguita nel modo più sicuro possibile e con il minor numero possibile di codice.

Attualmente io uso ATL::CComBSTR per la gestione del ciclo di vita:

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

quello che non mi piace qui è che ho bisogno di due prospetti separati a poco costruire l'ATL::CComBSTR legata al risultato conversione.

Esiste un modo migliore per eseguire lo stesso compito?

risposta

14

CComBSTR ha sovraccaricato i costruttori sia per char* e wchar_t*, che rendono la chiamata a SysAllocString() a vostro nome. Quindi l'allocazione esplicita nello snippet di codice non è effettivamente necessaria. Di seguito avrebbe funzionato altrettanto bene:

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

Inoltre, se non avete bisogno di usare il convertito BSTR altrove nel codice, è possibile eseguire la costruzione oggetto sul posto nella chiamata di metodo, in questo modo:

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

lo stesso vale per la classe _bstr_t, che può essere usato al posto di CComBSTR se non si vuole una dipendenza sul ATL.

+0

Ciò funzionerà sicuramente, tranne che con l'utilizzo del costruttore CComBSTR dovrò verificare che l'allocazione BSTR abbia avuto successo (CString :: AllocSysString() esegue il controllo e genera un'eccezione) e con _bstr_t dovrò occuparmi di Funzione _com_issue_error() - la sovrascrive o cattura _com_error da essa generata. – sharptooth

+0

Perché non lasciare che sia il metodo chiamato a controllare la validità dei propri argomenti? Se l'allocazione fallisce, 'CComBSTR :: m_str' sarà nullo. Quindi, il metodo chiamato controllerà la presenza di null e restituirà 'E_INVALIDARG', o non lo farà e lo stesso' catch' che avete già per 'CString :: AllocSysString()' può gestire l'eccezione per voi. È un idioma più pulito rispetto a eseguire esplicitamente il controllo, imho. –

+1

@Phil Booth: il metodo chiamato potrebbe interpretare un BSTR nullo come un caso speciale. Ad esempio, il significato potrebbe essere "specifica un nome file, se viene passata una stringa vuota viene usato il nome file predefinito". Quindi il metodo chiamato potrebbe non avere alcuna possibilità di sapere che c'è un problema. – sharptooth

2

Uno degli aspetti confusi della programmazione di Windows è la gestione della conversione di stringhe di stile di Visual Basic in/da stringhe di stile del linguaggio C. Non è che sia così difficile, è solo difficile ricordare i dettagli. Di solito non è fatto spesso, e la documentazione MSDN è così voluminosa che è difficile trovare risposte alle vostre domande. Ma la parte peggiore è che potresti eseguire un certo typecast che viene compilato correttamente, ma non funziona come ti aspetti. Ciò si traduce in codice che non funziona, e gli errori sono difficili da rintracciare. Dopo un po 'di esperienza, impari ad accertarti che le conversioni di stringhe facciano ciò che ti aspetti.

Le stringhe C sono matrici di caratteri terminati da un carattere NULL. Le stringhe di Visual Basic differiscono in quanto la lunghezza della stringa precede i caratteri nella stringa. Quindi, una stringa VB conosce la sua lunghezza. Inoltre, tutte le stringhe VB sono Unicode (16 bit per carattere). tipi di stringhe

BSTR/conversioni C String sono richiesti se:

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 dei _bstr_t costruttori permette di collegare semplicemente esistente BSTR in modo che si può avere l'eccezione che si desidera da CString::AllocSysString quando BSTR allocazione non riesce.

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

Il _bstr_t constructor documentation dice:

_bstr_t(
    BSTR bstr, 
    bool fCopy 
); 

fCopy
Se false, l'argomento bstr è collegato al nuovo oggetto senza fare una copia chiamando SysAllocString.

D'altra parte, CComBSTR constructor non sembra avere la firma corrispondente; anche se può essere utilizzato anche se l'eccezione di allocazione di allocazione BSTR non è realmente necessaria, come indicato da Phil Booth in his answer.