Wizard-Generated Build Configurations

[Previous] [Next]

As with the other AppWizards, the ATL COM AppWizard creates a project file that contains several build configurations, each tuned to a different set of goals and needs. The nuances of the ATL preprocessor symbols defined by the various ATL build configurations are quite possibly the most misunderstood aspect of ATL. Table 4-2 summarizes the build configurations we'll be covering in this section.

Table 4-2. Wizard-Generated Build Configurations.

Build Configuration Description Preprocessor Symbols Dependencies
Win32 Debug Used exclusively for testing and debugging. Compiler optimizations are disabled, and the linker generates debug information. _DEBUG Implicit link to CoCreateInstance of Registrar component
Win32 Release MinSize Aims to generate the smallest possible component footprint. Compiler optimizations are set to Minimum Size. NDEBUG
Explicit link to ATL.DLL
Win32 Release MinDependency Aims to reduce dependencies on other modules. Compiler optimizations are set to Minimum Size. NDEBUG
All configurations Links to static version of run-time library. C++ exception handling and Run Time Type Information (RTTI) are disabled. Exception handling must be enabled to use the Standard Template Library (STL). N/A N/A
Unicode configurations Links to Unicode versions of all Win32 APIs and treats TCHAR as wchar_t. For use only with components running exclusively under Windows NT and Windows 2000. _UNICODE Windows NT


Visual C++ lets you decide how to link the C run-time functions into your application, whether statically, dynamically, or not at all. Static linking means that the run-time code will be linked directly into your application. Dynamic linking means that your application will contain only references to the run-time functions. The implementation of those functions will reside in a DLL (MSVCRT.DLL) that your application links to at run time. For your application to run, that DLL must be present. Even when dynamically linking to the run-time DLL, some run-time functions require the existence of statically linked startup code. If you use those functions, the link to the C run-time library—whether static or dynamic—causes the linker to add startup code to your application, significantly increasing its size. This startup code, provided by the run-time library, calls constructors on global objects and initializes data structures used by the run-time library. Not all the run-time functions require the startup code—memcpy and strlen are typical examples—but many of them do. The following functions require statically linked startup code:

  • String comparison routines
  • Memory allocation routines
  • Global objects with constructors
  • C++ exception handling

The startup code adds only about 25 KB to your application footprint. This amount is negligible in traditional stand-alone applications built with MFC or Visual Basic. But when you're trying to create lean, mean COM servers (that is why you're using ATL, right?), 25 KB is a big, big deal.

Because the goal of ATL is to develop components that are as small as possible, ATL provides alternate implementations for several of the commonly used run-time functions that would otherwise require costly startup code. The _ATL_MIN_CRT preprocessor symbol controls the use of the ATL versions of these run-time functions. The _ATL_MIN_CRT symbol doesn't prevent you from using C run-time functions in your application. It simply tells the linker not to include the run-time library-provided startup code. Thus, if _ATL_MIN_CRT is defined and you attempt to use a function that requires the run-time startup code but doesn't have an ATL replacement, you'll get a link error stating that the _main function is unresolved. The error message makes sense: you've attempted to link to a function that requires startup code, but you've told the linker not to provide the startup code. The most effective approach is to define _ATL_MIN_CRT and then go about your merry business until you use a run-time function that produces the infamous _main link error. At that point, you can simply remove the _ATL_MIN_CRT preprocessor symbol and pay the associated code-size penalty. You can't define ATL_MIN_CRT if you want to use C++ exception handling or the Standard Template Library (STL), because both require the run-time startup code.


Like the C run-time library, ATL provides functionality that resides in a shared-code DLL—aptly if unimaginatively named ATL.DLL. (In early versions of ATL, the shared-code DLL was named REGISTER.DLL, a name that was neither apt nor imaginative.) This file contains basically two things: global functions used by various ATL classes and templates, and the Registrar component, which we'll explain in detail in Chapter 7. Like the C run-time library, ATL is structured such that the code contained in the shared DLL can be linked to your component statically or dynamically. The method of linking to the ATL shared code depends on the absence or existence of two preprocessor symbols, _ATL_DLL and _ATL_STATIC_REGISTRY. The usage of these two symbols determines whether the ATL.DLL must be redistributed and registered along with the component. Table 4-3 explains the linkage implications of the _ATL_DLL and _ATL_STATIC_REGISTRY symbols. As you can see from the table, the only combination of these two symbols that doesn't create a run-time dependency on ATL.DLL is to define _ATL_STATIC_REGISTRY and not define _ATL_DLL.

Table 4-3. Preprocessor Symbols That Control Linkage to ATL.DLL.

Preprocessor Symbol Explanation
_ATL_DLL The existence of this symbol indicates that ATL will dynamically link to its global functions (as exported by ATL.DLL) rather than statically linking them directly into the module.
_ATL_STATIC_REGISTRY The existence of this symbol indicates that ATL will not use CoCreateInstance to instantiate the Registrar component housed in ATL.DLL. Rather, ATL will statically link that functionality directly into the module.

The process of installing and registering the ATL shared-code DLL is complicated by the fact that there are two different versions of ATL.DLL—one for Microsoft Windows 95 and Windows 98 (ANSI) and one for Windows NT and Windows 2000 (Unicode). If your application targets both operating systems, your setup program must include both versions of the DLL and take special precautions to ensure that the proper DLL is installed and registered, depending on the operating system that resides on the target machine.

ATL.DLL should reside in the windows\system32 folder. If that file already exists on the target machine, you should perform a version comparison before copying the file to make sure that the version of ATL.DLL that you're installing is newer than the one that already exists. After copying the file, you must register it using REGSVR32.EXE or by loading the DLL and calling its exported DLLRegisterServer function.

Previous Versions of ATL: ATL.DLL

On the Visual C++ 5.0 installation CD, the Unicode and ANSI versions of ATL.DLL reside in the \devstudio\vc\redist and \devstudio \vc\redist\ansi folders, respectively. On the Visual C++ 6.0 CD, these two files reside in the \os\system and \os\system\ansi folders, respectively. The version of ATL.DLL that ships with Visual C++ 6.0 is backward compatible to ATL projects developed with Visual C++ 5.0.

Win32 Debug

The Win32 Debug build configuration is used exclusively for testing and debugging. Generally, you shouldn't redistribute components built with the Debug configuration. Compiler optimizations are turned off, and the linker uses the static, debug version of the multithreaded run-time library. Because the Debug configuration doesn't define the _ATL_STATIC_REGISTRY symbol, it is dependent on the Registrar component that resides in ATL.DLL.

Win32 Release MinSize

The Win32 Release MinSize build configuration attempts to create the smallest COM server possible. It does this by defining _ATL_DLL, which causes the project to link dynamically to ATL.DLL, and _ATL_MIN_CRT. Because most developers aren't in the habit of building the release versions of their components until far along in the development cycle, they typically suffer from the _main link error described earlier when they first attempt to compile the Release MinSize (and Release MinDependency) build. If you're faced with that situation, you have two options: you can remove the _ATL_MIN_CRT definition from the configuration, or you can replace all references to the C run-time functions that require run-time startup code with Win32 API equivalents (if available). The former is a much simpler process, but the latter is a worthwhile exercise, especially when you're trying to develop the smallest component possible.

Interestingly, the MinSize configuration links to the static rather than the dynamic version of the C run-time DLL. For components that make liberal use of the C run-time library, a reduction in footprint might be gained by instead linking to the run-time library dynamically. (See Figure 4-6.)

click to view at full size.

Figure 4-6. Visual C++ allows you to specify whether to link to the C run-time library statically or dynamically.

Win32 Release MinDependency

The Win32 MinDependency build takes the opposite tack of the MinSize configuration. It favors lack of dependency over reduced footprint. For developers who are willing to pay a small code-size price for the luxury of not having to redistribute the ATL.DLL or MSVCRT.DLL files, the MinDependency build is the best choice. This configuration defines _ATL_STATIC_REGISTRY and _ATL_MIN_CRT, and it links to the static version of the C run-time library.

All Configurations

All the ATL COM AppWizard_generated build configurations share common characteristics. Notably, they don't enable C++ exception handling or Run Time Type Information (RTTI). Having no C++ exception handling or RTTI is an acceptable default setting because it encourages the use of the two COM practices that differ from the traditional C++ usage model. First, although it's acceptable to throw exceptions within the body of an interface method, it violates the rules of COM to throw an exception that crosses a component boundary. To pass errors from one component to another, COM instead uses HRESULTs and the ISupportErrorInfo and IErrorInfo interfaces. Second, when dealing with interface pointers, you must use QueryInterface rather than dynamic_cast to convert from one pointer type to another. The reason is that it's perfectly legal for a COM object to use composition rather than inheritance as its means of supporting multiple interfaces.

Because exception handling and RTTI are used less frequently in lightweight COM objects than in traditional stand-alone C++ applications, and because these options can increase footprint size and memory usage, they are disabled in all the wizard-generated configurations. If you want to use the dynamic_cast, type_id, or type_info operators, you must enable RTTI. If you want to use the STL in your ATL project, you must manually enable exception handling for all configurations, but you should take precautions to ensure that exceptions thrown by the STL don't cross the boundaries of your interface's methods. The following code is taken from a COM collection object:

 class CAnimals :     public CComObjectRootEx<CComSingleThreadModel>,     public CComCoClass<CAnimals, &CLSID_Animals>,     public ISupportErrorInfoImpl< &IID_IAnimals >,     public IDispatchImpl<IAnimals, &IID_IAnimals, &LIBID_ANIMALSERVERLib> {          std::vector<IAnimal*> m_itemList;     STDMETHOD(Item)(VARIANT index, IDispatch** ppItem)     {         // Oops! An out-of-range index throws an exception!         return m_itemList.at(index)->QueryInterface(             IID_IDispatch, (void**)ppItem);     }      }; 

In the preceding code, the STL vector class throws an out_of_range exception if an invalid index is passed into the vector::at method. Under the rules of traditional C++, it might have been acceptable to let the exception percolate up the call stack, but under the COM model it isn't. Visual Basic clients, for which collection classes were invented, don't know how to handle C++ exceptions, so the Animals collection is doomed to failure unless one of two things happens:

In case you're wondering, the CComCoClass::Error method used in the code snippets shown above sets up the IErrorInfo interface to provide error information to the client.

All the wizard-generated configurations link statically to the C run-time library. As described earlier, you can both define _ATL_MIN_CRT and link statically to the run-time library: the settings aren't mutually exclusive. The combination of these settings simply means that C run-time functions not provided by ATL will be linked statically and must not require startup code.

Unicode Configurations

The wizard-generated project includes Unicode versions of the three basic build configurations described earlier: Debug, Release MinSize, and Release MinDependency. The Unicode configurations are for use only with components that will run exclusively under Windows NT and Windows 2000 because Unicode isn't supported under Windows 95 or Windows 98. Under Windows NT and Windows 2000, the system DLLs export two versions of many of the Win32 APIs—one version for single-byte characters and another for double-byte Unicode characters. Whereas the non-Unicode configurations define the _MBCS preprocessor symbol, the three Unicode build configurations define the _UNICODE preprocessor directive, which causes an application to link to the wide versions of the Win32 APIs. Here's the pseudocode for the MessageBox function:

 WINUSERAPI int WINAPI MessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType); WINUSERAPI int WINAPI MessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType); #ifdef _UNICODE #define MessageBox  MessageBoxW #else #define MessageBox  MessageBoxA #endif // !UNICODE 

Most often, you'll simply use the generic MessageBox function in your code, but it's translated to the appropriate exported system function based on the presence or absence of the _UNICODE directive.

Inside Atl
Inside ATL (Programming Languages/C)
ISBN: 1572318589
EAN: 2147483647
Year: 1998
Pages: 127
Authors: Steve Zimmerman, George Shephard, George Shepherd

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net