Outside of the Windows CE kernel where the C-style DLL prevails, COM is the most common technology used to expose key technology elements on embedded Windows devices. Many of the every-day activities that end-users perform with their Windows Mobile device are based on the COM architecture—ActiveSync, Pocket Outlook, Internet Explorer Mobile, the Soft Input Panel (SIP), and Windows Media Player all rely on COM as the primary integration technology. The C++ developer is uniquely placed to take advantage of these COM-based technologies, and the Active Template Library (ATL) is the best toolkit available for COM development.
COM and ATL are both huge topics, and have filled many previous books and articles. Rather than duplicate the already substantial body of literature that introduces COM and ATL, this article assumes some familiarity with COM and ATL development for the desktop and server environment, and primarily focuses on the subtle differences between the full version of COM and ATL and the Smart Device version.
Before drilling into the use of ATL to write COM components for Windows CE, it is worth briefly mentioning that ATL also simplifies COM programming when consuming components. COM relies on reference counts to determine when the memory associated with a component should be freed. The process of incrementing and decrementing the reference count of a COM object is a tedious and error-prone exercise, and ATL addresses this problem with the use of smart pointers. In a previous article, a Smart Device MFC project was shown that used Pocket Outlook to retrieve information about the time that was booked with appointments on a particular day. The project used standard interface pointers that required a call to Release to each interface before the interface pointer went out of scope.
To add ATL support to an existing MFC or Win32 project, simply bring up the project properties as shown in Figure 1, and select to statically or dynamically link to ATL. Static linking simplifies deployment, and is the recommended strategy for Smart Device projects. Once ATL support has been added, the raw interface pointers can be converted to ATL smart pointers by using the CComPtr template, so for the sample application, IPOutlookApp*, is replaced with CComPtr<IPOutlookApp>, and the call to Release can be removed.
Figure 1: Adding ATL Support to Existing Projects
Smart Device ATL for Component Authoring
For experienced ATL developers moving from the desktop world, the first thing that they will notice about the Smart Device ATL Project Wizard is the lack of Attribute support. Attributes have been part of the desktop version on ATL since Visual Studio 2002, and allows developers to concentrate of defining classes and interfaces directly in C++ rather than the COM-specific Interface Definition Language (IDL). In the absence of attributes, Visual Studio support for adding controls and classes reduces the burden of developers needing to gain a deep knowledge of IDL, and the addition of a COM object to a project inside Visual Studio adds the required IDL code in addition to the generation of the C++ class skeleton. However, like any code generation technique that adds code to a number of separate files, the real challenge comes when a control needs to be renamed or moved to a different project. In this case, using the IDE to generate the skeleton of the new class and interfaces is recommended, after which the method bodies can be moved across using cut-and-paste techniques.
Many of the difference between the desktop and mobile versions of ATL reflect underlying differences in the supported COM features on these platforms. Windows Mobile does not support the un-registration of COM components; theref0re, the code generated by the ATL application wizard is different for a Smart Device Project. A call to CAtlDllModuleT:DllUnregisterServer still exists in the generated code, but an extra parameter is passed to the method to instruct the ATL framework to ignore the call.
One of the critical differences between ATL objects on the desktop and device is how threading models work. As a brief background, the COM infrastructure allows a COM object to nominate one of a number of different threading models via a Registry setting. COM components that are not thread-safe or have strong thread affinity could elect to live in a single-threaded apartment (STA), and COM would use windows queues to synchronize the delivery of calls to the object. COM components that handled their own thread safety needs could elect to live in the multi-threaded apartment (MTA), and these components typically had better performance and greater scalability characteristics compared to STA-residing components. The problem for MTA components was that they still exhibited a performance-hit due to marshalling of calls to components living in STAs, and this gave rise to free-threaded components that could move from the MTA to STAs and back again. Free-threaded components are implemented using a technique known as aggregating the free-threaded marshaller, and in addition to the thread-safety requirements of free-threading, special techniques need to be used when holding interface pointers to COM objects (the COM global interface table and the ATL helper class CComGITPtr greatly simplify the work of dealing with member variable interface pointers—see the MSDN documentation on CComGITPtr for further details.)
The critical point for ATL developers is that a Smart Device Project for most builds of the Windows CE operating system does not ship with a full COM implementation, and this includes all Windows Mobile builds. According to the documentation, the slimmed-down version of COM "provides a midrange implementation of COM and OLE automation that supports only in-process free-threaded objects and requires about 100-200 KB of memory." When using Visual Studio 2005 or Visual Studio 2008 to add a new ATL object to a project, a similar dialog to the full version of ATL is displayed, as shown in Figure 2. The main difference between the Smart Device and desktop version of the dialog is the hyperlink to documentation, and following this hyperlink explains that the options related to threading models available don't apply to most CE platforms, including Windows Mobile. Regardless of the threading model selected in the dialog shown in Figure 2, a free-threaded component will be generated.
Figure 2: Adding a STL Simple Object to a Smart Device Project
Although the prospect of implementing a free-threaded component may not appear attractive to developers who have struggled with understanding the COM global interface table, it is worth noting that the complexities of needing to go between multiple STAs and the MTA do not exist in Windows Mobile because apartments are not present in the slimmed-down COM plumbing. The other point worth noting is that the primary use of COM on Windows Mobile is to integrate with and extend user interface elements such as the Soft Input Panel, Internet Explorer, and Media Player. In these scenarios, a COM component will be called on the user-interface thread, and will not be subject to the same level of multi-threading stress as a COM component in a server environment.
ATL simplifies the consumption and production of COM components, and the version of ATL available for Smart Device projects offers the bulk of functionality from the full ATL version. The COM implementation that ships with most builds of Windows CE, including all Windows Mobile builds, lacks many of COM's advanced features like apartments, and this simplifies the programming experience for C++ developers using ATL. For the C++ developer with some experience with templates and COM, Smart Device ATL offers a fast track for integrating with a range of Windows CE technologies.
About the Author
Nick Wienholt is an independent Windows and .NET consultant based in Sydney. He is the author of Maximizing .NET Performance and co-author of A Programmers Introduction to C# 2.0 from Apress, and specialises in system-level software architecture and development, with a particular focus of performance, security, interoperability, and debugging.
Nick is a keen and active participant in the .NET community. He is the co-founder of the Sydney Deep .NET User group and writes technical article for Australian Developer Journal, ZDNet, Pinnacle Publishing, CodeGuru, MSDN Magazine (Australia and New Zealand Edition) and the Microsoft Developer Network. An archive of Nick's SDNUG presentations, articles, and .NET blog is available at www.dotnetperformance.com.
In recognition of his work in the .NET area, he was awarded the Microsoft Most Valued Professional Award from 2002 through 2007.