Home > Articles > Software Development & Management > Object Technology

The Mechanics of COM+

Like this article? We recommend

Limiting Context

If a class uses one or more COM+ runtime services, each instance of that class needs a context configured to suit its needs. But what if a class does not use any services? Consider a class that encapsulates the details of validating some sort of data. Other classes use this helper class to validate input passed to them by client programs, but client programs never use the validation class directly. The implementation of the validation class simply examines the data it receives and returns a boolean value indicating whether it is valid. Classes that use the validation class interpret its boolean return code to decide whether to proceed with a client request. The validation class neither knows nor cares about context; it does not rely on it and does not do anything with it. It never calls either CoGetObjectContext or CoGetCallContext. Each instance of the validation class can do its job in any environment because it is oblivious of the fact that there is an environment. Each validation class instance can accomplish its task without the additional space overhead of a new context or the additional time overhead of calls through the interception layer. Given that, the validation class should not be a normal configured class. If it were, the default catalog settings would force each instance into a new context of its own, which is neither necessary nor efficient. Instead, the validation class should be registered such that the SCM always puts each new instance directly in its creator's context.

Nonconfigured Classes

One way to achieve this effect is by using a nonconfigured class. Nonconfigured classes have entries in the Registry, but not in the catalog. Remember that the SCM puts a new object into a new context and introduces interception only if its creator's context cannot meet its needs. If the creator's context is a suitable environment for the new object, the SCM will put the object there and return a raw pointer to it. The SCM assumes that nonconfigured classes do not know and do not care about context; if they did, they would be configured classes with specific declarative attributes recorded in the catalog. The SCM always puts new instances of nonconfigured classes directly into their creators' contexts, and CoCreateInstance[Ex] always returns a raw reference, never a proxy, to the new object. (There is one exception to this rule related to threading, which is addressed in Chapter 4.)

Raw-Configured Classes

It is possible to set a configured class's declarative attributes so that the SCM treats it like a nonconfigured class at creation time. If a configured class is registered this way, each new instance will always live in its creator's context. Here too CoCreateInstance[Ex] will always return a raw reference to the new object, so I call configured classes that are registered this way raw-configured classes.

Raw-configured classes turn off all the runtime services that are implemented via interception, which is just about all of them. (Later chapters explain how raw-configured classes should set their attributes to turn these features off.) Raw-configured classes can use a constructor string (Construction Enabled = true, ConstructorString = "This string will be passed to every new instance of this class") if they want to. They can also use the object pooling service if they want to.2 Neither of these features is implemented via interception, so turning them on does not force a new object into a new context.

You should also set a raw-configured class's MustRunInClientContext attribute, described in Table 3-3, to true. This boolean flag tells the SCM that instances of a class must activate in their creator's context. If the SCM cannot meet this requirement for some reason, it fails the activation request and returns CO_E_ATTEMPT_TO_CREATE_OUTSIDE_CLIENT_CONTEXT. Whether or not a runtime services requires interception may vary depending on the configuration of a creator's context. By enabling a raw-configured class's MustRunInClientContext attribute, you can ensure that its instances will use services only when interception is not required.3

Table 3-3 The MustRunInClientContext class attributes

Attribute

Type

Default

Notes

MustRunInClientContext

Boolean

False

If SCM cannot put new instances in creator's context, activation fails


Raw-configured classes are typically installed in a library application of their own. This makes it possible to load their code into any process where a context might exist. It also solves a thorny security problem. The SCM always puts new instances of classes deployed in an application configured to support component-level security into individual contexts of their own. To avoid this, you have to disable support for component-level security by setting an application's AccessChecksLevel attribute, which is shown in Table 3-4, to COMAdminAccessChecksApplicationLevel.

Table 3-4 The AccessChecksLevel application attribute

Attribute

Type

Default

Notes

AccessChecks

COMAdmin

COMAdminAccess

Controls granularity

AccessChecks

ChecksApplication

ComponentLevel

Level of security access checks


If raw-configured classes are deployed in a library application of their own, you can disable component-level security for that application without affecting other applications. In other words, the configured classes in other server or library applications that use your raw-configured classes can still use component-level security if they want to.

Figure 3-12 shows how a raw-configured class is deployed and used. In this case, object A is an instance of a normal configured class. The SCM put it in its own context A when it was created. Object A creates object B, an instance of a raw-configured class deployed in a library application with component-level security turned off. The SCM puts object B in context A.

Figure 3-12
Using a raw-configured class

There are three advantages to using raw-configured classes instead of nonconfigured classes. First, raw-configured classes have entries in the catalog. Nonconfigured classes do not appear in the catalog; they are registered directly in the Registry using classic COM techniques. Having all your classes in the catalog makes it easier to manage your system's configuration because you can find all your classes' configuration information in one place.

Second, raw-configured classes are part of an application, usually a library application. Applications are the standard unit of deployment in COM+. Because there are tools for exporting applications and installing them on other machines, being in an application can help ease configuration management.

Third, as mentioned before, raw-configured classes can use the constructor string mechanism and the object pooling service because neither relies on interception. For all these reasons, in general, raw-configured classes are preferred. The rest of this book discusses raw-configured classes and ignores nonconfigured classes except in situations where their behavior differs.

Context-Aware Code Revisited

Each new instance of a raw-configured class lives in its creator's context. If a class is aware of that context and its implementation calls CoGetObjectContext or CoGetCallContext, can it still be a raw-configured class? The answer is a qualified yes. Remember that COM+ maps runtime services to contexts, not to individual objects. Any code executing in a context can make use of the services the context provides. Developing a context-aware raw-configured class is fine as long as you guarantee that it behaves correctly in any context. Consider a class that encapsulates, sending event notifications using Microsoft Message Queue (MSMQ). MSMQ relies on transactions to guarantee that messages are delivered in the order they were sent and that each message arrives exactly once. The event notification class can be implemented as a raw-configured class that uses a context's declarative transaction if there is one, or an internal MSMQ transaction if there is not. In short, this class can be used from any context. Its instances do not need new contexts of their own because their environmental needs are always the same as the environmental needs of their creators.

This may seem a risky way to design your classes, but it is not. It is simply leveraging your understanding of how contexts and interception work. Consider a method call into an instance of a configured class running in some context. The COM+ plumbing intercepts the call and makes sure the appropriate runtime services are invoked. Inside the method, the object can access context by calling either CoGetObjectContext or CoGetCallContext. If the object calls another one of its own methods, that method can access context by calling one of these APIs as well. If the object creates a language-level object and calls one of its methods, that method can also access context. Finally, if the object creates another COM object in the same context and calls one of its methods, then that method can access context, too. This is exactly what happens when a configured class makes use of a raw-configured class, as shown in Figure 3-13.

Figure 3-13
How a context-aware raw-configured class works

If object A' is an instance of a raw-configured class, it can acquire references to context A's object context because it is executing on a thread in context A. It can retrieve a reference to the current call context, too. Remember that both CoGetObjectContext and CoGetCallContext retrieve references to context based solely on the calling thread. Neither API cares which object is calling it. Any code a thread executes can retrieve either reference, until the thread passes through another interceptor and they are either removed or replaced. If object A called another one of its own methods, that second method could access context. Object A' accesses context the same way. Putting context-aware code into a nonconfigured or raw-configured class makes it a reusable, updatable, deployable unit that can be written in any language you like. In short, it gives you all the advantages of traditional in-process classic COM without the additional overhead of a new context and interception incurred by each instance of a configured class using the same services as its creator.

There is no real risk in this approach as long as your raw-configured classes behave correctly no matter what services the context they are created in provides. Remember that, while a class can use the current object context to find out about its environment, it cannot find out everything about its context. It is up to you to ensure that your raw-configured classes do not depend on aspects of context that cannot be detected. This is not hard once you understand how the COM+ services work.

If this seems to be taking advantage of some kind of undocumented loophole that might someday be closed, consider three things. First, key pieces of the COM+ infrastructure rely on nonconfigured and raw-configured classes. OLE DB and ADO use nonconfigured classes so they execute in their creator's context specifically so they can access and automatically enlist against a declarative transaction if one is present. Internet Information Server (IIS) uses raw-configured classes to dispatch HTTP requests. If the basic system plumbing relies on this feature, you can too.

Second, the MustRunInClientContext attribute exists specifically to allow a configured class to insist that it wants to run in its creator's context, as a raw-configured class does. As you will see in later chapters, other services provide attribute settings specifically designed to support raw-configured classes. The creators of COM+ designed the runtime with the notion of raw-configured classes in mind.

Third, if for some reason the context and interception architecture were changed such that new instances of raw-configured classes were no longer put in their creators' contexts, classes that are not aware of context will not care, and classes that are aware of context can simply be redeployed as configured classes with the right options set.

A Different Way of Looking at the World

Using raw-configured classes may seem like a strange idea, especially if they make use of context. It definitely represents a very different way of looking at the world of contexts. It reduces the number of contexts that exist, lowering memory consumption. It also reduces the number of calls through the interception plumbing, because calls to instances of raw-configured classes are not intercepted.

Here is an extended version of the formula introduced earlier for estimating the memory consumption of a COM+ process. This version still assumes the object-per-client model, but it has been extended to consider the impact of using instances of raw-configured classes.

((n2 x (s2 + 3,072)) + (n1 x (s1 + 2,048)) + (n0 x s0)) ÷ 1,024 = k KB

The new variable n0 represents the total number of objects that can be accessed without a proxy—degree 0 interception. Instances of raw-configured classes fall into this category. The new variable s0 is the average size of the n0 objects in bytes.

In the earlier example, 500 clients each used a single object in a server application process, so n2 = 500. Each of those objects used three additional objects that lived in contexts of their own that could be reached without a thread switch, so n1 = 1,500. All together, there were 2,000 objects in 2,000 contexts. With objects that consumed an average of s2 = s1 = 32 bytes of memory, the total footprint for the process was approximately k = 4,560 KB, or 4.5 MB. However, if each of the n2 = 500 clients' objects used three additional objects that did not have to live in their own contexts, memory consumption would be greatly reduced. If each of those additional objects' requirements could be met by their creator's context—either because they do not care about context or because they rely on the same services their creator needs—they could live there and be accessed directly. In this case, n2 = 500, n1 = 0, and n0 = (500 x 3) = 1,500. Assuming the objects are still the same average size, s2 = so = 32 bytes, the total memory consumed by the process drops to approximately k = 1,560 KB, or 1.5 MB. At 62 KB, the object still represent only 4 percent of that total; however, there is a 66 percent reduction in the memory consumed by contexts.

Figure 3-14 shows the memory consumption statistics for this new scenario with four average sizes for objects. Again the vertical axis measures memory consumption in KB, and the horizontal measures average object size. The shaded area at the bottom of each bar still represents the space consumed by contexts and interception plumbing. It is the same in all four cases because there are always 500 contexts. It is 66 percent lower than the previous case, shown in Figure 3-11, because 1,500 fewer contexts exist. The numbers that are above the bars indicate the percentage of memory the objects consume in each case. They are all higher than in the previous case because the amount of memory consumed by contexts has decreased.

Figure 3-14
Memory consumed by 2,000 objects in 500 contexts

Two things should be apparent from these numbers. First, reducing the number of contexts dramatically reduces the overall memory consumption of a process and dramatically increases the percentage of memory dedicated to objects themselves. Second, the larger the objects get, the less beneficial this reduction is. However, as noted earlier, objects would have to be quite large indeed to dull the impact of putting each one in a new context of its own.

Some might argue that this is a premature optimization that is too dependent on the implementation details of the COM+ plumbing, but I do not see it that way. This approach simply uses contexts efficiently, never paying more than is necessary to leverage the services COM+ provides. It is codified in Rule 3.2.


Rule 3.2

Give raw-configured classes preference over configured classes whenever possible to reduce context and interception overhead. Always use this technique for classes that do not care about context. Consider using this technique for classes that do care about context if you can guarantee that they will behave correctly in any context.


Subtle Complexities

Using an instance of a raw-configured class within a single context is fine; however, returning a reference to one of these objects to a caller in another context can lead to some subtle complexities. A reference to an object must be marshaled when it is passed from one context to another. This happens automatically when interface pointers are passed as arguments to and from calls to COM methods and APIs. If a client calls to an instance of a configured class living in a context, and that object returns a reference to an instance of a raw-configured class living in the same context, the interface pointer it returns will be marshaled. The client will get a reference to a proxy that forwards calls directly to the instance of the raw-configured class. Figure 3-15 illustrates this situation.

Figure 3-15
An external reference to an instance of a raw-configured class

In Figure 3-15, a client created object A, an instance of a configured class that the SCM put into context A. Object A created object A', an instance of a raw-configured class that the SCM also put into context A. Object A returned a reference to object A' to its client. What exactly happens when the client calls to object A' depends on the configuration of context A.

Remember that runtime services are applied to contexts, not objects. A new context is configured to provide the services an initial new object needs, as defined by its class's declarative attributes. That first object is known as the context's distinguished object because it is the object the context was originally constructed for.4 COM+ implements services by intercepting calls and invoking infrastructure code as needed. This happens not for calls to a distinguished object, but for all calls into a context. In the example, the client's calls directly to object A' will be intercepted at the context boundary, and whatever runtime services the distinguished object A requires will be applied. This may or may not present a problem.

Imagine that object A is an instance of a configured class set up to use the COM+ statistics service (it is registered in the catalog with EventTrackingEnabled = true). The SCM makes sure context A is set up to supply this service. All calls into context A are intercepted so statistics about the use of class A can be gathered. If the client calls to object A' in context A, the call will still be intercepted, and the statistics service will record the call as an invocation on an instance of class A. This may or may not be a problem. It is certainly misleading.

Now imagine that object A is an instance of a configured class set up to use role-based security. Assume it is configured to allow the user Alice to call any method of the interface IA and to deny calls from any other users or through any other interfaces. This security check is implemented automatically via interception when calls to object A enter context A. The reference to object A' that object A returns to the client is of type IA'. If the client attempts to call to object A' the call will be intercepted at the context boundary. Context A's environment is configured only to allow Alice to call through interface IA. Calls through IA', even if Alice makes them, are not allowed. So the client's attempt to call IA' will be rejected with the standard error code E_ACCESSDENIED. This is a problem.

What exactly happens when a client calls to an instance of a raw-configured class running in a context originally created for an instance of some other configured class depends on the specific combination of services the configured class is using. The exact behavior is difficult to predict and, in some cases, can be very strange indeed. You should avoid this situation by following Rule 3.3.


Rule 3.3

Use instances of raw-configured (or nonconfigured) classes to help implement the methods of configured classes, but do not return references to them to callers.


Custom Marshaling

Actually, there is one exception to Rule 3.3. In the example above, it would be okay for object A to return a reference to object A' to the client if object A' supported some form of custom marshaling, such as, marshal-by-value or free-threaded marshaling. Custom marshaling allows a COM object to control what happens when its interface pointers are passed from one context to another. An object expresses its desire to custom marshal by implementing the standard IMarshal interface. If an object exposes this interface, it will never be attached to a standard proxy/channel/stub connection. Without that, there is no interception, runtime services are never invoked, and the problems outlined never occur.

It is a common misconception that instances of configured classes cannot custom marshal; this is not the case. It is the case that a context's distinguished object cannot custom marshal. If the SCM creates a new context to meet a new object's needs, the object is going to live there, and calls to it are going to be intercepted. Many configured classes use runtime services that make each instance the distinguished object in its own context, so it is natural to assume that instances of configured classes cannot custom marshal. However, the SCM never creates new contexts for instances of raw-configured classes, and they can custom marshal if they want to. In fact, this is exactly how ADO's disconnected Recordsets—instances of a nonconfigured class—work. If you are planning to return a reference to an instance of a raw-configured class to a caller outside the context the object lives in, the object should definitely custom marshal. This is Rule 3.4.


Rule 3.4

If a configured class does return a reference to an instance of a raw-configured class to a caller, make sure the raw-configured class uses custom marshaling.


Footnotes

2. Chapter 5, Objects, addresses object pooling in detail.

3. Chapter 4, Threads, provides an excellent example of why the MustRunInClientContext attribute is useful.

4. As you'll see in later chapters, some runtime services are tied directly to a context's distinguished object.

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020