Determining why binary compatibility is broken - vb6

When I try to rebuild one of my VB6 DLLs, I get a warning:
"The binary compatibility DLL or EXE contains a parameter type or
return type whose definition can not be found"
I have to release a few changes in selected DLLs (simple changes internal to methods - nothing that breaks the compatibility according to this)
The generally accepted method which I have followed is to maintain the old DLLs in a separate shared directory and while making the new DLLs, compile them with binary compatibility set to the old set of DLLs. This is done to not change the GUIDs while I register my new DLLs. These GUIDs are used as references in other DLLs which I have not disturbed during the release.
I'm pretty sure I didn't add anything to break the binary compatibility rule (No change in signature, public methods, variables etc.) Why is this error occurring?
Am I being a noob by not checking something basic? Scratching my head since morning. Any help is much appreciated.
EDIT: If at all there are changes to my signature, Is there a way that I can know without comparing code?

Take your old DLLs and add a compat_ prefix to them.
Basically rename your MyAppDataAccess.dll file to compat_MyAppDataAccess.dll.
Now go to the properties of your ActiveX DLL and set your project to have binary compatibility with the new compat_MyAppDataAccess.dll, like below.
Now just build your DLL and deploy it.
It should work. If, in fact you binary compatibility would be broken as a result of your changes, then you'll get a warning stating that.

Related

How to share VB project with another programmer overcoming the vbp "reference" issue?

I have this old VB6 project that is composed of a few DLLs, OCXs, and GUIs.
There is a GUI component that includes this in it's VBP file:
Type=Exe
Reference=*\G{00020430-0000-0000-C000-000000000046}#2.0#0#C:\Windows\SysWOW64\stdole2.tlb#OLE Automation
Object={EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}#1.1#0; ieframe.dll
Object={3050F1C5-98B5-11CF-BB82-00AA00BDCE0B}#4.0#0; mshtml.tlb
Reference=*\G{64E54C86-D847-48F7-9AE5-D6C9B8E6A3A2}#3.0#0#..\..\bin\Crypt.dll#Crypt
Reference=*\G{B3E7F95C-B6D9-458E-B4D4-5272759B139A}#4.0#0#..\..\bin\SpeechMike.dll#SpeechMike_DLL
Object={831FDD16-0C5C-11D2-A9FC-0000F8754DA1}#2.1#0; MSCOMCTL.OCX
Object={AB4F6C60-4898-11D2-9692-204C4F4F5020}#29.0#0; Ccrpsld.ocx
Object={48E59290-9880-11CF-9754-00AA00C00908}#1.0#0; msinet.ocx
Object={9C526969-AA6E-4D61-BAFA-117FD20C2B38}#3.0#0; SpeechMike.ocx
The Reference settings are a pain since they always change from one machine to the other. I mean, the GUID '9C526969-AA6E-4D61-BAFA-117FD20C2B38', for the last one as an example, will be something on my system, but something else on somebody else's machine.
For now, to make it work, I erase References to Crypt.dll and SpeechMike.dll. Also Object SpeechMike.ocx. Otherwise, Visual studio looks for something that does not exists. Then in "project > references" I check both Crypt and SpeechMike and the Reference goes back to the VBP with the proper GUID and version. Finally, in 'project > components' I add the OCX and I'm good to go.
Am I wrong about that? How can I share the project with some else without going through hoops and loops to start the project?
I'm using MS Visual Basic 6 (part of VS 6 enterprise).
This sounds like "failure to maintain binary compatibility." Normally you only do this to yourself, but of course it can be a bigger headache if multiple people are compiling your libraries from the source Project files.
When you create ActiveX EXEs, DLLs and OCXs you need to create a "base" version where type and class ID values (GUIDs) get assigned. The documentation even suggests that you do this leaving the procedures empty: just a comment line or something so the IDE does not remove the empty declarations.
You don't have to use an "empty" base reference library, it can be one with full code in it.
Once you have compiled this baseline library, you'd exit and save your Project. Then rename this "empty" library as something else and from there keep it along with your Project source files.
After this you re-open the Project and go into Project Properties and on the Component tab change the Compatibility setting to Binary Compatibility and in the box there enter the full path and name of your compiled baseline library. Save the Project. Now you can add code and compile the "real" library to be used by other programs.
When you distribute these libraries (DLLs, OCXs) to somebody else in source code form so that they can compile them you must provide this renamed compiled baseline library along with the source code files, VBP file, resource files, etc.
From there your GUIDs will be stable until you make a change to something that breaks binary compatibility (changing a method's argument list, etc.).
There is more detail on this in the online Help (MSDN Library). See:
Using Visual Basic|Component Tools Guide|Creating ActiveX Components|Debugging, Testing, and Deploying Components|Version Compatibility in ActiveX Components

Visual Studio: different ocx file version number for new OS?

I'm looking for general advice. I created a Visual Studio 2010 project that outputs an ocx file that is used on XP and Vista machines. The DLL on which it depends has been updated on our Win7 machines. I simply needed to rebuild for Win7 using the exact same code with an updated .lib file. I created a second project configuration (ReleaseW7) and it only differs from the original project config (Release) in that it points to the new .lib.
So now I have 2 files both named xx.ocx. Besides looking at the name of the folder each file resides in (or looking at the creation time of each) there is no way to determine which is which. I thought of using different file version numbers but as far as I can tell (and I'm relatively new to this so I could certainly be wrong) that would require two separate projects each with a slightly modified resource (.rc) file, instead of simply having two configurations within the same project. If nothing more, that seems like a waste of hard drive space. It also feels like the "wrong" way of using file version numbers
Is there a cleaner or more "standard" way of handling this? All I really want is a way for the folks who install the ocx and support the end user to know for certain that they are working with the correct file.
Long story short, I decided to use different version numbers. I was able to setup a preprocessor definition for the resource compiler and use that to handle different versions of VS_VERSION_INFO in my .rc file.
In case anyone is interested, this is the resource I found:
http://social.msdn.microsoft.com/Forums/en-US/winformssetup/thread/605275c0-3001-45d2-b6c1-652326ca5340/

How do you verify that 2 copies of a VB 6 executable came from the same code base?

I have a program under version control that has gone through multiple releases. A situation came up today where someone had somehow managed to point to an old copy of the program and thus was encountering bugs that have since been fixed. I'd like to go back and just delete all the old copies of the program (keeping them around is a company policy that dates from before version control was common and should no longer be necessary) but I need a way of verifying that I can generate the exact same executable that is better than saying "The old one came out of this commit so this one should be the same."
My initial thought was to simply MD5 hash the executable, store the hash file in source control, and be done with it but I've come up against a problem which I can't even parse.
It seems that every time the executable is generated (method: Open Project. File > Make X.exe) it hashes differently. I've noticed that Visual Basic messes with files every time the project is opened in seemingly random ways but I didn't think that would make it into the executable, nor do I have any evidence that that is indeed what's happening. To try to guard against that I tried generating the executable multiple times within the same IDE session and checking the hashes but they continued to be different every time.
So that's:
Generate Executable
Generate MD5 Checksum: md5sum X.exe > X.md5
Verify MD5 for current executable: md5sum -c X.md5
Generate New Executable
Verify MD5 for new executable: md5sum -c X.md5
Fail verification because computed checksum doesn't match.
I'm not understanding something about either MD5 or the way VB 6 is generating the executable but I'm also not married to the idea of using MD5. If there is a better way to verify that two executables are indeed the same then I'm all ears.
Thanks in advance for your help!
That's going to be nearly impossible. Read on for why.
The compiler will win this game, every time...
Compiling the same project twice in a row, even without making any changes to the source code or project settings, will always produce different executable files.
One of the reasons for this is that the PE (Portable Executable) format that Windows uses for EXE files includes a timestamp indicating the date and time the EXE was built, which is updated by the VB6 compiler whenever you build the project. Besides the "main" timestamp for the EXE as a whole, each resource directory in the EXE (where icons, bitmaps, strings, etc. are stored in the EXE) also has a timestamp, which the compiler also updates when it builds a new EXE. In addition to this, EXE files also have a checksum field that the compiler recalculates based on the EXE's raw binary content. Since the timestamps are updated to the current date/time, the checksum for the EXE will also change each time a project is recompiled.
But, but...I found this really cool EXE editing tool that can undo this compiler trickery!
There are EXE editing tools, such as PE Explorer, that claim to be able to adjust all the timestamps in an EXE file to a fixed time. At first glance you might think you could just set the timestamps in two copies of the EXE to the same date, and end up with equivalent files (assuming they were built from the same source code), but things are more complicated than that: the compiler is free to write out the resources (strings, icons, file version information, etc.) in a different order each time you compile the code, and you can't really prevent this from happening. Resources are stored as independent "chunks" of data that can be rearranged in the resulting EXE without affecting the run-time behavior of the program.
If that wasn't enough, the compiler might be building up the EXE file in an area of uninitialized memory, so certain parts of the EXE might contain bits and pieces of whatever was in memory at the time the compiler was running, creating even more differences.
As for MD5...
You are not misunderstanding MD5 hashing: MD5 will always produce the same hash given the same input. The problem here is that the input in this case (the EXE files) keep changing.
Conclusion: Source control is your friend
As for solving your current dilemma, I'll leave you with this: associating a particular EXE with a specific version of the source code is a more a matter of policy, which has to be enforced somehow, than anything else. Trying to figure out what EXE came from what version without any context is just not going to be reliable. You need to track this with the help of other tools. For example, ensuring that each build produces a different version number for your EXE's, and that that version can be easily paired with a specific revision/branch/tag/whatever in your version control system. To that end, a "free-for-all" situation where some developers use source control and others use "that copy of the source code from 1997 that I'm keeping in my network folder because it's my code and source control is for sissies anyway" won't help make this any easier. I would get everyone drinking the source control Kool-Aid and adhering to a standard policy for creating builds right away.
Whenever we build projects, our build server (we use Hudson) ensures that the compiled EXE version is updated to include the current build number (we use the Version Number Plugin and a custom build script to do this), and when we release a build, we create a tag in Subversion using the version number as the tag name. The build server archives release builds, so we can always get the specific EXE (and setup program) that was given to a customer. For internal testing, we can choose to pull an archived EXE from the build server, or just tell the build server to rebuild the EXE from the tag we created in Subversion.
We also never, ever, ever release any binaries to QA or to customers from any machine other than the build server. This prevents "works on my machine" bugs, and ensures that we are always compiling from a "known" copy of the source code (it only pulls and builds code that is in our Subversion repository), and that we can always associate a given binary with the exact version of the code that it was created from.
I know it has been a while, but since there is VB De-compiler app, you may consider bulk-decompiling vb6 apps, and then feeding decompilation results to an AI/statistical anomaly detection on the various code bases. Given the problem you face doesn't have an exact solution, it is unlikely the results will be 100% accurate, but as you feed more data, the detection should become more and more accurate

Should you build components every time you build a main app

We have started using Final Builder to create builds for our vb6 and .net projects. We are also using Visual Source Safe to manage our source. Some of our vb6 exe's are dependent on certain ocx's, such that a particular vb6 exe may require a particular version of an ocx.
The question is, should the final builder script for our exe project also re-build the ocx project, or is it better to simply pull a particular version of the already compiled ocx. My concern is that other developers could have broken the build (or created a bug) for the ocx which could then break the exe we are trying to build. Moreover, re-building the ocx project would result in the same version of the ocx but with a different date, resulting in confusion if dllhell(ocx hell) issues arise.
There is no difference in terms of building and maintaining your app between a ocx and a activex dll. The ocx should use binary compatibility and be part of your compile process.
This is however a general rule. You may have some components that rarely change if ever. In my own VB6 application I have a handful of components that reside at the bottomost level of my reference hierarchy that rarely get updated. They maybe get updated one or twice a year at best. Some haven't been updated for several years now.
However based on your description it sounds like the controls are still being modified. So I doubt the second case applies.
In the end use your best judgment.
There are two ways to use OCX/DLLs: code reusability vs. fragmentation of an over-large project.
Those meant for re-use would be absurd to build, build, and rebuild, and almost never should be customized to fit a new application. These are your crown jewels, and most people should have no ability to modify the source. They are the domain of your organization's "library writers" because that's what they are: libraries.
If you simply have large, monolithic, unweildy applications you may have to go the other route. Then OCXs and DLLs simply become an awkward extension of the "module" concept. This is why we have Project Groups.
Your library users should not be fiddling with libraries though. I'm sure they all fancy themselves able to "ensure they are up to date and performant" but that's a different debate entirely.

Developing in VB 6.0

We have multiple projects in VB 6.0. Most of these projects are ActiveX DLL's. When developing, projects take a '.dll' reference of other projects, but this does not allow us to debug. So, for this we have to take a reference to the '.vbp' project. However, taking a project reference, means we are asked for binary compatibility.
During development, should we use project compatibility and build projects into DLL's for deployment?
It's fine to reference the vbp during development, just make sure you keep binary compatibility on. If you do not, you'll make the registry into a nice mess and deployment will be a disaster. Keep in mind, however, even with binary compatibility on, every time you change the public interface of the DLL, you're creating a forward reference in the OLE entry in the registry.
we have four levels of DLLS in the CAD/CAM software we use for my company's cutting machines. We handled this by making a compatibility directory that the PREVIOUS version's DLLs in it. With this we can continue to use binary compatibility.
The process looks like this.
Compatibility has Revision 119 DLLs
in it.
We compile down Revision 120 and
release it
Copy the Revision 120 DLLs to the
compatibility directory.
Develop
Test
We Compile down Revision 121 and
release it.
Copy the Revision 121 DLLs to the
compatibility directory.
[repeat]
The main problem you need to watch out for is changes to the the lowest level of DLLs you use. Visual Basic 6 uses a #include statement in generating its internal type libraries. Doing will need to getting it confused over whether it is still binary compatible or not. Note you can see this by using the OLE View tool that comes with Visual Studio 6.
The solution to this problem is compile the low level DLL and immediately put it into the compatibility directory. The resulting internal typelibs for the higher level DLLs will now properly detect whether you are binary compatible or not.
Remember binary compatibile means all you can do is add a method or property. You can't change a existing method's name or argument list. (it's signature in COM terms)
You should be able to debug referencing a dll. Did you start the projects in the right order? Or you can add all/some dll into the same "Project Group" (*.vbg).

Resources