Aug 8, 2010

How to Build VB6 Apps with TFS Team Build 2010

So you’ve got yourself a nice, shiny, new TFS 2010 server and you’re using its build automation features to build your .NET code but you also have some, shall we say it, “legacy” VB6 code laying around that you have to keep alive.  You’ve retired source safe and installed the MSSCCI provider TFS 2010 so TFS is your source repository but now you want the build server to build your VB6 code just like it does for your .NET code.

Here’s how to get VB6 applications built using TFS 2010:

Preliminary Steps

1. Go to your build templates folder in source control and make a copy of DefaultTemplate.xaml.  Call it VB6BuildTemplate or something similarly memorable.

2. Open up the new template and find the “Compile the Project” activity sequence.  For reference it’s roughly located in “Compile, Test and Associate Changesets and Work Items” > “Compile and Test” > “Compile and Test for Configuration” > “If BuildSettings.HasProjectsToBuild” > “Compile the Project”

3. Find the “Run MSBuild for Project” activity and delete it.  We’re going to replace that with our own tasks.

Ensure the Output Directory Exists

When you that MSBuild activity runs to compile your .NET projects the output locations are created for you automatically but since we’re not using MSBuild we don’t have that luxury for our VB6 compilations so we have to create the folder ourselves.

Start by dragging an “If” Activity into the sequence

image

Then drag a CreateDirectory task (from Team Foundation Build Activities) into the “Then” section as shown

image

Now the point of this is to check if the outputDirectory has already been created and to create it if it hasn’t.

Set the Condition for the If Activity to: Not System.IO.Directory.Exists(outputDirectory).

Set the Diirectory property of the createDirectory to outputDirectory

image

For maintainability, rename the activities in the designer as well so that you can better understand what is happening.

image

By the way, if you are sure the directory doesn’t get created earlier in your process then you can drop the if activity and just place the createDirectory activity into the flow directly.

Ensure a Log Directory Exists

When we run the VB6 compiler in a build we need to capture the log output to a text file otherwise VB will want to try and open a dialog box telling us there was a compiler problem and want us to click OK. Unfortunately when running unattended, there is no UI and we will never see a window to click the link on.

We’re going to place our log file output in the drop location so that we can easily access it once the build is complete.

Create another if task (or copy/paste) from the previous step and ensure that we use logFileDropLocation instead of outputDirectory.

image

Call the VB6 Compiler

Now drag an InvokeProcess activity into the workflow and set it up as follows:

DisplayName VB6 Compiler
FileName Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86) + "\Microsoft Visual Studio\VB98\VB6.exe"
Arguments "/make """ + localProject + """ /out """ + logFileDropLocation + "\vb6.log"" /outdir """ + outputDirectory + """"
Result VB6Result

 

Note that the VB6Result variable will likely to show up with a warning until you create it as a variable in your workflow. So on the workflow create the variable with a type of Int32 and a scope of “Compile the Project”

If you wish, you can also send stdOutput and errOutput from the InvokeProcess tasks to the build log using the WriteBuildMessage and WriteBuildWarning tasks.  For each of these use the appropriate std/errOutput variables as the values for the Message property, though with the VB6 compiler you’re unlikely to see any messages since we’re sending output to the log file.

The workflow should now look something like this:

image

Check the Compiler Result

Finally we need to check if the compile passed or not.  If it fails we will get a non-zero result back from InvokeProcess

If we don’t check this then the build process just assumes things work and continues on it’s merry way. so add another “If” Activity to the flow and in the Then part add a “Throw” Activity from the Error Handling group.  Set the Throw Activity’s Exception property to “New Exception” and the Condition on the “If” activity to “VB6Result <> 0”.

image

Don’t forget to rename the activities to help you diagnose any problems.

Use It in a Build

Finally, save your workflow, check it in to source control (in the BuildProcessTemplates folder) and then create a build definition using the new template.

Trigger the build and check the compilation results.  Everything should now work as expected.  Now all you need to do it retire that VB6 code :-)  Good luck with that!

17 comments:

  1. Hi,

    How do i fill the "localProject" var with every project?

    Add it to the definition like a .sln file?

    ReplyDelete
  2. It's exactly I needed.
    Thanks a lot for providing this great guidance about building VB6 applications with TFS team build 2010.

    ReplyDelete
  3. It is really helpful guideline for use. I try to use this before it but I didn’t know about this process and not got succeed but now this process it is very easy to work with this great guidance.

    ReplyDelete
  4. I have heard that TF build 2010 does not support the compile for vb 6 application. We need to install the compiler for vb6.
    I just want to know is it really true?

    ReplyDelete
  5. This is definitely a topic thats close to me so Im happy that you wrote about it. Im also happy that you did the subject some justice. Not only do you know a great deal about it, you know how to present in a way that people will want to read more.

    ReplyDelete
  6. Thank you Richard, I did the same and everything is working fine; I'm able now to build all of my legacy apps.
    One strange thins is if I will queue a build I will get a result EXE not working fine (collapse), if I'll do the build from VB6 IDE, or from the command line (on the same build server) I'll get a working fine app.
    Please advise!

    ReplyDelete
  7. Good luck retiring that code, indeed. Good blog post!

    ReplyDelete
  8. I really appreciate of your self for the helpful information you have shared. I find this information very useful and it has considerably saved my time.

    ReplyDelete
  9. This works for me when compiling a vb6 exe, but when I try to compile a dll with project or binary compatibility set - I get an error. Is there a command line setting I can use?

    ReplyDelete
  10. Isn't using VB6 Task in MSBuild Extension Pack make it much easier?

    ReplyDelete
  11. Has anyone tried building .net solutions which have references to .tlb files?. Building a .Net assembly with a reference to interop dll works just fine, but not with tlb's generated from .net assemblies.

    ReplyDelete
  12. So you’ve got yourself a nice, shiny, new TFS 2010 server and you’re using its build automation features to build your .NET code but you also have some, shall we say it, “legacy” VB6 code laying around that you have to keep alive. You’ve retired source safe and installed the MSSCCI provider TFS 2010 so TFS is your source repository but now you want the build server to build your VB6 code just like it does for your .NET code.

    WHY DO I WANT TO DO THIS ?

    I HAVE TOTALLY MISSED THE POINT OF THIS - WHAT IS IT FOR ?

    ReplyDelete
  13. I'd call you, quoting 'The Matrix', my personal Jesus Christ.

    Thanks a lot, that's just what I needed.

    ReplyDelete
  14. Thanks for this. Really helpfull.

    But what's about this problem: http://support.microsoft.com/kb/2517589/en-us
    Is there any 'good' solutiuon ?

    ReplyDelete
  15. Thanks for this useful post. I got this working for VB6. But Have u got a post for building visual studio 2008 vcproj projects in TFS2010 builds? The problem I have is VC9 is the production code and at the moment, TFS build fails as it keep prompting for conversion, I guess to vcxproj. Please email me at byu@easyscreen.com if more details required. Thanks in advance

    ReplyDelete
  16. For Preliminary Step 3 "Find the 'Run MSBuild for Project' activity and delete it." I recommend you just wrap it in an If activity with a condition like 'System.IO.Path.GetExtension(localPath) = ".vbp"' so the template can support VB6 in addition to its existing behaviour.

    ReplyDelete
  17. I am really indebted to you for writing this blog post and saving a mere mortal like me. Your saved me from a great deal of ordeal. Many thanks.

    ReplyDelete