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
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........");
throw int(1);
}
catch(int)
{
LPTSTR str = OLE2T(L"Some string string string string string........");
}
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:
LPCTSTR szr = CW2AEX<2>(L"some string");
szr;
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:
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:
CStringT< TCHAR, StrTraitATL< TCHAR, ChTraitsCRT< TCHAR > >
or
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.
CAtlArray/CAtlList:
CAtlArray<CString, CStringElementTraits<CString> > array;
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);
rbMap.RemoveKey(30);
Various other more specialized classes:
CAutoPtrArray/CAutoPtrList /CComUnkArray /CHeapPtrList /CInterfaceArray /CInterfaceList
"Collection
Classes" (MSDN)
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:
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:
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;
}
CHeapPtr<CComAllocator | CCRTAllocator>:
CHeapPtr<int, CComAllocator> ptr;
ptr.Allocate(100);
CAutoPtr<CString> ptr(new CString("string"));
CAutoVectorPtr<CString> pVec(new CString[100]);
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)
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)
ATL7 includes wrappers for win32API security.
Quick Example:
CSid sidDenied;
sidDenied.LoadAccount("Leo");
CDacl dacl;
dacl.AddDeniedAce(sidDenied, GENERIC_ALL);
CSecurityDesc desc;
desc.SetDacl(dacl);
CSecurityAttributes secattr(desc);
CHandle hEvent(CreateEvent(&secattr, FALSE, FALSE, "NamedEvent"));
CHandle hEventOpen(OpenEvent(EVENT_ALL_ACCESS, FALSE, "NamedEvent"));
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.