|
Binary Compatibility
Binary Compatibility
First, find the setting.While working on an ActiveX component, you can locate this setting by selecting the 'Project/ Properties' menu. From there, click on the 'Component' tab. Down near the bottom of that tab is a frame called 'Version Compatibility'.
Learning the "ins and outs" of this setting can save you hours of grief later. Keep in mind that the 'No Compatibility' and 'Project Compatibility' can mean death to previously released applications.
No Compatibility:
Just as it says. VB does nothing to preserve component compatibility. Every time you compile, VB generates entirely new interface ID's for every public interface.
Project Compatibility:
This setting is mainly for use during the initial creation of the component. This allows you to re-open your project groups without adding all references and components each time you start to work on them. This setting should *not* be used after the first time you compile.
Binary Compatibility:
This is the one you need to get comfortable with. This is the one that allows you to make changes to your component without recompiling every application you've made that uses the component.
An ActiveX Control or DLL is worthless without Public interfaces. The interfaces include all of the properties, methods, events, etc. that you've marked as Public. In other words, everything you've added that shows in Intellisense while working outside of your component.
The Basics:
Let's say you have a component, version 1.0.0, that exposes 2 public properties.
Their names are PropA and PropB.
When you compile, VB generates something similar to a GUID for each of these properties. These are the Interface ID's and are long, hard to read, ugly values that are stored in the registry.
These ID's enable compiled applications to access those properties.
Ok.. so far, we have:
Version 1.0.0: 'the actual version number doesn't matter. I'm using it here for future reference.
Keep in mind that the ID's shown below are highly over simplified versions of what the
long, hard to read ID's actually look like.
PropA (Interface ID = 1)
PropB (Interface ID = 2)
Those ID's are compiled in to any app that needs your component. In other words, the app that needs your component couldn't care less about a property named PropA,
All it cares about is a property that has an Interface ID = 1.
If you compile without Binary Compatibility, VB will generate entirely new Interface ID's for those properties. After recompile, they could be.
Version 1.0.1:
PropA (Interface ID = 21) 'again, highly over simplified.
PropB (Interface ID = 299)
This is all fine and dandy for your component and anything you work on in the future that needs this component, but it's absolute death, no holds barred, Error 429
or 430 time for any applications that referenced the component before recompiling.
Also, it may cause 2 or more separate entries in your References or Components dialog to show.
Of course, only the most recent is valid, but there's no easy way to tell which is the most recent by looking at the dialog.
Set up and get ready to use Binary Compatibility.
Initial setup is easy.
A) In your components project folder, create a new folder and call it 'Release' or 'Compat' or something similar to let you know what the folder contains.
B) Copy your compiled component to that folder. Some people take an extra step and change the extension of that copy to '.cmp' or similar, to make it clear that this is used only for compatibility settings. This copy of your component is essentially an object model that contains all of the public interfaces in use.
C) Open your project, select the 'Project/ Properties' menu. From there, click on the 'Component' tab. Near the bottom, you'll find an option button that says 'Binary Compatibility'. Select that and use the ellipses (browse) button to locate the copy of your component created in step B.
From now on, as long as you don't change anything related to PropA or PropB, including expected number of arguments, their names or types, VB will extract the Interface ID from that model each time you re-compile the component. In general, you can add new interfaces at any time, but you can't change or remove any without breaking compatibility and rendering the component worthless as far as previously compiled applications are concerned.
Well, those were the basics.
Now for some of the "Gotcha"s.
First of all, *always* remember that the compatibility model contains only those interfaces that were present when you copied the file to your 'Compat' folder.
In this example, the model contains only PropA and PropB.
As the rules state, you can add new interfaces without breaking old applications.
So, we'll add PropC to Version 1.0.2.
Older applications that never knew about PropC will still function correctly because all they care about are the Interface ID's for PropA and PropB.
But, if your model isn't updated to include this new interface, the next time you recompile, you'll be back in the same boat... but more confused because OldExeThatUsesPropAandB still works fine, but NewExeThatUsesPropABandC fails.
This is because VB is extracting any Interface information from the compatibility model
you instructed it to use, but generating a new ID for the PropC property every time you compile.
When you think about it, this is the only way it could be. Nobody told VB that you wanted to keep the Interface information so, to make it easy on you, VB is happily generating a new ID during each time you compile. It really couldn't work any other way.
VB is doing its best to hide complexities from you. Every once in a
while, this "Ease of Use" makes things harder <g>
So, the moral of this part of the story is.. Always update your model.
Every time you add a new interface, the model absolutely needs to be updated.
That doesn't mean that you should over-write the existing model though.... Read on....
This can get tricky if used incorrectly but, you should retain a copy of any component you've released. You may need these older components for models later.
This comes into play when you're updating the app that needs the older component. Remember that this is the app that needs only properties PropA and PropB.
The tricky part is, you've now added Interface information to the registry for PropC. This means that this information will be compiled into any applications that reference your component while recompiling.
Even though that application never uses PropC, the interface information is now expected to be there. So, you recompile OldExeThatUsesPropAandB and distribute it to your customer.
They install it and, since there's no component on their computer that has interface info for PropC. BANG! Error 430 (Automation error, the component dies horribly) or Error 429 (can't create the object at all).
Obviously, the easiest way to handle this problem is to always ship the latest version of your components with your applications. But, there may be some reason that you don't want to do this. Either the customer didn't pay for an update, or you simply don't want to give them the new component.
If you've saved a copy of the component that was initially shipped with that application (v1.0.0), you can use that while compiling the updated exe
and the newly compiled exe will still be oblivious to that new
PropC.
To do this, unregister the latest component so there's no Interface information for PropC in your registry.
Then, re-register the older component before compiling the updated exe.
If you do this, you should be able to ship only the updated exe if desired.
I've developed an Add-In for VB6 called ComGuard that will take all of the guesswork and most of the danger out of component development.
Using ComGuard will eliminate the need for you to manually keep these models up to date and maintain backup copies.
Click here to jump to ComGuard's product page
Hope this helps...
|