Ever wondered why W2A leaks a lot of memory when used in a loop?
for(int i=0;i<count;i++)
{
str= W2A(bstr);
cout<<str<<endl;
}
When we try and step in at W2A we end up with following ASM code.
*********************************************************************************
_alloca_probe_16 proc ; 16 byte aligned alloca
push ecx
lea ecx, [esp] + 8 ; TOS before entering this function
sub ecx, eax ; New TOS
and ecx, (16 - 1) ; Distance from 16 bit align (align down)
add eax, ecx ; Increase allocation size
sbb ecx, ecx ; ecx = 0xFFFFFFFF if size wrapped around
or eax, ecx ; cap allocation size on wraparound
pop ecx ; Restore ecx
jmp _chkstk
***********************************************************************************
What we see here is the stack is resized as in, W2A does an allocation on the stack
so what would happen when this goes in a loop? obvious answer would be, the stack
grows, and ends up with Stack Overflow problem.
so what would happen when this goes in a loop? obvious answer would be, the stack
grows, and ends up with Stack Overflow problem.
So we end up with a couple of questions..
1.What is the best way takle this problem.
2.Are there any alternatives.
3.Why USES_CONVERSION MACRO when we use W2A.
3.Why USES_CONVERSION MACRO when we use W2A.
1.One way is to manually convert it CString like this function MyW2A
does.
does.
CString MyW2A(BSTR bstr)
{
CString s;
If(bstr!=NULL)
{
LPSTR p = s.GetBuffer(SysStringLen(bstr) + 1);
::WideCharToMultiByte(CP_ACP,
0,
bstr,
-1, // assume NUL-terminated
p,
SysStringLen(bstr)+1,
NULL,
NULL);
s.ReleaseBuffer();
}
return s;
}//MyW2A
JNM(Joseph NewComer) has a very good article on String management here
2. CW2A which has been provided as part of ATL 7.0 can be used instead of W2A,
another cool thing about this is, USES_CONVERSION is not required for CW2A.
another cool thing about this is, USES_CONVERSION is not required for CW2A.
3. Why do we need, USES_CONVERSION MACRO when we use W2A?
The answer lies in Atlconv.h file and the way these macros have been defined.
/*
*where is the _lpw defined?
*where is _convert defined?
*where is _acp defined?
*/
*where is the _lpw defined?
*where is _convert defined?
*where is _acp defined?
*/
#define W2A(lpw) (\
((_lpw = lpw) == NULL) ? NULL : (\
(_convert = (lstrlenW(_lpw)+1), \
(_convert>INT_MAX/2) ? NULL : \
ATLW2AHELPER((LPSTR) alloca(_convert*sizeof(WCHAR)), _lpw,
_convert*sizeof(WCHAR), _acp))))
_convert*sizeof(WCHAR), _acp))))
/*
* U guessed it right? Look at the definition of USES_CONVERSION
* Simple right!!!
*/
* Simple right!!!
*/
#define USES_CONVERSION int _convert = 0; (_convert);\
UINT _acp = ATL::_AtlGetConversionACP() /*CP_THREAD_ACP*/;\
(_acp); LPCWSTR _lpw = NULL; (_lpw); \
LPCSTR _lpa = NULL; (_lpa)
UINT _acp = ATL::_AtlGetConversionACP() /*CP_THREAD_ACP*/;\
(_acp); LPCWSTR _lpw = NULL; (_lpw); \
LPCSTR _lpa = NULL; (_lpa)
Another clue would be when we compile without the USES_CONVERSION macro, we end up with the following errors.
1>c:\..\vc days\.....\w2atest\w2atest\w2atest.cpp(45) : error C2065: '_lpw' : undeclared identifier
1>c:\..\vc days\......\w2atest\w2atest\w2atest.cpp(45) : error C2065: '_convert' : undeclared identifier
1>c:\..\vc days\......\w2atest\w2atest\w2atest.cpp(45) : error C2065: '_lpw' : undeclared identifier
1>c:\..\vc days\......\w2atest\w2atest\w2atest.cpp(45) : error C2065: '_convert' : undeclared identifier
1>c:\..\vc days\......\w2atest\w2atest\w2atest.cpp(45) : error C2065: '_convert' : undeclared identifier
1>c:\..\vc days\......\w2atest\w2atest\w2atest.cpp(45) : error C2065: '_lpw' : undeclared identifier
1>c:\..\vc days\......\w2atest\w2atest\w2atest.cpp(45) : error C2065: '_convert' : undeclared identifier
1>c:\..\vc days\......\w2atest\w2atest\w2atest.cpp(45) : error C2065: '_acp' : undeclared identifier
No comments:
Post a Comment