| CodeGuru Home | VC++ / MFC / C++ | .NET / C# | Visual Basic | Newsletters | VB Forums | Developer.com |
|
|||||||
| CodeGuru Individual FAQs The indivdual FAQs for CodeGuru. See the specific Topic FAQ forums for index pages and links to these Frequently Asked/Answered Questions. |
![]() |
|
|
Thread Tools | Search this Thread | Display Modes |
|
#1
|
||||
|
||||
|
Q: ATL String: What's wrong with the USES_CONVERSION macros? How to avoid using them?
A: The simplest way (in ATL 3.0) to convert a Wide Character String to an ANSI String is by using OLE2A or W2A, and their equivalent Macros. Simplest, but not the safest! Code:
BSTR bstrMyBeaster = SysAllocString (L"Tring, Tring!"); WCHAR* pwszMyWCharString = L"Tring, Tring!"; USES_CONVERSION; LPSTR pszCharStringFromBSTR = OLE2A (bstrMyBeaster); LPSTR pszCharStringFromLPWSTR = W2A (pwszMyWCharString); // ... SysFreeString (bstrMyBeaster); Q: If it is simple and if it works, then, what's wrong in using it? A: Macros such as OLE2A, W2A and the likes cause Stack Overflows when used in loops. The reason:_alloca allocates memory on the Function Stack. This memory is released ("popped") only on function exit. So, a loop that loops too often and converts strings can result in a situation where the stack has no space left to offer. This situation causes a Stack Overflow Exception. Sample of a Prospective Stack Overflow Exception causing Function: Code:
int StackGuzzler (void)
{
WCHAR* pwszTest = SOME_WCHAR_STRING;
for (int nCounter = 0; nCounter < SOME_MAX_COUNT; nCounter++)
{
USES_CONVERSION;
LPSTR pszCharVersion = W2A (pwszTest); // Allocated on stack
}
return 1;
} // Stack Memory is cleared i.e. "popped" here - this is sometimes too late!
Q: How do we overcome this Stack Overflow problem? A: By not using the macros. By simply delegating the string conversion to another function - one that returns the ANSI String (i.e. 'char*' or 'LPSTR' allocated on the heap/free store). If you are using ATL 7.0, you have the option to use a set of Conversion Classes that are better suited. Take a look at the next question for further information. Function that safely converts a BSTR to LPSTR: Code:
char* ConvertBSTRToLPSTR (BSTR bstrIn)
{
LPSTR pszOut = NULL;
if (bstrIn != NULL)
{
int nInputStrLen = SysStringLen (bstrIn);
// Double NULL Termination
int nOutputStrLen = WideCharToMultiByte(CP_ACP, 0, bstrIn, nInputStrLen, NULL, 0, 0, 0) + 2;
pszOut = new char [nOutputStrLen];
if (pszOut)
{
memset (pszOut, 0x00, sizeof (char)*nOutputStrLen);
WideCharToMultiByte (CP_ACP, 0, bstrIn, nInputStrLen, pszOut, nOutputStrLen, 0, 0);
}
}
return pszOut;
}
Code:
char* ConvertLPWSTRToLPSTR (LPWSTR lpwszStrIn)
{
LPSTR pszOut = NULL;
if (lpwszStrIn != NULL)
{
int nInputStrLen = wcslen (lpwszStrIn);
// Double NULL Termination
int nOutputStrLen = WideCharToMultiByte (CP_ACP, 0, lpwszStrIn, nInputStrLen, NULL, 0, 0, 0) + 2;
pszOut = new char [nOutputStrLen];
if (pszOut)
{
memset (pszOut, 0x00, nOutputStrLen);
WideCharToMultiByte(CP_ACP, 0, lpwszStrIn, nInputStrLen, pszOut, nOutputStrLen, 0, 0);
}
}
return pszOut;
}
Code:
LPWSTR pwszMyWideCharString = L"Tring, Tring!"; LPSTR pszSimpleCharStringFromLPWSTR = ConvertLPWSTRToLPSTR(pwszMyWideCharString); // .. use the string delete [] pszSimpleCharStringFromLPWSTR; SysFreeString (bstrMyBeaster); Code:
BSTR bstrMyBeaster = SysAllocString (L"Tring, Tring!"); LPSTR pszSimpleCharStringFromBSTR = ConvertBSTRToLPSTR(bstrMyBeaster); // ... use the string delete [] pszSimpleCharStringFromBSTR; SysFreeString (bstrMyBeaster); Q: Does this issue persist with ATL 7.0? A: Fortunately, no - as you now have the option to not use these macros. Changes with ATL 7.0:
Last edited by Siddhartha; November 10th, 2005 at 06:11 PM. |
![]() |
| Bookmarks |
|
||||||
| Thread Tools | Search this Thread |
| Display Modes | |
|
|