Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

What's new in ATL7

0.00/5 (No votes)
1 May 2002 1  
Overview of new classes in ATL7

This article doesn't cover new ATL7 Server Classes and Attributes. This is not a complete list - only what I have found so far.

Strings
Collections
Threading
Memory Management
Files
Security
Miscellaneous

Strings

ATL3: 

String conversion macros had a few limitations. It was allocating memory from stack, with potential to overflow the stack with large strings. The string was freed when the function exited and not at any introduced scope inside the function. It was using outdated OLE2ANSI define. And if you look at the remarks for _alloca (which was used for the conversions) on MSDN, it says that it has limitations when used inside SEH or C++ EH. 

For example look at the ATL3 String Conversion Macros:

USES_CONVERSION;
try
{
      for(int i=0; i< 100000; ++i)
          LPTSTR str = OLE2T(L"Some string string string string string........");  
			// stack overflow, memory on the stack grows...


      throw int(1); // if above doesn't fail, then make sure catch(int) is executed 

}
catch(int)
{
      LPTSTR str = OLE2T(L"Some string string string string string........"); 
		// _alloca can't be used in SEH or C++ EH

                    // Generates Unhandled Exception

                    // Will be marked as error in VS.NET during compile

}

ATL7: 

String Conversion macros/classes improve in those areas mentioned above. It uses stack memory for small strings and heap for large strings so there is no stack overflow when stack space is not enough. The string is freed when it's scope ends and not when function exits. Can be used in exception handlers. Can be used in loops (since it can be controlled by scope).

The macro names are easy to read. The form is as before: SourceType2[C]DestinationType
From:

A-ANSI/W-Unicode/T-generic To [Constant] A-ANSI/W-Unicode/T-generic.

CA2T/CA2CT - from ANSI to generic string based on _UNICODE define
CT2A/CT2CA - from T generic string to ANSI string based on _UNICODE define
CT2W/CT2CW - from T generic string to UNICODE string
CW2T/CW2CT - from UNICODE to generic string based on _UNICODE define
CT2WEX/CT2CWEX - from T generic to UNICODE string and buffer can be specified
CW2TEX/CW2CTEX - from UNICODE to T generic string and buffer can be specified

CA2W - from ANSI to UNICODE
CW2A - from UNICODE to ANSI
CW2AEX/CA2WEX - the actual class that some of the above typedef/macros use

So above code would look like this and without crash:

try
{
     for(int i=0; i< 100000; ++i)
         CW2A str(L"Some string string string string string........");
     throw int(1);
}
catch(int)
{
      CW2A str(L"Some string string string string string........");
}

Be aware of one caveat. All of the above macros can't be used in same code construct as in ATL3:

LPTSTR str = CW2A(L"some string"); 

The above code is wrong. After that line the temporary object created by CW2AEX is destroyed.
Just be aware that the macros represent C++ classes and are controlled by scope rules.
To see the problem try this:

// use size 2 for initial string length to make sure stack size 

// is not enough and heap is used for memory

LPCTSTR szr = CW2AEX<2>(L"some string"); 

szr; // at this line szr should point to garbage

CString:

Another Addition is the CStringT class for manipulating strings. Even though this class exposes the same methods as previous MFC CString. It's not the old MFC CString. This class is templated. It has few typedefs to work with char, wchar_t, and TCHAR. CString is a typedef:

CStringT< TCHAR, StrTraitATL< TCHAR > > CAtlString;

which is redefined based on MFC being used or not to:

// #ifdef _AFX

typedef CAtlString CString;

The CStringT itself is shared between MFC/ATL. By default it uses CRT, but that can be changed by defining either _ATL_MIN_CRT or _ATL_CSTRING_NO_CRT. Which in turn makes the appropriate typedef visible to the compiler, for example either:

// use CRT and have more functionality

CStringT< TCHAR, StrTraitATL< TCHAR, ChTraitsCRT< TCHAR > >

or

// don't use CRT, but use win32API string functions, (wvsprintf, lstrlen, CharNext, etc)

CStringT< TCHAR, StrTraitATL< TCHAR >, ChTraitsOS<TCHAR> > 

Another class CFixedStringT provides fixed pre-allocated contiguous buffer for optimized memory management.

The memory management for either one can be customized through implementation of IAtlStringMgr and that implementation already exists CAtlStringMgr. Its ctor takes a pointer to IAtlMemMgr, which can be any of predefined implementations or your own: 

CCRTHeap - use CRT heap
CWin32Heap - use win32 heap
CComHeap - use COM Task memory allocator

etc. So for example:

CComHeap comHeap;
CAtlStringMgr mg(&comHeap);
CString str(&mg);
str += "some string";

and we get ::CoTaskMemAlloc being used for memory allocation.

"String and Text Classes"(MSDN)

"ATL/MFC String Conversion Macros"(MSDN)

Collections

ATL7 introduces new collection classes. The classes have similar interface as previous MFC collection classes. These are templated classes
and we can pass our own CElementTraits for handling specialized cases, such as CopyElements, RelocateElements, CompareElements, and Hash.

CAtlArray/CAtlList:

// use CStringElementTraits to have a valid comparison for Find 

CAtlArray<CString, CStringElementTraits<CString> > array; 

// other traits are CStringRefElementTraits, CStringElementTraitsI

CAtlList<CString, CStringElementTraits<CString> > list;   

list.AddHead(CString("hello"));
list.AddHead(CString("string"));
POSITION pos = list.Find("hello");
if(pos != NULL)
{
    CString str = list.GetAt(pos); 
}

CAtlMap

CAtlMap<CString, int, CStringElementTraits<CString> > map;
map.InitHashTable(269);
map["key1"] = 2;
map["key2"] = 2;
int value;
if(map.Lookup("key1", value));

CRBTree/CRBMap /CRBMultiMap - Red-Black tree based implementation

CRBMap<int, int> rbMap;
rbMap.SetAt(10, 20);
rbMap.SetAt(30, 40);
CRBMap<int, int>::CPair* p = rbMap.Lookup(30);
//p->m_key; p->m_value;

rbMap.RemoveKey(30);

Various other more specialized classes:

CAutoPtrArray/CAutoPtrList /CComUnkArray /CHeapPtrList /CInterfaceArray /CInterfaceList

"Collection Classes" (MSDN)

Threading

CWorkerThread<Win32ThreadTraits|CRTThreadTraits>:

Quick example:

class WorkerClass : public IWorkerThreadClient
{
    HANDLE m_hEvent;
    CWorkerThread<Win32ThreadTraits> m_thread;
public:
WorkerClass()
    {
        m_thread.Initialize();
        m_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
        m_thread.AddHandle(m_hEvent, this, NULL);
    }
    ~WorkerClass()
    {
        m_thread.RemoveHandle(m_hEvent);
        m_thread.Shutdown();
    }
    void ResumeThread()
    {
        ::SetEvent(m_hEvent);
    }
    void FreezeThread()
    {
        ::ResetEvent(m_hEvent);
    }
private:
 // IWorkerThreadClient

    HRESULT Execute(DWORD_PTR dwParam, HANDLE hObject)
    {
        FreezeThread();
        return S_OK;
    }
    HRESULT CloseHandle(HANDLE hHandle)
    {
        ::CloseHandle(hHandle);
        return S_OK;
    }
};

Then:
{
    WorkerClass work;
    work.ResumeThread();
    Sleep(5000);
    work.ResumeThread();
    Sleep(5000);
}

And here is imagined usage of CThreadPool:

struct IDoSomeWork
{
    virtual void Work()=0;
};

class Work1 : public IDoSomeWork
{
    void Work(){}
};
class Work2 : public IDoSomeWork
{
    void Work(){}
};
class ThreadPoolWorker
{
    public:
// support for CThreadPool Worker Archetype

    typedef IDoSomeWork* RequestType;
    BOOL Initialize(void* pvWorkerParam)
    {
        return TRUE;
    }
    void Execute(RequestType request, void* pvWorkerParam,OVERLAPPED* pOverlapped)
    {
        request->Work();
    }
    void Terminate(void* pvWorkerParam)
    {
    }
};

{
    CThreadPool<ThreadPoolWorker> pool;
    pool.Initialize();
    IDoSomeWork* pWork1=new Work1();
    pool.QueueRequest(pWork1);
    IDoSomeWork* pWork2=new Work2();
    pool.QueueRequest(pWork2);
    Sleep(5000);
    delete pWork1; delete pWork2;
}

Memory Management

CHeapPtr<CComAllocator | CCRTAllocator>:

CHeapPtr<int, CComAllocator> ptr;
ptr.Allocate(100);

// this class is not for arrays of objects, because it doesn't call delete[],

// but only delete.

CAutoPtr<CString> ptr(new CString("string"));  

CAutoVectorPtr<CString> pVec(new CString[100]); // this calls delete[]

CComGITPtr: 

Manages the pointer in GIT table. Creates the GIT and calls the IGlobalInterfaceTable methods for you.

Other more specialized classes include:

  • CAutoPtrArray
  • CAutoPtrList
  • CComHeap
  • CComHeapPtr
  • CComPtrBase
  • CCRTAllocator
  • CCRTHeap
  • CGlobalHeap
  • CHandle
  • CHeapPtrBase
  • CHeapPtrList
  • CLocalHeap
  • CWin32Heap

Memory Management Classes(MSDN)

Files

CAtlFile is a thin wrapper around the win32API for files. CreateFile, ReadFile, WriteFile, etc
CAtlTemporaryFile can be used for temporary files. They are automatically named, opened, closed, and deleted.
CAtlFileMappingBase/CAtlFileMapping can be used for mapped files:

CAtlTemporaryFile file;
CAtlFileMapping<char> filemap;
file.Create(NULL, GENERIC_READ|GENERIC_WRITE);
file.SetSize(1024);
filemap.MapFile(file, 1024, 0, PAGE_READWRITE, FILE_MAP_READ|FILE_MAP_WRITE);
char* pMem = filemap;
strcpy(pMem, "hello");

"File Handling Classes"(MSDN)

Security

ATL7 includes wrappers for win32API security.

Quick Example:

    CSid sidDenied;
    sidDenied.LoadAccount("Leo");
    CDacl dacl;
    // try either deny or allow and see how OpenEvent later on behaves

    dacl.AddDeniedAce(sidDenied, GENERIC_ALL);
    // dacl.AddAllowedAce(sidDenied, GENERIC_ALL);

    CSecurityDesc desc;
    desc.SetDacl(dacl);
    
    CSecurityAttributes secattr(desc);
    // limit the access rights to the named event

    CHandle hEvent(CreateEvent(&secattr, FALSE, FALSE, "NamedEvent"));

    // try open it with all access rights

    CHandle hEventOpen(OpenEvent(EVENT_ALL_ACCESS, FALSE, "NamedEvent"));
    // if deny ace was added above it should fail. If allow ace

    // was added, it should succeed

    if(GetLastError() == ERROR_ACCESS_DENIED)
        ATLTRACE("\n\nAccess denied when opening event\n\n");

    
    CSecurityDesc descCheck;
    AtlGetSecurityDescriptor("NamedEvent",SE_KERNEL_OBJECT, &descCheck);
    CDacl daclCheck;    
    descCheck.GetDacl(&daclCheck);
    CSid::CSidArray sidarr;
    daclCheck.GetAclEntries(&sidarr);
    for(UINT i=0; i<sidarr.GetCount(); ++i)
    {
        ATLTRACE("%s\n", (LPCTSTR)sidarr[i].Sid());
        ATLTRACE("%s\n", (LPCTSTR)sidarr[i].AccountName());
        ATLTRACE("%s\n", (LPCTSTR)sidarr[i].Domain());
    }

"Security Classes"(MSDN)

Miscellaneous

#import can now take progid/libid and not just hard coded filename. For example:

#import <libid:20000000C-500A-100B-B005-000000000000> version("2.2")
#import "progid:SomeServer.Blah.1" embedded_idl, no_namespace

CComModule is replaced with other classes, such as: CAtlComModule/CAtlWinModule/CAtlDllModuleT/CAtlExeModuleT/CAtlServiceModuleT/etc
No more need to call Init()/Term() explicitly. The methods are now called by the appropriate ctor/dtor of the module classes.

No more need for BEGIN_OBJECT_MAP/END_OBJECT_MAP. OBJECT_ENTRY_AUTO is used instead. It's placed at global scope
and is auto generated into the ATL object map at link time. It uses linker segments to gather all the globally declared map entries into one list.

CComCurrency - wrapper for CURRENCY type
CAtlException - defines ATL related exception

CImage - depends on GDI+. Can work with jpeg, gif, bmp, png. See "CImage Limitations with Earlier Operating Systems" (MSDN)

_U_STRINGorID/_U_MENUorID/_U_RECT/CPoint/CRect/CSize - various simple wrappers. See "Utility Classes" (MSDN)

Synchronization wrappers defined in atlsync.h: CCriticalSection, CEvent, CMutex, and CSemaphore. But they are not documented in MSDN.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here