Robert Coleridge
MSDN Content Development Group
Compiler Support for COM
With the release of Microsoft® Visual C++® 5.0, Component Object Model (COM) programming just got easier. The compiler now has built-in support for many COM features. A few of the new COM features are discussed below.
#import Keyword
Imagine being able to invoke methods on a third-party COM object as easily as you would any class you wrote yourself! This is the power that the #import keyword gives you. By specifying the name of a COM object, whether a DLL, .exe, or typelib, the compiler generates a header file and source for inline functions for accessing the COM object directly. The code generated is based on _com_ptr_t and throws _com_error exceptions even if the actual DLL or .exe does not. The days of wading through a type library just to write the interface signature declarations are over!
New COM Classes
Along with some other fancy enhancements to the compiler come four new classes and templates that either enhance the #import keyword or simply make COM programming easier.
_com_ptr_t
The _com_ptr_t class is a very powerful wrapper template for smart interface pointers. If you've done COM programming in the past, then you know how important it is to keep reference counts straight. Keeping reference counts straight is one of the most tedious problems to debug in COM. You no longer have this headache when you use _com_ptr_t. This simple template greatly simplifies all of the reference counting work for you. AddRef and Release are handled safely behind the scenes.
_com_error
There is now a standard package to use when throwing COM exceptions: the _com_error package. This class encapsulates any HRESULT coming back from a COM function and any associated IErrorInfo. The _com_error package provides several COM methods for extracting requested information, such as the HRESULT, a text description of the error, and the fields from the IErrorInfo structure.
_variant_t and _bstr_t
The COM specification defines the various data types that are standard to COM programming. If you need to pass a string, use a BSTR data type, and if you need to pass objects or unknown data use a VARIANT. Although these types are fundamental to COM programming, there has not been much support for them until now. These two data types are now easier to use with the new release of Visual C++, which uses the C++ classes _variant_t and _bstr_t.
New Keywords
bool/true/false
With the introduction of an integral Boolean data type (bool), the application size and, potentially, the size of your data get smaller. Boolean data types of the older type, BOOL, were defined as an unsigned short. BOOL was either 2- or 4-bytes long! What this meant was that any stored data records containing BOOLs took up extra space with leading zeros. If you did not write special code to trim the size of this data type that was stored out to disk, your data files suffered from excessive empty space. Now with the bool data type this empty space is minimized since a bool is only 1-byte long. With the introduction of the bool data type come its associated values: true and false. Note that these values are not the old values of TRUE and FALSE; however, at the present time they equate to the same value.
mutable
The new storage class specifier, mutable, allows you to declare class member data as "modifiable even in a const object." This allows you to distinguish between "abstract const" (const to the user) and "concrete const" (const to the implementation).
class Object { public: void x(); void y() const; private: int m1; mutable int m2; }; void Object::x() // Can always modify object. { m1 = 0; m2 = 1; } void Object::y() const // Object is const. { // cannot modify m1 m2 = 2; // Can modify m2 because it is mutable. }
MFC and the WinINet API
With this release of Visual C++, the Microsoft Foundation Class (MFC) library encapsulates the WinINet application programming interface (API). What used to take a significant amount of coding and testing time now takes only a few minutes. In addition, you can reduce the number of WinINet API function calls to a single class invocation. There are currently a total of 13 new WinINet API classes in the MFC. Programming for the Web has never been easier.
ATL 2.1 Compiler Optimization
Be aware that ActiveX™ Template Library (ATL) 2.1 has been optimized for the Visual C++ 5.0 compiler. In particular, you should be aware that many ATL classes are declared with the ATL_NO_VTABLE macro. This has the effect of creating objects without vtables. For further information see the article in the ATL documentation titled "Compiler Optimizations." Note that with this new release of ATL there are 39 new classes that facilitate control creation, seven renamed classes, and seven classes that have been dropped entirely.
Tips and Tricks
The New bool Data Type: When to Use It
The introduction of internal support for Boolean data types in the newest release of Visual C++ prompts an interesting question: When should we use it? This arises from the discrepancy in size between the older BOOL type, which is 4 bytes long, and the new bool type, which is 1 byte long. If BOOL data has been stored to disk, then you need to retrieve it as a BOOL or convert the data. If BOOL data is being passed via pointer to another application or DLL, then receive the data as a BOOL.
If the new application has no interaction with older BOOLs, then use the new bool type, since it is now integral to the compiler and can be optimized for.
When is True Not True? When Doing Inter-Language Programming
The difficulty here lies in inter-language support. In both Visual C++ and Visual Basic® the value for false is zero, but the value for true is not the same in both languages! Visual C++ uses a positive one (1) and Visual Basic uses a negative one (–1)!
dim bResult as Boolean // This code will NOT work since Visual C++ and Visual Basic have differing // 'true' values. bResult = Foo.Bar(); if bResult = True then DoSomeThing();
dim bResult as Boolean // This code WILL work since both know that true does not equal 0. bResult = Foo.Bar(); if bResult then DoSomeThing();
By making this small change in coding you can ensure that any code you write that deals with Boolean conditionals will have interlanguage operability.
How to Make True = True
Under Visual C++ version 4.2 and earlier, the data type BOOL was used to define Boolean data types and return codes. If an application that uses this data type is recompiled under Visual C++ 5.0, it will still function as expected but you may receive a warning that you did not receive before. You will definitely get this warning if you begin to mix and match the older BOOL with the newer built-in bool data type. The compiler is simply warning you that the optimization techniques it has for bool data types cannot be used, since the two data types are internally different.
#pragma warning (disable : 4800) // Turns off bool warning.
You should only disable the warning as a temporary solution, however. It would be better to change your BOOLs to bool, or not to mix and match the two.
How to Use a Structure to Execute Code Before and After Your Main Code
When using smart interface pointers from a template, it is often necessary to have certain code execute before and after the main program executes. For example, let's assume that you needed to have OLE initialized before your program started and have OLE uninitialize after your program is finished. The technique below demonstrates how to do this.
struct OleInit { OleInit() { OleInitialize(NULL); } ~OleInit() { OleUninitialize(); } } Init_Ole;
Place the above code segment in your code outside of any function, for example above your main routine. Since this code is outside of any function, the constructor gets called prior to the main routine. Calling the constructor, in effect, calls the OleInitialize routine. At the end of the program's life the destructor is called, thus calling the OleUninitialize routine. This technique could be applied to any code that must be started prior to the main routine starting and any code that must run after the program is finished.