Discussion:
[NAnt-users] Building VB6 project group
Rik Hemsley
2006-04-25 14:25:28 UTC
Permalink
Hi,

I'm attempting to get NAnt to build a set of VB6 projects. So far, I
have it checking out code from SourceSafe and some of the projects
build successfully.

The problem I have come across is this: Where projects reference other
projects, I don't know how to update a project's reference to point to
a newly-built DLL.

The project Transport relies on the DLL from the project TransportX.

I've managed to alter the path to the referenced DLL, so that it
points to the newly-built version:

Reference=*\G{B45436A5-CF4F-4658-90FE-DF5B438DEC7E}#2.0#0#..\TransportX\TransportX.dll#

but nant complains like this:

[vb6] Building project
'C:\ContinuousIntegration\BuildTemp\Transport\Transport.vbp'.
[vb6] Couldn't find the tlb file for
'b45436a5-cf4f-4658-90fe-df5b438dec7e' ver.2.0.
[vb6] Output file
'C:\ContinuousIntegration\BuildTemp\Output\Transport.dll' does not
exist, recompiling.

I then get a messagebox giving me a compile error in one of the source
files for the Transport project, 'Can't find project or library'. This
is referring to the missing reference to the TransportX DLL.

Any ideas on how I can make this reference resolve?

Thanks,
Rik
Rik Hemsley
2006-04-25 15:11:52 UTC
Permalink
Hope this helps,
That's fantastic, thanks. I think this'll be a great help!

Cheers,
Rik
Foster, Richard - PAL
2006-04-25 15:21:32 UTC
Permalink
[Resending to group... Otherwise Rik's reply doesn't help anyone! :-)
Basically, off-list it was determined that Rik had binary compatibility
problems, and binary compatibility was (temporarily) disabled.]

The problem is if you turn off binary compatibility then the GUIDs all
change. You would need to find out the original and the updated GUID for
each of the exposed ActiveX objects, then update that GUID in all
downstream source files / projects. Certainly possible, but perhaps not
the easiest thing to do!

In my experience, the "Unable to set version compatible component"
usually occurs under one of the following circumstances:

1) A referenced component has broken binary compatibility. As a result,
if any public property or method of your component uses objects from the
referenced component it can also not maintain binary compatibility.
2) (Usually the root cause) In one of the projects, the file being
referenced for binary compatibility is the same location that the output
is being built to.

Again, in my experience, the best way to resolve this is as follows:

1) Open each of the projects (or a solution containing all the
projects).
2) Set the project(s) to "project" compatibility.
3) Build the project(s).
4) Copy the output executable to a "compatibility" location. (If you're
using continuous integration, you probably also want the compatibility
file under source code control, but you only need to update it after a
binary compatibility break).
5) Set the project(s) back to binary compatibility, referencing the
compatibility copy of the file in question.
6) Repeat (as necessary) for any downstream project(s).

Once you have completed this, you should then be able to build the
entire group using Nant... At least until you need to change one of the
interfaces.

*** Warning : If you do change any of the interfaces, you need to update
your compatibility files too. Otherwise the next time you build the
project it will not maintain complete binary compatibility! I tend to do
this by copying the most recent successful build of a project to its
"compatibility" location. ***

Hope this helps,
Regards,
Richard

-----Original Message-----
From: Rik Hemsley [mailto:***@gmail.com]
Sent: Tuesday, April 25, 2006 10:41
To: Foster, Richard - PAL
Subject: Re: [NAnt-users] Building VB6 project group

Sorry, I should have mentioned that, earlier in the script, I turn off
binary compatibility for the project files, because otherwise I get the
message "unable to set the version compatible component"

I believed that turning off BC for the build was the way to work around
this - I guess not then?

Cheers,
Rik
Rik Hemsley
2006-04-25 14:41:41 UTC
Permalink
Sorry, I should have mentioned that, earlier in the script, I turn off
binary compatibility for the project files, because otherwise I get
the message "unable to set the version compatible component"

I believed that turning off BC for the build was the way to work
around this - I guess not then?

Cheers,
Rik
Rik Hemsley
2006-04-26 09:14:01 UTC
Permalink
Post by Foster, Richard - PAL
1) Open each of the projects (or a solution containing all the
projects).
2) Set the project(s) to "project" compatibility.
I set each project to 'project' compatibility, but still got the
"Unable to set version compatible component" complaint. I adjusted my
script so that it removes the "CompatibleEXE32" line from each project
file, which seemed to allow the build to continue, but...
Post by Foster, Richard - PAL
3) Build the project(s).
I still get the error about the missing TLB file. I think it's
actually referring to TLB information stored inside the (missing) DLL,
rather than a separate file.

Oddly, this error does not appear for another project which is set up similarly.

Transport references TransportX (and some system stuff)
AnotherProject references AnotherProjectX (and some system stuff)

AnotherProject is built successfully, before the failure occurs for
the Transport project.

Perhaps there is a built copy of AnotherProjectX.DLL somewhere on this
system, with the correct GUID, but not of TransportX.DLL. This is
quite possible.

I might try to update the reference to TransportX in the .vbp, but
that would require finding the GUID of the newly-built TransportX.DLL.
I'm now having a look to see if anyone has made a utility to do this.
The ITypeLib/ITypeInfo stuff doesn't look like it's fun to work with.

Cheers,
Rik
Rik Hemsley
2006-04-26 09:27:18 UTC
Permalink
Post by Rik Hemsley
Perhaps there is a built copy of AnotherProjectX.DLL somewhere on this
system, with the correct GUID, but not of TransportX.DLL. This is
quite possible.
I used OLE/COM object viewer to look for registered DLLs and found
that indeed there is a AnotherProjectX.DLL registered with the GUID
that's in AnotherProject.vbp ... and there is no TransportX DLL with
the GUID in Transport.vbp.

Does anyone know of a GUID extraction tool? My google skills don't
seem up to the job of finding one, if it exists.

Rik
Rik Hemsley
2006-04-26 10:11:16 UTC
Permalink
Post by Rik Hemsley
Does anyone know of a GUID extraction tool? My google skills don't
seem up to the job of finding one, if it exists.
I found an easy way:

In VB6, add a reference to "TypeLib Information" and use:

TLI.TypeLibInfoFromFile(Path).Guid

Rik
Foster, Richard - PAL
2006-04-26 13:04:27 UTC
Permalink
Ah... Perhaps I was a bit unclear. Are you still trying to do this in
Nant? If so, I meant in VB6!

I also forgot another step:

2a) In your VB projects, you need to (temporarily) set the reference to
the in-IDE project, not the built version of the library.

Having two VB-built components with the same GUID would be a good trick.
The only way I can think of that may allow that to happen is if two
independent projects, both derived from one starting point, share the
same binary compatibility file.

A far more likely problem is that because the component has not
maintained full binary compatibility with the downstream references
(either intentionally, or by overwriting/deleting the compatibility
file, or rebuilding the library more than once without updating the
compatibility file after an interface change), the referenced library
simply cannot be located any more. The simplest method I know of to fix
this is to open the referencing project, remove the reference to the
library (sometimes VB6 will even tell you that it's missing), save the
project and exit VB, then finally load the project back up and add the
reference back in again. (I have found that skipping the shutdown step
occasionally seems to confuse VB, and on several occasions has resulted
in corruption of other Reference= lines.)

I'm also slightly confused by your subsequent message where you say:
there is no TransportX DLL with the GUID in Transport.vbp

I assume you are referring to the GUID part of the "Reference=" line?
Again, this would be consistent with TransportX.DLL being a VB project
that has been rebuilt outside the project group (solution) while not
maintaining binary compatibility. I also assume from your subsequent
message that you have now found the right GUID. Is that true?

All this strangeness just reminds me why I no longer choose to develop
COM components in VB! :-)

Hope you are successful.
Regards,
Richard
Rik Hemsley
2006-04-26 15:02:39 UTC
Permalink
Post by Foster, Richard - PAL
Ah... Perhaps I was a bit unclear. Are you still trying to do this in
Nant? If so, I meant in VB6!
No problem; your advice gave me enough to figure out how to fix this!
Post by Foster, Richard - PAL
2a) In your VB projects, you need to (temporarily) set the reference to
the in-IDE project, not the built version of the library.
This is what I do when building from within the IDE. I still find it
incredible that you can't build a project group in one step,
considering how long VB6 has been going.
Post by Foster, Richard - PAL
I assume you are referring to the GUID part of the "Reference=" line?
Again, this would be consistent with TransportX.DLL being a VB project
that has been rebuilt outside the project group (solution) while not
maintaining binary compatibility. I also assume from your subsequent
message that you have now found the right GUID. Is that true?
That's right. Once I found a way to get the CLSID (it's a GUID, but
it's called CLSID) from the DLLs I had just built, I was able to get
this whole build working.

What I do now, for each DLL:

1. Check out from source control.
2. If this DLL depends on other DLLs which have just been built, fix
their references in the .vbp by extracting the CLSID, major and minor
versions from the DLLs.
3. Set .vbp file's compatibility to 'project' (value = 1)
4. Set name of compatibility file to empty ("") in .vbp
5. Build the DLL
6. Set .vbp file's compatibility to 'binary' (value = 2)
7. Replace name of compatibility file in .vbp
8. Rebuild the DLL

For the final EXE, which references all the DLLs I've built, I perform
steps 1 and 2, then build.

In the end I ditched my VB6 console app and used the typelib utilities here:

http://confluence.public.thoughtworks.org/display/CCNETCOMM/Tools+for+VB6

To build an interop wrapper for TLBINF32.DLL, as that page notes is
needed, I created a simple project in VS.NET and added a reference to
TLBINF32.DLL, then built the project. There's probably a command line
utility to do this somewhere.

I then had no idea how to get the compilation of the typelib code to
use the interop wrapper. I couldn't find any documentation on the nant
site relating to this, though perhaps it was on their wiki, which was
down when I looked.

After some guesswork, I tried copying the wrapper DLL into
nant-release-directory\bin and edited nant.exe.config, adding <include
name="interop.tli.dll" /> into <task-assemblies> inside <platform
name="win32" default="auto>. This worked!

I would have used the VB project building code which John Cole
provided, but my google search first turned up the typelib code and I
only found the rest later.

I will now have a look to see if I can use some of John's VB handling
code (thanks John!) as mine has a couple of problems:

1. The CLSID of all DLLs is updated, when it may not need to be (BC
may not have been broken). This may or may not be a problem for us.
2. All DLLs are built twice. This wastes about two minutes of build
time, so isn't such a problem.

Cheers,
Rik
Rik Hemsley
2006-04-26 14:00:02 UTC
Permalink
Rick,
Take a look at
http://confluence.public.thoughtworks.org/display/CCNETCOMM/Tools+for+VB6
These are the NAnt/NAntContrib scripts we use to build our VB6 projects.
It includes tasks to fix VBP's when class id's change and to auto-magically
back a vbp to project compatibility and return it to binary when you get
some compile strangeness.
I found your scripts a few hours ago and have used the typelib code to
get this working, so thanks! I was just in the middle of writing a
message to say what I used and how I got it all to build correctly,
which I'll finish this afternoon.

Cheers,
Rik
Foster, Richard - PAL
2006-04-26 14:09:43 UTC
Permalink
Oooh! Thanks for the pointer John/Rik. I hadn't seen any reference to
those scripts on the CCNet list.

I may finally have to get the legacy apps under CCNet too! (I've been
promising myself that I would for over a year now, but simply haven't
had the time to get the build scripts into a form where they would run
under the CCNet service account.)

Regards,
Richard

-----Original Message-----
From: nant-users-***@lists.sourceforge.net
[mailto:nant-users-***@lists.sourceforge.net] On Behalf Of Rik Hemsley
Sent: Wednesday, April 26, 2006 10:00
To: nant-***@lists.sourceforge.net
Subject: Re: [NAnt-users] Building VB6 project group
Rick,
Take a look at
http://confluence.public.thoughtworks.org/display/CCNETCOMM/Tools+for+VB
6
Giscard Biamby
2006-04-27 02:38:40 UTC
Permalink
The method I use for my vb6 projects is a little different.
I will take a look at the thoughworks page to see if some
of their vb6 tools could help me. My method only builds the
.dll's once.

Binary Compatibility:
Each vb6 project has a subfolder called "compat". This
folder holds the current binary compatibility file. The
compat folder and it's .dll are also stored in version
control.
All the .vbp files in the build point to the .dll in
the projec's compat subfolder. Compatibility mode is always
set to Binary Compatibility in the official builds. If
someone wants to break compatibility they do so on their
own machine, and check in the new binary compatibility
reference file along with their code changes.

So the continuous integration process looks like this:

1. CCNet detects change
2. Working folders are deleted
3. Version control is labelled, and code checked out
4. Build order of vb6 projects is determined on the fly
with an app I wrote. A new nant script with calls to <vb6>
task in the proper build order is output.
5. Same app also enforces compatibility is set to "binary"
("2" in the .vbp) and that the compatibleexe is pointing to
the .dll in the compat folder.
6. New nant script with build order is called from build
script
7. Interops are generated for some of the .dll's
8. NUnit tests compiled and run against Interop'ed vb6
.dll's
9. components packaged into .msi
(I should add a step here to update the "compat" subfolders
with the .dll's from the successful build here.

I also have a set in there to generate a image that
graphically displays the dependencies between the vb6
components. You can see an couple examples on my blog:

http://my.dreamfirst.com/blogs/giscard_biamby/archive/2006/04/12/1216.aspx
http://my.dreamfirst.com/blogs/giscard_biamby/archive/2006/04/09/1209.aspx

I've create custom nant tasks <vb6graph> and
<vb6buildorder> for the steps that generate this graph, and
the one that generates the nant script with the correct
build order.

-Giscard
Post by Foster, Richard - PAL
Oooh! Thanks for the pointer John/Rik. I hadn't seen any
reference to
those scripts on the CCNet list.
I may finally have to get the legacy apps under CCNet
too! (I've been
promising myself that I would for over a year now, but
simply haven't
had the time to get the build scripts into a form where
they would run
under the CCNet service account.)
Regards,
Richard
-----Original Message-----
Of Rik Hemsley
Sent: Wednesday, April 26, 2006 10:00
Subject: Re: [NAnt-users] Building VB6 project group
Rick,
Take a look at
http://confluence.public.thoughtworks.org/display/CCNETCOMM/Tools+for+VB
Post by Foster, Richard - PAL
6
-------------------------------------------------------
Using Tomcat but need to do more? Need to support web
services, security?
Get stuff done quickly with pre-integrated technology to
make your job easier
Download IBM WebSphere Application Server v.1.0.1 based
on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid0709&bid&3057&dat1642
Post by Foster, Richard - PAL
_______________________________________________
NAnt-users mailing list
https://lists.sourceforge.net/lists/listinfo/nant-users
"Few are those who see with their own eyes and feel with their own hearts." -Albert Einstein

__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
http://mail.yahoo.com
Foster, Richard - PAL
2006-04-27 13:27:24 UTC
Permalink
Giscard,

I would agree 100% that the mechanism you describe is what *should*
happen. In fact, Our current solution does something almost identical...
only it uses gnu make (instead of NNnt), plus a couple of custom
utilities. As I'm sure you will appreciate, the output from make is less
web-presentation-friendly than Nant. :-)

Unfortunately, speaking from experience, there have been times when the
compatibility files were not appropriately updated in source code
control (including one occasion when Visual Source Safe did something
utterly bizarre with the file), and it has been necessary to perform
exactly the type of manual intervention you describe in a local build
(updating the binary compatibility files), before committing the entire
change set back.

Thanks for the links to your blog. I think management would be very
interested in a more graphical view of the project we inherited (and any
future ones we may inherit). You may be getting more questions from me
soon! :-)

Regards,
Richard

-----Original Message-----
From: Giscard Biamby [mailto:***@yahoo.com]
Sent: Wednesday, April 26, 2006 22:39
To: Foster, Richard - PAL; nant-***@lists.sourceforge.net
Subject: RE: [NAnt-users] Building VB6 project group

The method I use for my vb6 projects is a little different.
I will take a look at the thoughworks page to see if some of their vb6
tools could help me. My method only builds the .dll's once.

[Remainder of message trimmed]

Loading...