- Rule 2-1: Think in Terms of Interfaces
- Rule 2-2: Use Custom Interfaces
- Rule 2-3: Define Custom Interfaces Separately, Preferably Using IDL
- Rule 2-4: Avoid the Limitations of Class-Based Events with Custom Callbacks
- Rule 2-5: Be Deliberate About Maintaining Compatibility
- Rule 2-6: Choose the Right COM Activation Technique
- Rule 2-7: Beware of Class_Terminate
- Rule 2-8: Model in Terms of Sessions Instead of Entities
- Rule 2-9: Avoid ActiveX EXEs Except for Simple, Small-Scale Needs
Rule 2-9: Avoid ActiveX EXEs Except for Simple, Small-Scale Needs
When you create a new project in VB, you are presented with a list of project types from which to choose: Standard EXE, ActiveX EXE, ActiveX DLL, ActiveX Control, Addin, IIS Application, and so forth. The ActiveX project types are used when you want to create a COM servera set of classes in a DLL or EXE that can be activated using COM. If your goal is a user-interface component, select ActiveX Control. However, if your goal is a traditional object-oriented, non-user interface component, then you should select either ActiveX DLL or ActiveX EXE. But which one?
The answer depends on two factors: the type of COM activation you desire, and whether you plan to use MTS or COM+. Let's review the three types of COM activation: in-process, local, and remote. An in-process activation means the COM object resides in the same process as the client that created the object. In this case, you must create an ActiveX DLL project, and the resulting DLL must be installed on the client's machine. Both local and remote COM activation represent out-of-process activation, in which the object resides in a process separate from the clienton either the same machine (local) or a different one (remote). With this scenario you have a choice. You can create an ActiveX EXE project, and the resulting EXE serves as a stand-alone process for hosting your objects, or you can create an ActiveX DLL and configure it to run within MTS or COM+ as a server process.
In-process objects are much more efficient, because calls are typically 10 to 100 times faster than calls out of process. The trade-off is that out-of-process objects offer
Fault isolation (object can crash without crashing the client, and vice versa)
Separate security identity (object runs under an identity separate from the client)
Multi-threaded behavior (clients can concurrently activate objects/execute calls)
The ability to run objects on a machine separate from the clients
The last is perhaps the most important, because it enables the construction of distributed, multi-tier applications. Assuming you want out-of-process activation, the question is should you use ActiveX EXEs or should you turn to MTS/COM+?
In short, VB's ActiveX EXEs are designed to support small-scale needs. They provide basic out-of-process activation, nothing more. On the other hand, MTS and COM+ support large-scale designs, in addition to providing a host of other services: security, resource sharing, distributed transactions, and configuration/process management. When in doubt, the general consensus is to use MTS or COM+, because you never know when you may need to handle additional clients, share resources among your objects, or implement security. However, if your needs are simple, then VB's ActiveX EXEs are a viable option. Because Chapter 3 focuses entirely on MTS and COM+, we discuss ActiveX EXEs here.
VB's ActiveX EXEs enable you to build multi-threaded server applications with relative ease. Like many features of VB, multi-threading is presented through the IDE with the utmost consideration for productivity. In this case, your ActiveX EXE's threading strategy is determined by two option buttons and a text box, not by coding. These Threading Model settings are found in your project's properties, under the General tab as shown in Figure 2.20.
Figure 2.20 Project properties for an ActiveX EXE
An ActiveX EXE is compiled to follow one of three threading model approaches. The default is Thread Pool of 1 (shown in Figure 2.20), which gives you a single-threaded application. This means that a single-thread is shared by all objects living in this server process, and thus only one client request can be processed at a time. Although this type of server consumes very few resources, it should be used only when you are supporting a single client.
The second approach is Thread per Object, which represents the other end of the threading spectrum. Now, instead of one thread, every object has its own thread.25 The result is maximum concurrency, because no client request blocks that of another. However, even though the server process supports an unlimited number of concurrent clients, does it maximize throughput? Not likely. At some point, the rising number of threads begins to hurt performance, because the operating system spends more time switching from one thread to another than it does letting a thread run. Thus, if you want to maximize both concurrency and throughput, you need to either scale up (add more hardware to the existing machine) or scale out (add more machines and load balance). You'll also need to cap the size of the thread poolthe motivation for the third approach.
The third (and best) approach for multi-threading is a thread pool more than 1. The idea is to limit concurrency by restricting the number of threads, thereby guaranteeing some base amount of throughput as the load on your server process increases. For example, Figure 2.21 shows a VB ActiveX EXE compiled with a thread pool of 3. The threads are depicted as circles with arrowheads, and each thread is assigned to a single apartment within the process (hence the term single-threaded apartment, or STA). When VB objects are created, they are likewise assigned to an apartment, and remain in that apartment until they are destroyed. Although the ActiveX EXE can support an unlimited number of objects (and hence an unlimited number of clients), in this example only three client requests can be processed concurrently. In particular, note that clients 1 and 2 have objects assigned to the same thread. Thus, if both submit a request (i.e., make a method call) at the same time, one request is processed and the other is blocked.
Figure 2.21 ActiveX EXE server with four clients and a thread pool of 3
The idea of a fixed-size thread pool is not unique to VB. MTS and COM+ also take this approach: MTS 2.0 on WinNT has a thread pool of 100, whereas COM+ (i.e., MTS 3.0) on Windows 2000 has a thread pool per processor ranging in size from 7 to 10. Notice that the size of the pool was reduced significantly in COM+, acknowledging the tension between concurrency and throughput.
Even though their thread pooling strategies are the same, note that MTS and COM+ provide a more sophisticated implementation, yielding better performance than VB's ActiveX EXEs. MTS and COM+ provide other distinct advantages as well. For example, consider the problem of objects trying to share data such as configuration information or a set of database records. In VB, the standard approach is to use global variables declared in a BAS module. However, in an ActiveX EXE, global variables are not truly global: A BAS module is replicated so that each apartment has its own copy. The result is that "global" variables are global only within an apartment. 26 This implies that you must use an alternative mechanism to share state, such as a file or database, or the memory-based Shared Property Manager within MTS and COM+.
With regard to security, VB's ActiveX EXEs rely on COM's security model. Using the dcomcnfg utility, you can configure the identity under which an ActiveX EXE runs, as well as who may start up, access, and configure the EXE. This also applies to the authentication level (frequency of authentication and network packet integrity/privacy).
In summary, ActiveX EXEs provide a quick-and-dirty mechanism for outof-process COM activation, and thus are a basis for application designs requiring fault isolation, security, concurrency, or distributed processing. However, keep in mind that Microsoft is moving away from ActiveX EXEs, and is encouraging developers to build ActiveX DLLs and to let MTS or COM+ serve as your EXE. This allows Microsoft to provide services that are difficult to implement yourself, and the ability to evolve these services without the need for you to recompile your code. Applications based on MTS and COM+ will scale, offer better concurrency and resource sharing, allow more flexible configuration of the server, and yield faster time-to-market for multi-tier systems. In the end, you'll spend your time more productively, working on business logic rather than infrastructure.