Home > Articles > Programming > Windows Programming

This chapter is from the book

Rule 2-5: Be Deliberate About Maintaining Compatibility

In a COM-based system, clients communicate with objects via interfaces. These interfaces must be well-defined, registered, and agreed on by all parties for your system to run properly (Figure 2.14). The good news is that this is relatively easy to ensure in your first release: Recompile the COM servers, then recompile the clients and deploy.

Figure 2.14 COM requires that servers (and their interfaces) be registered

However, at some point you will be faced with recompiling and redeploying one of your COM servers—perhaps to apply bug fixes or to add new functionality. In this case, what happens to the clients? You can either (1) redeploy all new clients to match or (2) ensure that your COM server maintains compatibility with the existing clients. Although the latter is typically preferred (and certainly less work), it requires that you have a solid understanding of COM's rules for versioning, and how VB applies those rules. Otherwise, recompiling a COM server can lead to all sorts of errors on the client side, from "Can't create object" and "Type mismatch" to the dreaded GPF.

Before we start, let's review some important concepts in COM. A typical COM server is a DLL/EXE that defines one or more classes, one or more interfaces, and a TLB that summarizes this information. Every class, interface, and TLB is assigned a unique 128-bit integer called a GUID. These are referredto as CLSIDs, IIDs, and LibIDs, respectively. GUIDs are compiled in the COM server that defines them, make their way into the registry when the COM server is registered, and usually get compiled in the clients as well. COM activation is the process of creating an instance of a class from a COM server, triggered, for example, when a client executes New. To activate, COM requires both a CLSID and an IID, locates the COM server via the registry, asks the COM server to create the instance, and then obtains the proper interface reference for return to the client. As discussed in rule 2-3, you can use the OLEView utility to view the contents of a server's TLB and to see the GUIDs firsthand.

Lastly, it's very important to understand the difference between a default interface and a custom one. Review rules 2-1 and 2-2 if necessary.

To maintain compatibility with clients, the short answer is that when recompiling a COM server, you need to focus on three things: functionality, interfaces, and GUIDs. Obviously, although implementation details may change, the server's overall functionality must be compatible from one version to the next. Second, the interfaces exposed by each class should not change in any way. Methods cannot be deleted, their names cannot differ, and their parameters cannot vary (not in number, type, or order). Finally, the identifying GUIDs should not change (i.e., the CLSIDs, IIDs, and LibID). Let's look at these compatibility issues in more detail.

Scripting Clients

The first step is to understand your clients. There are two types: scripting and compiled. Scripting clients are typically written in VBScript or JavaScript and are executed in environments such as ASP, IE, or WSH. The key characteristic of a scripting client is its use of generic object references:

Dim rObj  '** As Variant / Object

This typeless variable represents a late-bound (indirect, less efficient) connection to an object's default interface. 8, 9 In addition, scripting clients typically create objects using VB's CreateObject function, passing the appropriate ProgID (a string denoting the TLB followed by a class name):

Set rObj = CreateObject("Employees.CConsultant")

CreateObject first converts the ProgID to a CLSID (via the registry), and then performs a standard COM activation. 10 Once activated, a scripting client may call any method in the object's default interface. For example,

rObj.IssuePaycheck

This assumes that IssuePaycheck is a public subroutine within class CConsultant.

Thus, maintaining compatibility in your COM server amounts to preserving the ProgIDs and the default interfaces. The ProgIDs are easy to deal with: Simply do not change the name of your TLB or your classes. When building COM servers in VB, note that your TLB's name is derived from your VB project's name (a project property). As for the default interfaces, for each class you cannot delete any public subroutine or function, nor can you change its method signature. However, note that because clients are late-bound and parameters are thus passed as variants, it is possible to change a parameter's type in some cases and still maintain compatibility. For example, suppose a class originally contained the following method:

Public Sub SomeMethod(ByVal iValue As Integer)

This can evolve to

Public Sub SomeMethod(ByVal lValue As Long)

without breaking compatibility because Integer is upward compatible with Long.

Finally, it is worth noting that compiled environments also behave like a scripting client when object references are generic. In VB, this occurs whenever clients use the Variant or Object data type:

Dim rObj2 As Object  '** this says I want to be late-bound
Dim rObj3 As Variant '** likewise...

Each reference denotes a late-bound connection to an object, regardless of how that object is created:

Set rObj2 = New Employees.CConsultant
Set rObj3 = CreateObject("Employees.CConsultant")

In this case, the same compatibility rules apply, with the exception that the client's use of New requires that the COM server's CLSIDs and default IIDs also remain unchanged. This is discussed in the next section.

Compiled Clients

Compiled clients are characterized by object references of a specific interface type, for example:

Dim rObj4 As Employees.IEmployee   '** a custom interface
Dim rObj5 As Employees.CConsultant  '** the default interface

These variables represent a vtable-bound (direct, efficient) connection to a specific interface of an object. These interface types must be defined by your COM server—or more precisely, in its TLB—which the client must reference. Object creation is typically done using New or CreateObject:

Set rObj4 = CreateObject("Employees.CConsultant")
Set rObj5 = New Employees.CConsultant

Regardless of how the objects are created, at this point the reference rObj4 can be used to call methods in the custom interface IEmployee, whereas rObj5 can be used to call methods in CConsultant's default interface.

From the perspective of compatibility, the key observation about compiled clients is that they refer to interfaces and classes by name. As a result, when the client code is compiled, the corresponding IIDs and CLSIDs are embedded into the resulting EXE. Thus, maintaining compatibility with compiled clients requires that you preserve not only the ProgIDs and the interfaces, but the GUIDs as well.

Much like scripting clients, the ProgIDs and interfaces are under your control. However, VB is in charge of generating the necessary GUIDs whenever you compile your COM server. So how can you prevent VB from changing these values during recompilation? By manipulating your project's version compatibility setting, as shown in Figure 2.15.

Figure 2.15 VB's version compatibility settings

The first setting, No Compatibility, means precisely that. If you recompile, all GUIDs will be changed, thereby breaking compatibility with compiled clients. This setting lets you intentionally break compatibility (e.g., when you need to begin a new development effort). The second setting, Project Compatibility, is meant to preserve compatibility with other developers. In this case the LibID and CLSIDs are preserved, but the IIDs change. This allows references to your TLB to remain valid (i.e., references to your COM server from other VB projects), as well as class references embedded in Web pages. However, the IIDs continue to change, reflecting the fact that the server is still under construction. The rationale for this setting is team development, and thus the setting should be used when you are developing classes that you must share with others before the design is complete. To help track versions, note that VB changes the version number of your COM server's TLB by a factor of one each time you recompile. The third and final setting is Binary Compatibility, in which all GUIDs are preserved from one compilation to the next. This is VB's "deployment" setting, because it enables you to maintain compatibility with compiled clients out in production. Thus, you should switch to binary compatibility mode (and remain there) as soon as you release the first version of your COM server. Note that binary compatibility is necessary even if your interfaces and IIDs are defined separately, because of the fact that your clients may be dependent on the default interfaces generated by VB. 11

When working in binary compatibility, it's important to understand that VB needs a copy of your released DLL/EXE to maintain compatibility when you recompile. Notice the reference in Figure 2.15 to "release1\Employees.DLL." VB simply copies the GUIDs from the referenced file and uses them to generate the new COM server. It's considered good practice to build each release in a separate directory (release 1, release 2, and so on) so that you can always recompile against an earlier version if necessary.12 In general, however, make sure your binary compatibility setting always references the most recent production release. To prevent accidental overwriting, it's also a good idea to keep your release DLLs/EXEs in a version control system for read-only checkout.

Besides retaining GUIDs, binary compatibility mode also protects your interfaces. In particular, VB prevents you from making any changes that might break compatibility. For example, changing a method's parameter type from Integer

Public Sub SomeMethod(ByVal iValue As Integer)

to Long

Public Sub SomeMethod(ByVal lValue As Long)

yields the warning dialog shown in Figure 2.16. At this point, unless you are absolutely sure of what you are doing, you should cancel and then either restore the method signature, switch compatibility mode, or define a new interface containing your change. 13 Note that variants can be used as parameter types to give you some flexibility for future evolution without the need to change explicitly the type in the interface.

Figure 2.16 VB's warning dialog that an interface has changed

Version-Compatible Interfaces

The COM purist would argue that when you need to change an interface, you do so by defining a completely new one. This makes versioning easier to track, because each interface will have a distinct name (and IID). Although this may lead to more work within your COM servers, it enables a client to differentiate between versions, and thus remain backward compatible with your earlier COM servers. For example, a client can test for version 2 of the IEmployee interface before trying to use it:

If TypeOf rEmp Is IEmployee2 Then '** is v2 available in this object?
	Dim rEmp2 As IEmployee2
	Set rEmp2 = rEmp

	<use rEmp2 to access v2 of IEmployee interface>

	Set rEmp2 = Nothing
End If

As a result, new clients can be released before servers are upgraded, or can continue to function properly if servers are downgraded for some reason.

However, although COM purists argue in favor of maintaining version-identical interfaces, VB implements a more flexible (but dangerous) notion known as version-compatible interfaces. In short, VB's binary compatibility mode actually allows one type of interface change: You may add methods to the default interface. When you do so, VB is careful to add the new methods to the end of the class's underlying vtable, generating a single default interface that is compatible with both old and new clients. Note that VB increases the version number of your COM server's TLB by 0.1 to reflect the fact that the interface changed.

Interestingly, VB isn't breaking the rules of COM, because it generates a new IID to identify the resulting interface. To maintain compatibility, VB must produce code within the COM server so that objects recognize both the new and the old IIDs when queried at run-time. Likewise, the registry must be reconfigured to support the fact that multiple IIDs map to the same physical interface. In particular, the original interface forwards to the new interface, as shown in Figure 2.17. Note that interface forwarding is direct. If you add a method from release 1 to release 2, and then add another method in release 3, releases 1 and 2 both forward to release 3.

Figure 2.17 Forwarding to a version-compatible interface

Why does VB offer this feature? To make it easier for your classes to evolve. Why is this feature dangerous? First of all, there is only one version of an interface from the perspective of the client—the most recent one. VB clients thus cannot use TypeOf to determine which version of an interface is available. This makes it harder for clients to achieve backward compatibility with earlier versions of your COM server. Second, VB only provides support for extending the default interface. You cannot add methods to custom interfaces such as IEmployee. In fact, adding methods to a custom interface yields no warning from VB, yet breaks compatibility with your clients (even in binary compatibility mode!). Finally, some client-side setup programs fail to register properly the necessary interface forwarding information, leading to COM activation errors at run-time. This is a known problem (e.g., with MTS's export command).14

The safer alternative is that of the COM purist: Use custom interfaces, and define a new interface whenever changes are needed from one release to another. Note that avoiding these dangers is also one of the reasons we recommend defining your custom interfaces outside VB. See rule 2-3 for more details. 15

COM is a somewhat fragile system, requiring that all participants agree—servers, clients, and registries alike. Because most applications live beyond version 1, maintaining compatibility in the presence of evolution and recompilation becomes one of the most important aspects of COM programming. Although the nuances may be complex, the overall solution is straightforward: Develop in project compatibility, deploy in binary compatibility, and use custom interfaces whenever possible.

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