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.
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:
- Determine the path of the gadget root, and the appropriate file names for the gadget and temporary build files.
- Remove any previous temporary gadget file that might exist (should only occur, if something unexpected crashed the app!).
- Carry out a full directory, and sub-directories scan for all folders and files.
- Remove the
GadgetPacker
and any previous Gadget file from the discovered file list. - Create a new temporary zip gadget file.
- Add all the files from step #3 to the zip file, including a mime type lookup for each one from the Windows Registry.
- Copy the temporary gadget zip to the final gadget file name, overwriting if one already exists.
- Delete the temporary gadget zip
- Execute the gadget file to initiate Windows installation of the gadget.
- If shift has not been pressed then exit the tool, otherwise don't exit.
Points of Interest
- The directory scan is a straightforward recursive loop that populates a
list<of String>
with all the found files:
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)
WriteMessage(item, True)
Next
For Each item As String In dirs
Dir(item)
Next
End Sub
- 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:
Private Sub buildGadget()
WriteMessage(String.Empty, True)
WriteMessage("Build Gadget File.........", True)
Dim progressStartVal = ProgressBar.Value
Dim progressTargetVal = 90
Dim fileCount As Integer = 0
Using zip As ZipPackage = ZipPackage.Open(zipFilePath + "\" + _
zipFileNameTemp, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None)
For Each item As String In buildFiles
Dim partUri As Uri = PackUriHelper.CreatePartUri(New Uri(getURI(item), _
UriKind.Relative))
WriteMessage("Adding: " + partUri.ToString, True)
Dim zipPart As ZipPackagePart = _
zip.CreatePart(partUri, getMimeType(item))
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.
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:
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
- 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.
- 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