Click here to Skip to main content
13,054,779 members (67,489 online)
Click here to Skip to main content
Add your own
alternative version


99 bookmarked
Posted 21 Apr 2002

What's new in ATL7

, 1 May 2002
Rate this:
Please Sign up or sign in to vote.
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.

Memory Management



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: <pre lang=c++>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 }


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

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

- from ANSI to UNICODE
- 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:

<!------------------------------- That's it! ---------------------------> <pre lang=c++>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


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 > >


// 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)


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.


// use CStringElementTraits to have a valid comparison for Find 
CAtlArray<CString, CStringElementTraits<CString> > array; 

// other traits are CStringRefElementTraits, CStringElementTraitsI
CAtlList<CString, CStringElementTraits<CString> > list;   

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


CAtlMap<CString, int, CStringElementTraits<CString> > map;
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;

Various other more specialized classes:

CAutoPtrArray/CAutoPtrList /CComUnkArray /CHeapPtrList /CInterfaceArray /CInterfaceList

"Collection Classes" (MSDN)



Quick example:

<pre lang=c++>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:

<pre lang=c++>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(); <pre lang=c++> IDoSomeWork* pWork1=new Work1(); pool.QueueRequest(pWork1); <pre lang=c++> IDoSomeWork* pWork2=new Work2(); pool.QueueRequest(pWork2); <pre lang=c++> Sleep(5000); delete pWork1; delete pWork2; }

Memory Management

CHeapPtr<CComAllocator | CCRTAllocator>:

CHeapPtr<int, CComAllocator> ptr;

// 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[]


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)


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;
filemap.MapFile(file, 1024, 0, PAGE_READWRITE, FILE_MAP_READ|FILE_MAP_WRITE);
char* pMem = filemap;
strcpy(pMem, "hello");

"File Handling Classes"(MSDN)


ATL7 includes wrappers for win32API security.

Quick Example:

<pre lang=c++> 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)


#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.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Leon Finker
United States United States
No Biography provided

You may also be interested in...


Comments and Discussions

GeneralRe: MMC SnapIn Pin
Slava Vassiliev5-May-02 20:35
memberSlava Vassiliev5-May-02 20:35 
GeneralRe: MMC SnapIn Pin
Alois Kraus30-Sep-02 1:16
memberAlois Kraus30-Sep-02 1:16 
GeneralRe: MMC SnapIn Pin
Leon Finker30-Sep-02 4:30
memberLeon Finker30-Sep-02 4:30 
GeneralString Conversion Pin
Blake Watts29-Apr-02 12:58
memberBlake Watts29-Apr-02 12:58 
GeneralRe: String Conversion Pin
Leon Finker30-Apr-02 5:46
memberLeon Finker30-Apr-02 5:46 
GeneralCComModule Init/Term Pin
okigan23-Apr-02 14:27
memberokigan23-Apr-02 14:27 
GeneralRe: CComModule Init/Term Pin
Leon Finker23-Apr-02 15:05
memberLeon Finker23-Apr-02 15:05 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170713.1 | Last Updated 2 May 2002
Article Copyright 2002 by Leon Finker
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid