Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / VB

GadgetPacker - Windows Gadget Build Tool

4.92/5 (21 votes)
2 Nov 2010CPOL6 min read 77.1K   2.2K  
A simple automated build tool to assist with Windows Gadget development

Introduction

Whilst developing a desktop gadget for Windows 7, it became apparent how much of a pain it was going through the build process. I decided it would be a lot easier to write a simple automation tool, to take care of the necessary steps. This would speed up the overall developing and testing phase.

This article does not cover in detail the whole desktop gadget development process, or go into detail about the code libraries used.

The purpose of this article is to provide members of the community who are developing gadgets, with a tool that they may wish to use to aid them in the process. The article will cover the steps undertaken in the process, and briefly cover how the code does its thing.

The tool was built using Visual Studio 2010 (VB.NET), targeting .NET 4.0 on a Windows 7 Ultimate installation.

Image 1

Background

A desktop gadget is effectively a collection of files and folders, predominantly HTML files, CSS files, image files, JavaScript files and of course, the gadget manifest which defines the gadget. The files and folders can be nested multiple levels deep, or can be a flat single folder full of the necessary files.

The gadget file is a zip file with all the files and folders packed, with the gadget root folder (the one containing the manifest.xml) at the top of the tree, and all other documents relative to this folder.

When you make changes to the source code for the gadget, you must go through a process of packaging and installation, in order to test the gadget.

The steps required to package a gadget are:

  • Remove old .gadget file from the development folder.
  • Create a zip file containing all the files, easily done by selecting all files and folders and then 'Send to Compressed (zipped) folder'.
  • Rename the zip file to a .gadget extension.
  • Execute the gadget file to install.

Now, as you could imagine, having to do this repeatedly to test the gadget changes would become very tiresome, all that left click, right click, send to, renames, etc., in explorer will eventually drive you potty. Time to get automation to do the business!

Using the GadgetPacker

The tool does not require any settings to be set, it has no options, and is quite simple in its design. The tool has been written in such a way, if you are developing more than one gadget, you can simply copy and paste the application's EXE into each development folder.

What you need to do is copy the GadgetPacker.exe file to the development folder, and rename it to whatever your gadget is going to be called. E.g. if your final gadget name will be SomeGadget.gadget, then you rename GadgetPacker.exe to SomeGadget.exe, that is it.

When you are ready to build the gadget, simply double click/run the GadgetPacker EXE. It will then go through the steps identified below to build the gadget.

There is only one hidden feature, and that is an 'AutoClose' override, and you can see this has been activated in the screen shot of the application above. All you need to do is press the Shift key while the application is running, and that will prevent the application from closing, allowing you to read the log should you so desire. There is also a 'ReRun' button that can be pressed, should you wish to manually restart the process once you have blocked the 'AutoClose'.

What Steps Are Taken?

The tool will go through the following steps when building the gadget:

  1. Determine the path of the gadget root, and the appropriate file names for the gadget and temporary build files.
  2. Remove any previous temporary gadget file that might exist (should only occur, if something unexpected crashed the app!).
  3. Carry out a full directory, and sub-directories scan for all folders and files.
  4. Remove the GadgetPacker and any previous Gadget file from the discovered file list.
  5. Create a new temporary zip gadget file.
  6. Add all the files from step #3 to the zip file, including a mime type lookup for each one from the Windows Registry.
  7. Copy the temporary gadget zip to the final gadget file name, overwriting if one already exists.
  8. Delete the temporary gadget zip
  9. Execute the gadget file to initiate Windows installation of the gadget.
  10. If shift has not been pressed then exit the tool, otherwise don't exit.

Points of Interest

  1. The directory scan is a straightforward recursive loop that populates a list<of String> with all the found files:
    VB.NET
    Private Sub Dir(ByVal Path As String)
    
        Dim files As New List(Of String)
        Dim dirs As New List(Of String)
    
        files = Directory.GetFiles(Path).ToList
        dirs = Directory.GetDirectories(Path).ToList
    
        For Each item As String In files
            buildFiles.Add(item.ToLower)            'switch everything to lower case
            WriteMessage(item, True)
        Next
    
        For Each item As String In dirs
            Dir(item)
        Next
    
    End Sub
  2. The System.IO.Packaging namespace found in WindowsBase DLL, contains the necessary classes for creating and handling zip files. The routine below is how each file is added to a newly created zip:
    VB.NET
    Private Sub buildGadget()
        WriteMessage(String.Empty, True)
        WriteMessage("Build Gadget File.........", True)
    
        Dim progressStartVal = ProgressBar.Value
        Dim progressTargetVal = 90
    
        Dim fileCount As Integer = 0
        'Create the temp package
        Using zip As ZipPackage = ZipPackage.Open(zipFilePath + "\" + _
    	zipFileNameTemp, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None)
    
            'Process each part
            For Each item As String In buildFiles
                'Take each file, create the relevant info for the zip file
                Dim partUri As Uri = PackUriHelper.CreatePartUri(New Uri(getURI(item), _
    		UriKind.Relative))
                WriteMessage("Adding: " + partUri.ToString, True)
    
                'Create the package part
                Dim zipPart As ZipPackagePart = _
    		zip.CreatePart(partUri, getMimeType(item))
    
                'Copy the Source data to the package part
                Using fileStream As New FileStream(item, FileMode.Open, FileAccess.Read)
                    CopyStream(fileStream, zipPart.GetStream())
                End Using
    
                fileCount += 1
    
                ProgressBar.Value = ((progressTargetVal - progressStartVal) * _
    		(fileCount / buildFiles.Count)) + progressStartVal
    
            Next
    
        End Using
    
        WriteMessage("Added " + fileCount.ToString + " item(s) to gadget.", True)
    
    End Sub

    One thing to note with using the packing, is that if you open up the zip file with explorer, you will notice a file named [ContentTypes].xml, this contains all the mime types that have been identified. This file is added automatically, and cannot be removed. However, it does not have any bearing on the overall gadget. Based on this, I have not made any attempt to remove it, or find other zip libraries to use in place of the one that is part of the framework.

  3. The mime type look up is performed by taking the extension of each file, and performing registry lookup. If a particular extension cannot be located, then a customer mime type is used. These are recorded in the [ContentTypes].xml file, and therefore has no impact for the purposes of the gadget. The code that performs the lookup is shown below:

    VB.NET
    Private Function getMimeType(ByVal path As String) As String
    
        Dim mime = String.Empty
        Dim ext = System.IO.Path.GetExtension(path).ToLower()
    
        Dim rk As Microsoft.Win32.RegistryKey = _
    	My.Computer.Registry.ClassesRoot.OpenSubKey(ext)
    
        Try
            mime = rk.GetValue("Content Type").ToString()
        Catch ex As Exception
            WriteMessage("ERROR: Cannot determine content type for: _
    	" + path + "; Setting to contentype/unknown", True)
            mime = "contenttype/uknown"
        End Try
    
        Return mime
    
    End Function
  4. The gadget installation process is initiated by using Process.Start("gadgetpathandname"), this then causes a Windows to prompt the user to confirm they wish to install the gadget. If the gadget already exists, Windows will also prompt the user if they wish to overwrite it.

    Image 2

    Image 3

  5. You will notice in the code snippets, WriteMessage(), this is a simple helper used to update the log entry on the form, it has two signatures, one that simply appends the message, the other that adds a CRLF sequence.

References / Further Reading

Whilst developing the gadgets and coming up with the tool, here are some web locations that may be of further interest;

What Next

Well, there is nothing else to add really, the tool is free to be used. If you have any ideas, etc., let me know.

Now I can get back to developing my first desktop gadget, so hopefully, one day, there will be an article for it!

Thanks for reading...

History

(Version numbers relate to code changes, not article revisions.)

  • V1.0 - 3rd November 2010: Initial article and code release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)