Developing in VB 6.0 - vb6

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).

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

Determining why binary compatibility is broken

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.

Including MS C++ runtime in VS2005 generated MSI

I've got a project that depends on a particular version of MSVCR80.dll (the MS Visual C Runtime) and I'm running into problems where, depending on the particular system configuration, my app doesn't always get the right version of that file. It's been a bit of a crap shoot as to what path it takes to find a file with that name, and it's not always right...
Is there a way, when creating a Deployment Project in VS2005, to ensure that my app will always use the runtime that I provided?? When I add the runtime file to the project, it asks about creating a merge module...but not really sure what that does. And regardless of creating one, the issue remains.
Martin Richter wrote an article about that on CodeProject:
Create projects easily with private MFC, ATL and CRT assemblies
This solution does not rely on your MSI packages but on the application that uses the CRT files.
I am not sure if it is your application after installation that doesn't work, or if it is a dll you use as part of the installation that doesn't work?
To make a very long story, very short: new versions of the C / C++ runtimes are installed as Win32 assemblies, or side-by-side installation. This means the files will go into folders under C:\Windows\winsxs - the Win32 equivalent of the GAC, and several versions of the same file can co-exist here.
Applications compiled with Visual Studio 2005 / 2008 will put a manifest file into the binary, and this manifest specifies what side-by-side runtime version to bind to. It doesn't matter if you put the MSVCR80.dll next to your EXE or even in system32 - the manifest embedded in the EXE will load the file from C:\Windows\winsxs.
This is all "full circle". In the old days runtimes went to System32. This caused the original dll-hell: applications overwriting each other's global runtime files. To remedy all this the idea was to "isolate changes" to each application. Hence the new approach was to isolate a local copy of the runtime file next to the EXE. Now this caused an entirely new problem: how do you make sure security updates for the isolated dll was deployed? In most cases this never happened, and you had lots of applications running with local, unsafe dll's. So what to do? The decision was to introduce the second coming of dll-hell: the side-by-side assembly approach. In this approach runtimes are not local, but global - with the critical difference of supporting side-by-side installations. This way, in theory, applications can function without overwriting each other's runtime dlls.
So that was the quick summary of "how to make runtime deployment complicated". I am not positive it is still possible to do, but did you check whether you can statically link to the runtime? Sometimes old-school really is easier...

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.

what is the diff between dependencies and manually add a dll/ocx in vs installer 6?

i'm using vs installer to build a setup package for my vb6 app.
and the problem is i can see that under the project explorer there's a list of dependencies attached to my exe file.
alt text http://img505.imageshack.us/img505/9696/croppercapture259lr8.png
and under the file system on target machine treeview, i can actually store the dll/ocx on a folder or in the windows system folder itself[the left window].
alt text http://img101.imageshack.us/img101/9224/croppercapture251qm1.png
so what i don't understand is .. is there actually a difference?
if i just set the dependencies and didn't add the dll or ocx to the folder or win sys folder, does the dll automatically get copied over too?
It is not guaranteed that all those dlls will be present on the system that the software is being installed on. So they need to be included in your installer. From there you have two choices.
You can install them in your windows system folders or in your application folder. The difference is that if you install them in your application folder you can set things up on XP and Vista so that the different version of the software with different version of the components can be fired up and run side by side. Installing them into the system folder will break any older version that depend on older version of the components.
Installing in the application folder rarely doesn't work if a component depends on other components that can't be updated. When this occurs it is usually with with Microsoft libraries. They have gotten better over the years on this issue.
You can read more about the issues involving side by side execution here
Finally the dependencies need to be in your installer so that they are registered in the Windows Registry. Unlike most .NET assemblies any ActiveX/COM application needs to have the component registered in order to use it even if you are using CreateObject and Variant types to access it.
I will admit the whole process is idiosyncratic and is one of the sources for the stories about DLL Hell. Start with the MSDN article, use wikipedia, and of course ask further questions here.
You should usually not have a "dlls" folder under the app folder for a normal Installer package but there are many factors involved (private standard DLLs, Reg-Free COM, etc.). Yes, the dependencies get included (unless you exclude them). They should each have a property that determines where they install on the target systems.
You also have a number of components in that list that are either not redistributable this way because they are OS-dependent system components, MDAC components, or not licensed for redist (fm20.dll for example).
Sadly this is an example of the type of package that can lead directly to DLL Hell for your users' systems. Fixing this can mean researching every MS component in MS KB articles to determine what can or should be redistributed and how.
Deployment can be a messy business to get right.

Resources