Article ID: 138813
Article Last Modified on 3/16/2005
/*
* AnsiToUnicode converts the ANSI string pszA to a Unicode string
* and returns the Unicode string through ppszW. Space for the
* the converted string is allocated by AnsiToUnicode.
*/
HRESULT __fastcall AnsiToUnicode(LPCSTR pszA, LPOLESTR* ppszW)
{
ULONG cCharacters;
DWORD dwError;
// If input is null then just return the same.
if (NULL == pszA)
{
*ppszW = NULL;
return NOERROR;
}
// Determine number of wide characters to be allocated for the
// Unicode string.
cCharacters = strlen(pszA)+1;
// Use of the OLE allocator is required if the resultant Unicode
// string will be passed to another COM component and if that
// component will free it. Otherwise you can use your own allocator.
*ppszW = (LPOLESTR) CoTaskMemAlloc(cCharacters*2);
if (NULL == *ppszW)
return E_OUTOFMEMORY;
// Covert to Unicode.
if (0 == MultiByteToWideChar(CP_ACP, 0, pszA, cCharacters,
*ppszW, cCharacters))
{
dwError = GetLastError();
CoTaskMemFree(*ppszW);
*ppszW = NULL;
return HRESULT_FROM_WIN32(dwError);
}
return NOERROR;
/*
* UnicodeToAnsi converts the Unicode string pszW to an ANSI string
* and returns the ANSI string through ppszA. Space for the
* the converted string is allocated by UnicodeToAnsi.
*/
HRESULT __fastcall UnicodeToAnsi(LPCOLESTR pszW, LPSTR* ppszA)
{
ULONG cbAnsi, cCharacters;
DWORD dwError;
// If input is null then just return the same.
if (pszW == NULL)
{
*ppszA = NULL;
return NOERROR;
}
cCharacters = wcslen(pszW)+1;
// Determine number of bytes to be allocated for ANSI string. An
// ANSI string can have at most 2 bytes per character (for Double
// Byte Character Strings.)
cbAnsi = cCharacters*2;
// Use of the OLE allocator is not required because the resultant
// ANSI string will never be passed to another COM component. You
// can use your own allocator.
*ppszA = (LPSTR) CoTaskMemAlloc(cbAnsi);
if (NULL == *ppszA)
return E_OUTOFMEMORY;
// Convert to ANSI.
if (0 == WideCharToMultiByte(CP_ACP, 0, pszW, cCharacters, *ppszA,
cbAnsi, NULL, NULL))
{
dwError = GetLastError();
CoTaskMemFree(*ppszA);
*ppszA = NULL;
return HRESULT_FROM_WIN32(dwError);
}
return NOERROR;
}
Sample use of these functions is as follows. CoTaskMemFree is used to
free the converted string if CoTaskMemAlloc was used to allocate the
string. The converted string must not be freed if it is returned through
an out-parameter to another OLE component, because that component is
responsible for freeing the string. LPOLESTR is a pointer to a Unicode
string.
// The following code gets an ANSI filename that is specified by the
// user in the OpenFile common dialog. This file name is converted into
// a Unicode string and is passed to the OLE API CreateFileMoniker. The
// Unicode string is then freed.
OPENFILENAME ofn;
LPOLESTR pszFileNameW;
LPMONIKER pmk;
:
// Get file name from OpenFile Common Dialog. The ANSI file name will
// be placed in ofn.lpstrFile
GetOpenFileName(&ofn);
:
AnsiToUnicode(ofn.lpstrFile, &pszFileNameW);
CreateFileMoniker(pszFileNameW, &pmk);
CoTaskMemFree(pszFileNameW);
// The following code implements IOleInPlaceFrame::SetStatusText.
// The lpszStatusText string, that is received from another OLE
// component, uses Unicode. The string is converted to ANSI before it is
// passed to the ANSI version of SetWindowText. Windows 95 supports only
// the ANSI version of SetWindowText.
COleInPlaceFrame::SetStatusText(LPCOLESTR pszStatusTextW)
{
LPSTR pszStatusTextA;
UnicodeToAnsi(pszStatusTextW, &pszStatusTextA);
SetWindowText(m_hwndStatus, pszStatusTextA);
CoTaskMemFree(pszStatusTextA);
}
NOTE: Comments in AnsiToUnicode and UnicodeToAnsi regarding the
allocator that is used to allocate the converted string. CoTaskMemAlloc
(the OLE allocator) is required to be used only if the resultant string
will be passed to another OLE component and if that component can free
the string. This means that strings that are passed as in-parameters to
OLE interface methods need not use the OLE allocator. Strings that are
passed as in-out-parameters or returned through out-parameters or in-
out-parameters must be allocated using the OLE allocator.
CreateFileMoniker(OLESTR("c:\\boo\\har.doc"), &pmk);
Another example of ANSI/Unicode conversion routines can be found in the
Microsoft Foundation Classes (MFC) source code which ships with the
Visual C++ 4.0 compiler. These routines are described in MFC Technote
59: 'Using MFC MBCS/Unicode Conversion Macros'. The definition these
macros OLE2T, T2OLE, OLE2CT, T2COLE, A2W, W2A, A2CW, W2CA and
USES_CONVERSION are in \msdev\mfc\include\afxpriv.h. Also see
AfxA2WHelper and AfxW2AHelper in the MFC source code in \msdev\mfc\src
and the use of OLE2T, T2OLE, OLE2CT and T2COLE in the MFC source code in
\msdev\mfc\src. These functions allow code to be compiled either for
Unicode or ANSI depending on whether the _UNICODE preprocessor
definition has been made. For example, the CreateFileMoniker call in the
above example can be made as follows with the MFC macros:
USES_CONVERSION; GetOpenFileName(&ofn); CreateFileMoniker(T2OLE(ofn.lpstrFile), &pmk);If _UNICODE is defined, T2OLE is defined as follows:
inline LPOLESTR T2OLE(LPTSTR lp) { return lp; }
If _UNICODE is not defined, T2OLE is defined as follows:
#define T2OLE(lpa) A2W(lpa)T in T2OLE indicates that the type being converted to an OLE string (Unicode string) is a Unicode string when _UNICODE is defined and an ANSI string when _UNICODE is not defined. Similarly LPTSTR is defined as a pointer to a Unicode string when _UNICODE is defined and as a pointer to an ANSI string when _UNICODE is not defined. T2OLE doesn't do any conversion when _UNICODE is defined (LPTSTR == LPOLESTR). When Unicode is not defined, A2W is called. A2W converts an ANSI string to Unicode as follows:
#define A2W(lpa) (\
((LPCSTR)lpa == NULL) ? NULL : (\
_convert = (strlen(lpa)+1),\
AfxA2WHelper((LPWSTR) alloca(_convert*2), lpa, _convert)\
)\
)
AfxA2WHelper uses MultiByteToWideChar to do the conversion.GetOpenFileName(&ofn); CreateFileMoniker(String16(ofn.lpstrFile), &pmk);In the above code, an instance of String16 is created. The constructor of the class will convert the ANSI string to Unicode. The language implementation will call the cast operator, operator const wchar_t *, to cast this parameter to the type of of CreateFileMoniker's first parameter. The cast operator will return the Unicode string which is passed to CreateFileMoniker. The object will destruct when in goes out of scope.
// String16 ////////////////////////////////////////////////////////
// Shim class that converts both 8-bit (foreign) and
// 16-bit (native) strings to 16-bit wideness
class String16 {
public:
// native and foreign constructors
String16(const char *p8);
String16(const wchar_t *p16);
// non-virtual destructor (this class is concrete)
~String16(void);
// native conversion operator
operator const wchar_t * (void) const;
private:
// native wideness string
wchar_t *m_sz;
// is foreign??
BOOL m_bIsForeign;
// protect against assignment!
String16(const String16&);
String16& operator=(const String16&);
};
// native constructor is a pass-through
inline String16::String16(const wchar_t *p16)
: m_sz((wchar_t *)p16), m_bIsForeign(FALSE)
{
}
// simply give out the native wideness string
inline String16::operator const wchar_t * (void) const
{
return m_sz;
}
// foreign constructor requires allocation of a native
// string and conversion
inline String16::String16(const char *p8)
: m_bIsForeign(TRUE)
{
// calculate string length
size_t len = strlen(p8);
// calculate required buffer size (some characters may
// already occupy 16-bits under DBCS)
size_t size = mbstowcs(0, p8, len) + 1;
// alloc native string and convert
if (m_sz = new wchar_t[size])
mbstowcs(m_sz, p8, size);
}
// delete native string only if synthesized in foreign constructor
inline String16::~String16(void) {
if (m_bIsForeign)
delete[] m_sz;
}
Additional query words: convert helper routines functions
Keywords: kbhowto kbprogramming kbcode KB138813