views:

1113

answers:

5

So far I've discovered I can convert incoming BSTRs to ANSI in two (of many?) ways, and I'm curious to know whether one is "better" than the other with respect to speed / efficiency etc.

The way I've been using for a while is use the USES_CONVERSION and W2A macros, e.g.

BSTR __stdcall F(BSTR p1, BSTR p2 ) {
    USES_CONVERSION;

    LPSTR sNum1 = W2A( p1 );
    LPSTR sNum2 = W2A( p2 );

Recently, however, I came across another technique:

BSTR __stdcall F(BSTR p1, BSTR p2 ) {
    long amt = wcstombs( NULL, p1, 1 );
    sNum1 = (char *) malloc( amt ); 
    wcstombs( sNum1, p1, amt );
    *(sNum1 + amt) = '\0';

    amt = wcstombs( NULL, p2, 1 );
    sNum2 = (char *) malloc( amt ); 
    wcstombs( sNum2, p2, amt );
    *(sNum2 + amt) = '\0';

Now I grant you, it's wordier, and has two calls to wcstombs but for all I know the USES_CONVERSION and W2A macros may be hiding all sorts of fun and games.

Which is the more efficient / faster code? Or, is there another technique I could use that would do the job better?

+1  A: 

W2A is good and easy to use if you're using ATL 7.0. ATL 3.0 can stack overflow on large strings, 7.0 doesn't have that problem and allocates memory on heap for big strings. ATL 7.0 doesn't need USES_CONVERSION macro either.

Full comparison of 3.0 and 7.0 is here.

ssg
+6  A: 

From MSDN:

[...]The recommended way of converting to and from BSTR strings is to use the CComBSTR class. To convert to a BSTR, pass the existing string to the constructor of CComBSTR. To convert from a BSTR, use COLE2[C]DestinationType[EX], such as COLE2T.

From the CComBSTR page:

[...]The CComBSTR class provides a number of members (constructors, assignment operators, and comparison operators) that take either ANSI or Unicode strings as arguments. The ANSI versions of these functions are less efficient than their Unicode counterparts because temporary Unicode strings are often created internally. For efficiency, use the Unicode versions where possible.

dirkgently
+2  A: 

Note:

If you use the ATL macros, eg: COLE2[C]DestinationType[Ex] (which you probably should), be sure to use the 'C' versions as possible, not the non-const versions as you have written. They may be equivalent for explicit BSTR->ASCII conversions (ie: COLE2A), but for conversions where there is no actual conversion required (eg: COLE2T when compiling for UNICODE), the 'C' versions can expand to noops, whereas the non-'C' versions will still copy if the source string is const (because you are expressing that you need the resulting string to be non-const).

Also of note:

The new ATL7 macros don't always require USES_CONVERSION, however they allocate temporary r-value objects, whereas the old macros use _alloca. This may or may not be important, depending on your usage (for example, DO NOT use the old macros in a loop which runs a large number of times, you can blow out the stack doing so).

Nick
+1  A: 

It's been a long time since i've done anything with COM or BSTRs but my suggestion is to stop treating BSTR's as something special. Treat them like a pointer to a wide character zero terminated string... if you do it might be easier to convert them to ANSI. check Eric's Complete Guide to BSTR Semantics...

nabiy
+1  A: 

Note in the approved answer by Nick, which whilst correct shares the same problem there is with the MSDN documentation that describes the macros.

The problem is that some of the macros such as the one listed by Nick - COLE2A, don't actually exist.

However further down the MSDN page there is some text that clues you into this fact and leads you to be able to figure out the correct macro!

The text is listed in the table under the following text:

There are several important differences between the older string conversion macros and the new string conversion classes:

In the New ATL 7.0 Conversion Classes column.

Which says:

OLE is always equivalent to W

So the macro in Nicks example is actually CW2A

Stone Free
Nasty ... thanks for that bit of info. Very helpful.
boost