Home > Articles > Programming > Windows Programming

This chapter is from the book

Rule 2-6: Choose the Right COM Activation Technique

In VB, the traditional mechanism for creating an object is the New operator. For example,

Set rEmp = New Employees.CConsultant

creates a new instance of the CConsultant class. However, this is not the only alternative. If the class is registered as a COM component, you can also use CreateObject and GetObject:

Set rEmp2 = CreateObject("Employees.CConsultant")
Set rEmp3 = GetObject("", "Employees.CConsultant")

On the other hand, if the class is configured to run under MTS, then you should probably be using CreateInstance instead:

Set rEmp4 = GetObjectContext.CreateInstance( _
               "Employees.CConsultant")

Finally, as if this wasn't enough, when you are writing server-side ASP code you will want to use Server.CreateObject:

Set rEmp5 = Server.CreateObject( _
               "Employees.CConsultant")

Do you know when to use each technique? If not, then read on . . .

First off, let's clear up a common misconception about how clients bind to objects at run-time.16 Logically, the situation is depicted in Figure 2.18. Clients hold references to interfaces and use these references to access objects. Physically, however, the binding mechanism used between client and object can vary, depending on how the reference variables are declared in the client. There are two main approaches: vtable-binding and late-binding. The former is more efficient, because the client is bound directly to an interface's implementation. This is available only in compiled environments such as VB, VC++, and soon ASP.Net. For example, the following two declarations dictate vtable-binding (1) to the default interface of class CConsultant and (2) to the custom interface IEmployee:

Dim rEmp1 As Employees.CConsultant '** (1) default interface
Dim rEmp2 As Employees.IEmployee  '** (2) custom interface

This is true regardless of how the objects are created. Regardless of whether the client uses New or CreateObject or some other mechanism, rEmp1 and rEmp2 are vtable-bound to the objects they reference. In contrast, consider the following declarations:

Dim rEmp3 As Variant
Dim rEmp4 As Object
Dim rEmp5       '** implies Variant

Figure 2.18 A client holding a reference to an object

These references all dictate late-binding, a less efficient mechanism based on COM's IDispatch interface (and one that always maps to the object's default interface). Again, this is true regardless of how the objects are created. For example, any use of rEmp5 is late-bound, even if the object is created using New:

Set rEmp5 = New Employees.CConsultant
rEmp5.SomeMethod '** this implies a lookup of SomeMethod, then invoke

Although late-binding is possible in compiled environments like VB (using the previous declarations), it is the only binding technique available in scripting environments such as IE, ASP, and WSH.

Note that the object being created must support the type of binding requested by the client; otherwise a run-time error occurs. Objects built with VB automatically support both vtable-binding and late-binding.

COM Activation

COM activation is the process by which a client creates a COM object at run-time. It is a somewhat complex process that involves the client, GUIDs, the COM infrastructure, one or more registries, and the COM server. Although the details are interesting, what's important here are the goals of activation: (1) create the object and (2) obtain the necessary interface references. 17 Keep in mind that objects can be activated across process and machine boundaries, a daunting task that is automatically handled by the COM infrastructure.

The New Operator

The most important characteristic of New is that it does not always trigger COM activation. In some cases, a call to New results in an optimized form of object creation performed entirely by VB. 18 How the New operator behaves depends on whether the class is internal or external, from the perspective of the client creating the object. For example, consider the following client code:

Dim rObj1 As IInterface
Set rObj1 = New CClass

The call to New results in VB's optimized creation if the class is internal, (i.e., CClass is either (1) part of the same VB project/DLL/EXE as the client, or (2) part of the same VB group as the client [and you are running that group inside the VB IDE]). Otherwise, the class is considered external, and COM activation is performed in an attempt to instantiate the object.

Being aware of New's optimized behavior is important for two reasons. First, it is much more efficient than COM activation, and thus is preferable for performance reasons. But, second, it is incorrect in certain situations, for example, when the class being instantiated is configured to run under MTS or COM+. In this case, COM activation is required for the class to receive the necessary MTS/COM+ services, but if the class is internal then New bypasses COM activation, creating an object that may not run properly. For this reason, the conservative programmer should avoid the use of New.

Note that the New operator can be applied in two different ways: traditional and shortcut. With the traditional approach, you declare a reference and then create the object separately as needed:

Dim rObj2 As IInterface
 .
 .
 .
Set rObj2 = New CClass
rObj2.SomeMethod

This allows your references to be of any interface type, and makes object creation visible in the code. The second alternative is the shortcut approach, in which you embed the New operator in the variable declaration:

Dim rObj3 As New CClass
 .
 .
 .
rObj3.SomeMethod

In this case, VB automatically creates an object on the first use of the reference variable (rObj2). Although this requires less typing, this approach restricts you to a class's default interface, and can lead to interesting runtime behavior. For example, consider the following code fragment:

Set rObj3 = Nothing
rObj3.SomeMethod     '** traditionally, this would fail
 .
 .
 .
Set rObj3 = Nothing
If rObj3 Is Nothing Then '** traditionally, this would be true
	Msgbox "you'll never see this dialog"
End If

Each time you use a shortcut reference in a statement, VB first checks to see if the reference is Nothing. If so, it creates an object before executing the statement. Not only does this result in additional overhead, but it also prevents you from checking whether an object has been destroyed (the act of testing re-creates another object!). For these reasons, we generally recommend that you avoid the shortcut approach.

CreateObject

Unlike New, the CreateObject function always creates objects using COM activation. You supply a string-based ProgID, and CreateObject converts this to a CLSID (via a registry lookup) before performing a standard COM activation. Here's a generic example:

Dim rObj1 As TLibName.IInterface
Set rObj1 = CreateObject("TLibName.CClass")

The advantage to this approach is flexibility. First, because CreateObject is based on strings and not class names, the class to be instantiated can be computed at run-time based on user input, configuration files, or records in a database. Second, CreateObject has an optional parameter for specifying where to create the object (i.e., on which remote server machine). This overrides the local registry settings, once again providing more flexibility at run-time. For example, this feature can be used to implement simple schemes for fault tolerance:

On Error Resume Next
Dim rObj2 As TLibName.IInterface
Set rObj2 = CreateObject("TLibName.CClass", "Server1")

If rObj2 Is Nothing Then '** server1 is down, try server2...
	Set rObj2 = CreateObject("TLibName.CClass", "Server2")
End If

If rObj2 Is Nothing Then '** both servers are down, give up...
	On Error Goto 0    '** disable local error handling
	Err.Raise ...     '** inform the client
End If

On Error Goto Handler '** success, reset error handler and begin...
 .
 .
 .

Note that the machine names are also string based, and thus can be read from configuration files or a database.

Because CreateObject only performs COM activation, it cannot instantiate Private or PublicNotCreatable VB classes. The class must be a registered COM object. Furthermore, whether you are using vtable-binding or late-binding, instantiation via CreateObject requires that the object support late-binding. 19 If the object does not, VB raises error 429. In these cases, the only way to instantiate the object is via New.

GetObject

As the name implies, GetObject is designed to gain access to existing objects; for example, an MS Word document object in a file:

Dim rDoc As Word.Document '**set a reference to MS Word Object Library
Set rDoc = GetObject("C:\DOCS\file.doc", "Word.Document")
rDoc.Activate

However, it can also be used to create new objects. For example,

Dim rObj1 As TLibName.IInterface
Set rObj1 = GetObject("", "TLibName.CClass")

In this sense, GetObject is equivalent to CreateObject, albeit without the ability to specify a remote server name.

Interestingly, as we'll see shortly, there's a version of GetObject that is more efficient than CreateObject, yet it is rarely used for this reason. Instead, it is commonly used to access MS Office objects or Windows services such as Active Directory, Windows Management Instrumentation (WMI), and the Internet Information Server (IIS) metabase. It is also used in conjunction with Windows 2000-based queued components (i.e., objects with method calls that are translated into queued messages for asynchronous processing). For example, suppose the class CQClass is configured as a queued component under COM+ on Windows 2000. The following gains access to the appropriate queue object for queuing of method calls (versus creating a traditional COM object that executes the method calls):

Dim rQObj As TLibName.CQClass
Set rQObj = GetObject("Queue:/new:TLibName.CQClass")

rQObj.SomeMethod        '** call to SomeMethod is queued
rQObj.SomeMethod2 "parameter" '** call to SomeMethod2 is queued

MsgBox "client is done"

In this case, the calls to SomeMethod and SomeMethod2 are queued for later processing by some instance of CQClass. This implies that a MsgBox dialog appears on the screen long before the actual method calls take place.

GetObjectContext.CreateInstance and Server.CreateObject

Suppose you have two classes configured to run under MTS, CRoot and CHelper. If CRoot needs to create an instance of CHelper, then there is exactly one way for CRoot to instantiate this class properly—via GetObjectContext.CreateInstance:

'** code for configured class CRoot
Dim rObj1 As TLibName.IInterface
Set rObj1 = GetObjectContext.CreateInstance( _
                  "TLibName.CHelper")

Likewise, if CRoot is an ASP page, then the proper way to instantiate CHelper is using Server.CreateObject:

'** code for ASP page
Dim rObj2
Set rObj2 = Server.CreateObject("TLibName.CHelper")

These methods are essentially wrappers around CreateObject, accepting a ProgID and performing COM activation. However, they enable the surrounding environment (MTS and ASP respectively) to recognize and to participate in the creation of the COM object. Direct calls to New and CreateObject bypass the surrounding environment, leading to slower or incorrect execution.20 For more details on the rationale and proper use of CreateInstance, see rule 3-3.

Performance Considerations

Most discussions involving the performance of COM objects focus on two things: (1) the type of binding (vtable versus late) and (2) the marshaling characteristics of any parameters. Although these are very important, little attention is paid to the cost of COM activation. Thus, assuming there is no compelling design reason to choose between New, CreateObject, and GetObject, is there a performance reason?

First, keep in mind that New is optimized for internal classes, so it is always the most efficient mechanism when COM activation is not needed. However, let's assume our goal is COM activation. There are three types of activation: in-process, local, and remote. In-process activation means the resulting object resides in the same process as the client. Both local and remote activation represent out-of-process activation, in which the object resides in a process separate from the client—either on the same machine (local) or a different one (remote). Examples of in-process activation include classes packaged as an ActiveX DLL and then registered as COM objects, and classes configured to run under MTS as a library package. Examples of local and remote activation include classes packaged in an ActiveX EXE, and classes configured to run under MTS as a server package.

In the case of in-process activation, New is always the most efficient: It is 10 times faster than CreateObject and is 10 to 20 times faster than GetObject. This is mainly the result of the fact that CreateObject and GetObject require additional steps (e.g., the conversion of the ProgID to a CLSID). Interestingly, in the out-of-process cases, the best performer varies: New is more efficient (10 percent) when you plan to use vtable-binding against the object's default interface, whereas CreateObject and GetObject are more efficient when you plan to use late-binding against the default interface (two times) or vtable-binding against a custom interface (10 to 15 percent). Let's discuss why this is so.

As noted earlier, COM activation has two goals: (1) create the object and (2) acquire the necessary interface references. The New operator is essentially optimized for vtable-binding against an object's default interface. In one API call, New creates the object and acquires four interface references: the default interface, IUnknown, IPersistStreamInit, and IPersistPropertyBag. On the other hand, CreateObject and GetObject are optimized for late-binding, because they acquire a slightly different set of interface references: IDispatch, IUnknown, IPersistStreamInit, and IPersistPropertyBag. Note that CreateObject and GetObject also take longer to create the object and to acquire these references (two API calls and three method calls).

So why is New slower in some cases? Recall that out-of-process activation yields proxy and stub objects to handle the communication between client and object (Figure 2.19). A proxy/stub pair is created during activation for each interface that is acquired, and thus forms part of the activation cost. Assuming the object does not perform custom marshaling, 21 the proxy-stub pair associated with its default interface is much more expensive to create than those associated with predefined COM interfaces such as IDispatch. As a result, if the client ends up using the default interface, then New is faster because it automatically acquires a reference to the object's default interface. However, if the client needs IDispatch (late-binding) or a custom interface, then CreateObject and GetObject are faster because time is not wasted building an expensive proxy/stub pair that will never be used. The results are summarized in Table 2.2.

Figure 2.19 COM out-of-process activation yields proxy and stub objects

Table 2.2 Maximizing performance of COM objects

Activation Type

Interface Client Will Use

No. of Calls Client Will Make

Best Performance

Activation

Binding

In-process

New

vtable

Local

default

< 10

CreateObject

late

 

3 10

New

vtable

custom

CreateObject

vtable

Remote

default

< 3

CreateObject

late

 

3 3

New

vtable

custom

CreateObject

vtable


What's fascinating is that activation is not the complete picture. The conventional wisdom for best overall performance is to access the object using vtable-binding because it requires fewer actual calls to the object and passes parameters more efficiently. However, vtable-binding implies the direct use of an object's interface (default or custom), and hence the need for an expensive proxy/stub pair in the out-of-process case. For example, assume the following client-side code is activating an out-of-process COM object:

Dim rObj1 As TLibName.CClass '** implies default interface
Set rObj1 = CreateObject("TLibName.CClass")

Even though CreateObject avoids the expensive proxy/stub pair, the Set statement will trigger their creation because the type of the variable being assigned is one of the object's interfaces. Therefore, to get the full benefit of using CreateObject, it turns out that you must also use late-binding! In other words,

Dim rObj2 As Object '** implies IDispatch to default interface
Set rObj2 = CreateObject("TLibName.CClass")

is roughly twice as fast as the previous code fragment. Of course, late-binding is more expensive per call, and thus the advantage of this approach diminishes as the number of calls increases. This explains the results in Table 2.2, in which there exists some threshold at which point vtable-binding becomes more efficient. Note that the exact threshold will vary in different situations (based on network speeds and distances, interface designs, and so on).

Lastly, if you are running Windows 2000 and are truly concerned with performance, you might consider using GetObject in place of CreateObject. GetObject is slightly more efficient when used as follows:

Dim rObj As ...
Set rObj = GetObject("new:TLibName.CClass")

In this case, GetObject acquires only two interface references instead of four; namely, IDispatch and IUnknown. Although this speeds up activation by reducing the number of method calls (which may be traversing across the network), it prevents the proper activation of "persistable" objects because IPersistStreamInit and IPersistPropertyBag are no longer available.

Fortunately or unfortunately, VB offers a number of different techniques for creating objects. Some always perform COM activation (CreateObject and GetObject); some do not (New). Some are more flexible (CreateObject and GetObject), whereas others must be used in certain cases for correct execution (GetObjectContext.CreateInstance, Server.CreateObject, and New). And some are more efficient than others, although one must take into account the type of activation, the interface being used, and the number of calls the client plans to make.

If you do not need COM activation, use New and vtable-binding. Otherwise, consult Table 2.2 to maximize performance. Although it may be counterintuitive, if your design involves "one-shot" objects (i.e., create, call, and destroy), then CreateObject with late-binding may be the most efficient approach. However, keep in mind that you lose IntelliSense and type checking with late-binding. For this reason, the conservative programmer should consider sticking with vtable-binding.

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