Executable components, also known as out-of-process or local components, are EXE files that house COM+ objects. Both executable and in-process components (with the help of a surrogate) can run on remote machines in a distributed environment. The promise of location transparency in COM+ means that you don't have to modify the client process, regardless of whether it's accessing an in-process or an executable component running on a local or remote machine. In previous chapters, we implemented in-process components; in this chapter, we'll discuss how you can convert an in-process component to an executable component and then call it remotely.
Figure 13-1 compares a client calling an in-process component to a client calling a component running in a separate address space.
Figure 13-1. The memory layout of in-process components, executable components, and their clients.
Before you build an executable component, you should carefully weigh the advantages and disadvantages of using executable components instead of their in-process siblings. As you know, you need not create an executable component to call a component remotely; DLL surrogates enable in-process components to run both locally and remotely.
The two primary advantages of executable components are that they can run as services, as described in Chapter 18, and that the user can run them as double-clickable applications. In both cases, you can still build the desired functionality into an in-process component and then create an executable front to call the component. Another reason that some developers favor executable components is that since they run in a separate address space from the client, they pose less of a security risk to the client. But you can also address this security risk by using a DLL surrogate. In fact, in the future there might not be any need for executable components that are not surrogates for in-process components.1
In some situations, the outgoing parameters of a method call made on an in-process component work slightly differently from a method call made on an executable component. For example, when a method running in an in-process component writes data using pointers provided by the method's out parameters, the caller's address space is updated immediately; if the method is running in an out-of-process component, the caller's address space is updated only when the method returns. Normally, this rather subtle difference is of no consequence. However, if a method running in an out-of-process component makes a call back to the caller, the caller might reasonably expect that its variables have been updated by the method. This will not be the case because the method has not yet returned. You can resolve this by specifying that methods should not write data through out parameters until just before they return, as is the case automatically with out-of-process components. In this way, this minor variation between the operation of in-process and out-of-process components is better masked.
What about the disadvantages of executable components? The main disadvantage is that they run much more slowly than in-process components because cross-process calls must be made. Of course, an in-process component running in a surrogate or any kind of component running on a remote machine suffers the same performance hit. The following table lists some questions you should ask yourself when you consider whether to implement an in-process component, an in-process component running in the default surrogate, or an executable component:
Question | In-Process Component | In-Process Component Running in the Default DLL Surrogate | Executable Component |
---|---|---|---|
Do you want instances of the object to be shared by more than one client? | No | Yes | Yes |
Do you plan to enter the object in the Running Object Table (ROT)? | No | No | Yes |
Does the object need to expose nonremotable interfaces (such as IViewObject)? | Yes | No | No |
Do you want the object to be insulated from client crashes? | No | Yes | Yes |
Do you want to run the component in the COM+ run-time environment? | Yes | Yes | No |
Do you want the object to have its own security context? | No | Yes | Yes |
Does the object require superior performance? | Yes | No | No |
Do you want the object to be run as a stand-alone application under the user's direct control? | No | No | Yes |
Does the object need to expose internal data structures directly to the client? | Yes | No | No |