Archive

Posts Tagged ‘ATL’

ATL CString Extension for UTF-8, UTF-7, ASCII, OEM, Latin1 Character Sets

April 29th, 2009 Christian Etter No comments

Sometimes we come across Text that has been encoded in a particular locale or Unicode encoding. ATL CString classes do not provide conversion for this in most cases, that’s where these two extension classes come in handy:

CStringWExt – Convert 8-bit Character Sets to UTF-16

class CStringWExt : public CStringW
    {
    public:
        BOOL Latin12Wide  ( PSTR s ) { return CP2Wide( 28591    , s ); } // Latin1 encoding or ISO/IEC 8859-1, similar to Windows-1252 
        BOOL OEM2Wide     ( PSTR s ) { return CP2Wide( CP_OEMCP , s ); } // Use for console related text
        BOOL ASCII2Wide   ( PSTR s ) { return CP2Wide( 20127    , s ); }
        BOOL UTF72Wide    ( PSTR s ) { return CP2Wide( CP_UTF7  , s ); }
        BOOL UTF82Wide    ( PSTR s ) { return CP2Wide( CP_UTF8  , s ); }
        BOOL ANSI2Wide    ( PSTR s ) { return CP2Wide( CP_ACP   , s ); }
        BOOL UserCP2Wide  ( PSTR s ) { return CP2Wide( GetUserCodePage()  , s ); }
        BOOL SystemCP2Wide( PSTR s ) { return CP2Wide( GetSystemCodePage(), s ); } // System code page is the locale set for non Unicode programs
        UINT GetUserCodePage() { return GetCodePage( LOCALE_USER_DEFAULT ); }
        UINT GetSystemCodePage() { return GetCodePage( LOCALE_SYSTEM_DEFAULT ); }
        UINT GetCodePage( LCID locale )
        {
            UINT langCP;
            if ( GetLocaleInfo( locale, LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, (LPTSTR)&langCP, sizeof(langCP) ) )
                return langCP;
            return 0;
        }
        BOOL CP2Wide( UINT cp, PCSTR s )
        {
            if ( s == NULL )
                return FALSE;
            int iBuffer = MultiByteToWideChar( cp, 0, s, -1, NULL, 0 );
            if ( iBuffer == 0 )
                return FALSE;
            Preallocate( iBuffer );
            if ( !MultiByteToWideChar( cp, 0, s, -1, GetBuffer() , GetAllocLength() ) )
                return FALSE;
            ReleaseBuffer();
            return TRUE;
        }
};

CStringAExt – Convert UTF-16 to 8-bit Character Set

This conversion with a target of OEM, ASCII and ANSI CP is potentially lossy, depeding on the text that has to be converted. To check if any loss has occurred, use an instance of CStringWExt above.

class CStringAExt : public CStringA
    {
    public:
        BOOL Wide2Latin1  ( PWSTR s ) { return Wide2CP( 28591    , s ); } // Latin1 encoding or ISO/IEC 8859-1, similar to Windows-1252 
        BOOL Wide2OEM     ( PWSTR s ) { return Wide2CP( CP_OEMCP , s ); } // Use for console related text
        BOOL Wide2ASCII   ( PWSTR s ) { return Wide2CP( 20127    , s ); }
        BOOL Wide2UTF7    ( PWSTR s ) { return Wide2CP( CP_UTF7  , s ); }
        BOOL Wide2UTF8    ( PWSTR s ) { return Wide2CP( CP_UTF8  , s ); }
        BOOL Wide2ANSI    ( PWSTR s ) { return Wide2CP( CP_ACP   , s ); }
        BOOL Wide2UserCP  ( PWSTR s ) { return Wide2CP( GetUserCodePage()  , s ); }
        BOOL Wide2SystemCP( PWSTR s ) { return Wide2CP( GetSystemCodePage(), s ); } // System code page is the locale set for non Unicode programs
        UINT GetUserCodePage() { return GetCodePage( LOCALE_USER_DEFAULT ); }
        UINT GetSystemCodePage() { return GetCodePage( LOCALE_SYSTEM_DEFAULT ); }
        UINT GetCodePage( LCID locale )
        {
            UINT langCP;
            if ( GetLocaleInfo( locale, LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, (LPTSTR)&langCP, sizeof(langCP) ) )
                return langCP;
            return 0;
        }
        BOOL Wide2CP( UINT cp, PCWSTR s )
        {
            if ( s == NULL )
                return FALSE;
            int iBuffer = WideCharToMultiByte( cp, 0, s, -1, NULL, 0, NULL, NULL );
            if ( iBuffer == 0 )
                return FALSE;
            Preallocate( iBuffer );
            if ( !WideCharToMultiByte( cp, 0, s, -1, GetBuffer() , GetAllocLength(), NULL, NULL ) )
                return FALSE;
            ReleaseBuffer();
            return TRUE;
        }
};

How to sort CAtlArray using qsort

December 8th, 2008 Christian Etter No comments

Unfortunately, ATL does not come with a built-in sorting algorithm. So the choices you have are: a) roll your own sort function or b) build your app with stdlib support and use the super easy qsort funtion:

CAtlArray<MyFile> dynamic_array;
//...
qsort( dynamic_array.GetData(), dynamic_array.GetCount(), sizeof( MyFile ), (int(*)(const void*, const void*))MyFileSorter );
//...
int __cdecl MyFileSorter( MyFile *p1, MyFile *p2 )
{
    if ( p1->x == p2->x )
        return 0;
    else
        return p1->x > p2->x ? 1 : -1;
}

In case your sorting callback’s signature is identical to int __cdecl ( const void*, const void* ), there is no need to cast the last parameter to the qsort function.
There is one important thing to note: the callback should only return -1, 0, and 1. So instead of doing a simple subtraction of the values you want to compare, you should add a boolean comparison which only returns one of the three values.

How to recursively retrieve all files in a directory tree

February 2nd, 2008 Christian Etter No comments

If you need to process all files or folders in an entire subtree, the following Win32/ATL code does the job. The following function recursively calls itself for all contained subfolders and adds the files found to a CAtlArray container. Obviously all this could also be done in pure C, yet since there are a few string concatenations involved, the use of ATL CString and a dynamically growing array will save a lot of additional work.

GetAllFilesRecursive is called with the path of the base folder where to start enumerating. The second argument is a pointer to a dynamically growing array. Why are we using CString instead of simple PTSTR pointers? That way we do not need to care about memory allocation and deallocation of the file names. Upon destruction of the CAtlArray class, all contained CStrings will be properly deallocated.

void GetAllFilesRecursive( PCTSTR sPath, CAtlArray<CString>* asFiles )
{
    WIN32_FIND_DATA FindFileData;
    CString s( sPath );
    s.Append( _T("\\*") );
 
    HANDLE hFind = FindFirstFile( s, &FindFileData );
    if ( hFind == INVALID_HANDLE_VALUE ) 
        return;
    else 
    {
        do 
        {
            if ( ( FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) )
            {
                if ( lstrcmp( _T("."), FindFileData.cFileName ) && lstrcmp( _T(".."), FindFileData.cFileName ) )
                {
                    s = sPath;
                    s.Append( _T("\\") );
                    s.Append( FindFileData.cFileName );
                    GetAllFilesRecursive( s, asFiles );
                }
            }
            else // file
            {
                s = sPath;
                s.Append( _T("\\") );
                s.Append( FindFileData.cFileName );
                asFiles->Add( s );
            }
        } while ( FindNextFile( hFind, &FindFileData) != 0 );
        FindClose( hFind );
    }
    return;
}

When we are dealing with directories, we have to filter out the ‘.’ and ‘..’ links which point to the current and parent directory respectively.