Best practice
UNICOM Intelligence recommends the following coding techniques and practices.
Compiler and linker settings
CDM uses the following project settings:
▪Warning level 4
▪Run-time type information (RTTI)
▪Exception handling
All other project settings should be left as the Visual C++ defaults.
COM development
All components implement the LibraryVersion interface, which is implemented using the LibraryVersion wizard.
Begin all type library help strings with your company name. For example:
helpstring("ABC Company DSC Registration Type Library")
Prefix registry script component descriptions with your company name. For example:
MRDSCReg.Capability.1 = s 'ABC Company Capability Class'
Register all components as part of the UNICOM Intelligence component category. For example:
ForceRemove 'Implemented Categories'
{
ForceRemove {8F8AD410-9DA2-11d3-9298-00A024AC7946}
}
}
...
NoRemove 'Component Categories'
{
NoRemove {8F8AD410-9DA2-11d3-9298-00A024AC7946}
{
val 400 = s 'SPSS MR Components'
}
}
Multithreading
Use the ObjectLock typedef when creating a critical section. ObjectLock is a typedef of:
CComObjectLockT(CComObjectRootEx<ThreadModel>* p)
This class calls the Lock method on a CComObjectRootEx derived object in its constructor. It calls the Unlock method in its destructor. The Lock and Unlock methods in CComObjectRootEx ultimately call either CComAutoCriticalSection::Lock or CComFakeCriticalSection::Lock depending on the threading model. For single-threaded components, use CComFakeCriticalSection, which does nothing. For multithreaded components, use CComAutoCriticalSection, which uses the WIN32 functions to enter and exit a critical section. This means that by using the ObjectLock typedef, critical sections are not used for single threaded components.
The following example shows how this class should be used:
void CItems::FinalRelease()
{
// Release the command interfaces held in the collection
ObjectLock Lock(this);
CNameCollection<IItem>::CollectionReleaseAll();
}
Test multithreaded components using the COM Stress Tester before releasing them to independent testing. A Visual C++ wizard is available for creating stress test projects. Perform stress tests with multiple free threads calling every method on the interfaces exposed by the component.
Finalizing objects
When finalizing objects in your code, keep the following in mind:
▪It's a good idea to call the Source.Uninitialize method from Source.FinalRelease. This ensures that Source objects get finalized even if there are no other calls to Source.Uninitialize.
▪Make sure that Source.Uninitialize explicitly closes all its commands, and that those commands close their child commands.
▪In general, only top-level commands should be manipulated by the client code. Lower level commands should generally only be manipulated (initialized, uninitialized, closed, and so forth) by their upper-level parents.
▪To uninitialize a command, call the DataBindings.Clear method. All child commands should be closed by DataBindings.Clear.
Debugging
Use the ATLTRACE and ATLASSERT macros for debugging. Use the ATLASSERT to check any unusual conditions that are not checked as part of normal error handling. For common modules, use ATLASSERT to check for invalid method arguments, or invalid class states. Use assertions, but don't use them in place of normal error handling routines. For a good guide to when to use and not use assertions, refer to Writing Solid Code by Steve Maguire.
See also