CodeGuru Forums -
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic Newsletters VB Forums Developer.com


Newest CodeGuru.com Articles:

  • Installing SQL Server 2008
  • Writing UDFs for Firebird Embedded SQL Server
  • [Updated] Shutdown Manager
  • Building Windows Azure Cloud Service Applications with Azure Storage and the Azure SDK

  • Search CodeGuru:
     



    Go Back   CodeGuru Forums > CodeGuru Technical FAQs > CodeGuru Individual FAQs
    FAQ Members List Calendar Search Today's Posts Mark Forums Read

    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.

    Reply
     
    Thread Tools Search this Thread Display Modes
      #1    
    Old April 17th, 2005, 03:56 PM
    Siddhartha's Avatar
    Siddhartha Siddhartha is offline
    Super Moderator
    Power Poster
     
    Join Date: Oct 2002
    Location: Germany
    Posts: 6,192
    Siddhartha has a reputation beyond repute (3000+)Siddhartha has a reputation beyond repute (3000+)Siddhartha has a reputation beyond repute (3000+)Siddhartha has a reputation beyond repute (3000+)Siddhartha has a reputation beyond repute (3000+)Siddhartha has a reputation beyond repute (3000+)Siddhartha has a reputation beyond repute (3000+)Siddhartha has a reputation beyond repute (3000+)Siddhartha has a reputation beyond repute (3000+)Siddhartha has a reputation beyond repute (3000+)Siddhartha has a reputation beyond repute (3000+)
    Lightbulb ATL String: What's wrong with the USES_CONVERSION macros? How to avoid using them?

    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:

    They allocate memory using _alloca
    _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;
    }
    Function that safely converts a 'WCHAR' String to 'LPSTR':

    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;
    }
    Using them:

    Code:
    LPWSTR pwszMyWideCharString = L"Tring, Tring!";
    LPSTR pszSimpleCharStringFromLPWSTR = ConvertLPWSTRToLPSTR(pwszMyWideCharString);
    
    // .. use the string
    
    delete [] pszSimpleCharStringFromLPWSTR;
    SysFreeString (bstrMyBeaster);
    and
    Code:
    BSTR bstrMyBeaster = SysAllocString (L"Tring, Tring!");
    LPSTR pszSimpleCharStringFromBSTR = ConvertBSTRToLPSTR(bstrMyBeaster);
    
    // ... use the string
    
    delete [] pszSimpleCharStringFromBSTR;
    SysFreeString (bstrMyBeaster);
    The two methods above totally erase the possibility of causing a Stack Overflow whilst converting Wide-Character Strings.


    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:
    • ATL 7.0 claims to resolve the issue of accumulating memory allocation per loop-cycle.
    • ATL 7.0 does not require USES_CONVERSION macros.
    • ATL 7.0 provides conversion (template) classes, and not macros.
      Code:
       
      CW2T pszString (L"Tring Tring"); 
        
      // Use it as a LPCTSTR 
      std::cout << pszString;
    For more information on how to convert strings using ATL 7.0, visit: ATL 7.0 String Conversion Classes and Macros.

    Last edited by Siddhartha; November 10th, 2005 at 06:11 PM.
    Reply With Quote
    Reply

    Bookmarks
    Go Back   CodeGuru Forums > CodeGuru Technical FAQs > CodeGuru Individual FAQs


    Thread Tools Search this Thread
    Search this Thread:

    Advanced Search
    Display Modes

    Posting Rules
    You may not post new threads
    You may not post replies
    You may not post attachments
    You may not edit your posts

    BB code is On
    Smilies are On
    [IMG] code is On
    HTML code is On
    Forum Jump


    All times are GMT -5. The time now is 08:24 PM.



    Acceptable Use Policy

    internet.comMediabistrojusttechjobs.comGraphics.com

    WebMediaBrands Corporate Info


    Advertise | Newsletters | Feedback | Submit News

    Legal Notices | Licensing | Permissions | Privacy Policy


    Powered by vBulletin® Version 3.7.3
    Copyright ©2000 - 2009, Jelsoft Enterprises Ltd.
    Copyright WebMediaBrands Inc. 2002-2009