Convert CString to ANSI string in UNICODE projects   Leave a comment

Quick Answer: use an intermediate CStringA.

  • Normally, this is not something that should be done.
  • It is technically unreliable, unless you can guarantee that the source CString to be converted does not contain any 2-byte characters.
  • This will work fine if you are using the English language without any special 2-byte symbols or accented letters.
  • This article is for educational use, and explains how it can easily be done, without relying on the USES_CONVERSION macro with W2A, or ridiculous WideCharToMultiByte API functions.
  • If you are using a language that actually requires Unicode (Asian languages, etc), or if the source CString contains any 2-byte character, this cannot be done. This is because there is no ANSI equivalent of any 2-byte character.
  • It is the responsibility of the programmer to ensure that the source CString does not contain any 2-byte characters.

Use intermediate CStringA (highly recommended):

  • Simple, easy, and effective. Almost impossible to use improperly.
  • This is only reliable if the source CString does not contain any 2-byte characters.
CString LastNameW( L"Smith" );
CStringA LastNameA( LastNameW );
FunctionForAnsi( (LPCSTR)LastNameA );
  • Or an even simpler example:
CString LastNameW( L"Smith" );
FunctionForAnsi( (LPCSTR)CStringA( LastNameW ) );

Here are some other ways that either do not work or are not recommended. I list them here to document things to avoid. What not to do.

WideCharToMultiByte API function (not recommended):

  • Too complicated. Too much code to write, test, debug.
CString LastNameW( L"Smith" );
int nLen = WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)LastNameW, -1, NULL, NULL );
LPSTR lpszA = new CHAR[nLen];
WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)LastNameW, -1, lpszA, nLen );
FunctionForAnsi( lpszA );
delete[] lpszA; // free the string

W2A ATL 3.0 macros (not recommended):

  • Not safe inside loops.
USES_CONVERSION;
CString LastNameW( L"Smith" );
FunctionForAnsi( W2A( (LPCWSTR)LastNameW ) );

CW2A ATL 7.0 conversion template classes (not recommended):

  • Strict rules to follow for proper usage. Too easy to use improperly.
CString LastNameW( L"Smith" );
CW2A pszA( (LPCWSTR)LastNameW ); // this is the right way
FunctionForAnsi( pszA );
CString LastNameW( L"Smith" );
FunctionForAnsi( CW2A( (LPCWSTR)LastNameW ) ); // improper usage, do not do this
CString LastNameW( L"Smith" );
LPCSTR pszA = CW2A( (LPCWSTR)LastNameW ); // improper usage, do not do this
FunctionForAnsi( pszA );

(LPCSTR)(LPCTSTR) cast (do not do this):

  • You cannot use (LPCSTR)(LPCTSTR) to cast a CString to LPCSTR in Unicode projects.
  • It does compile, but it does not properly convert the CString to an LPCSTR.
  • The resulting string will either be 0 or 1 length, or filled with garbage characters of unknown length, because the cast just changes the pointer type without any conversion.
  • You end up with a CHAR* pointing to a WCHAR array, a very bad thing.
CString LastName( L"Smith" );
FunctionForAnsi( (LPCSTR)(LPCTSTR)LastName ); // improper usage, do not to this

REF:

ATL String: What’s wrong with the USES_CONVERSION macros? How to avoid using them?

Using MFC MBCS/Unicode Conversion Macros

ATL and MFC String Conversion Macros

CString Management

About these ads

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: