Click here to Skip to main content
Email Password   helpLost your password?

Table of Contents

Introduction

This article presents a versatile way to zip up Visual Studio (VS) solutions, projects, and/or any selected items in the Visual Studio Solution Explorer window, directly to a zip archive. The approach used is, in general, different from that provided by other solutions to this problem. This addin uses the Visual Studio automation object (EnvDTE namespace) to enable it to decide what project items are to be included in the resulting Zip file. This approach has the following advantages:

The downside to this approach is:

Background

Being in the contracting game requires us to program on client sites, and often to work with the same code off-site. One way to backup the code efficiently is to provide Zip file functionality directly in the VS IDE, and the obvious way to do this is to implement the addin which works directly with the VS automation object and the EnvDTE.Solution, EnvDTE.Project, and EnvDTE.ProjectItem objects for the currently-loaded solution.

There are essentially two components to this addin:

To use #ziplib in your application, simply add a project reference to the .NET module ICSharpCode.SharpZipLib.dll in your VS.NET project and start hooking up the #ziplib objects.

Installing the Addin

The Windows Installer provides a standard Windows MSI module to install the ZipStudio addin for Visual Studio. Simply extract the files from ZipStudio_inst.zip to a folder and run setup.exe. When you run VS, a menu for the addin will appear in the Visual Studio 'Tools' menu. The addin menu will contain an icon and the menu text ‘Add to Zip file..’. Initially, the menu is disabled until a solution is loaded (or created) in VS. Select some items in the VS Solution Explorer and click the menu item. The Zip Studio window shown in Figure 1 below will appear.

Please note that if the addin is repeatedly installed/un-installed, it may be not appear to be installed and the addin menu may not appear even though the installation executed successfully. In this case, quit all running instances of Visual Studio and execute the file RecreateCommands.reg which is included in the ZipStudio project. The file consists of the following text:

REGEDIT4
[HKEY_CURRENT_USER\SOFTWARE\Microsoft\VisualStudio\7.1\PreloadAddinState]
"ZipStudio.Connect"=dword:1

If you now run Visual Studio the menu should appear. The registry setting in the file ensures that the addin is preloaded when Visual Studio starts up.

How it works

Figure 1 below shows the ZipStudio window as it appears in the Visual Studio IDE.

Figure 1: The ZipStudio Addin window as it appears in Visual Studio

The following user-interface controls can be seen:

Zip File Path

This text box provides the file path of the Zip file that will be created (or updated). The default is the same path as the current solution file (obviously with a .zip instead of a .sln extension). This name can be set to whatever valid file path you like. The '..' button to the immediate right of the file path text box can be clicked to browse for the Zip file.

Included Files Options

Included File List View

The list view shows all the files that will be included in the Zip file. The list can be sorted by any of the ‘Filename’, ‘Filepath’, or ‘Date Modified’ columns by clicking on the respective column headers.

Save Full Path Info

Setting this option works similar to the WinZip option with the same name – The full paths of the files are saved but does not include the actual drive letters. The full path ‘D:\ZipStudio\ZipStudio.cs’ is stored as ‘\ZipStudio\ZipStudio.cs’.

If this option is not set, the addin will attempt to save the file paths relative to a common root directory for all the files in the list. In the following set of files with file paths:

the addin will attempt to find a root path for the files and because the files are on different drives, the full paths for the files will in fact be saved. If only the second and third file are part of the list, the common root path will be ‘D:\ZipStudio’, so the path for the solution file will be ‘ZipStudio.sln’ and ‘ZipStudio\ZipStudio.cs’ for the C# file.

Save Settings

If this option is set, the Zip filepath, and the Zip file group options (described below) are saved as part of the VS solution file. This may be a problem if the solution is shared by multiple users or is controlled by a source-control system such as Visual Source-Safe. To ensure that this does not occur, keep this option un-selected.

Add Only Modified Files

When the addin is started up Visual Studio, it flags the current date/time. During the session, as files are edited, their modified date/time stamps are more recent than the addin startup time. Setting this option allows only these recently modified files to appear in the included file list.

Add Miscellaneous Files

Visual Studio maintains a list of files open in the editors in an internal project with the UniqueName ’<MiscFiles>’. This project does not have a file path and is not saved. By setting this option, all files that are open in VS that are not part of any project or solution files can also be included in the Zip file. Setting this option unchecked will ensure that only files which are required for the VS Solution to load and build successfully are included.

Reset File List

Any files manually removed in the ‘Remove Selected Items’ function below, are added back into the list of files included in the Zip file by clicking this push-button.

Remove Selected Items

The user has the opportunity to remove any files from the included list, by selecting them and then clicking this push-button. Any files so removed can be re-added by clicking the ‘Reset File List’ push-button.

Zip File Options

Open Folder After Creation

Setting this option will open the containing folder for the Zip file in the File Explorer and set the file selection to the Zip file after the file is created.

Shell Open Zip File

Setting this option will open the Zip file with the application associated with the .zip extension.

Create Zip File

Clicking this push-button creates the actual Zip file.

Using the code

The source-code for this addin is provided in the file ZipStudio_src.zip. Extract the files to a folder of your choice, ensuring that the 'Use folder names' option is set (assuming that you are using WinZip). To build the , open ZipStudio.sln in VS. Please note that the addin was originally built in VS.NET 2003 and that the Setup project ZipStudioSetup.vdproj has registry settings which will only work for VS.NET 2003.

The following is provided to assist your understanding when working through the source code.

In the DTE object, the Solution object consists of a Projects object, which is a collection of Project objects. In turn, a Project object consists of a ProjectItems object, which is a collection of ProjectItem objects. A ProjectItem object provides a set of file paths associated with the project item. As far as can be ascertained, a single file path is used for every project item.

The basic code for starting the file selection for inclusion in the Zip file is as follows:

if(this.DTE.SelectedItems.Count > 0)
{
    for(int i = 1; i <= this.DTE.SelectedItems.Count; i++)
    {
        SelectedItem item = this.DTE.SelectedItems.Item(i);
        if(item.Project == null)
        {
            if(item.ProjectItem == null)
            {
                Solution solution = this.DTE.Solution;
                // Get the solution files...
            }
            else
            {
                // Get the project item files...
            }
        }
        else
        {
            if(item.ProjectItem == null)
            {
                // Get the project files...
            }
        }
    }
}

A file path for every possible item can be found as follows:

string filePath = null;
if(Item is Solution) 
{
    filePath = ((Solution)Item).FullName;
}
else
{
    if(Item is Project)
    {
        filePath = this.GetProjectFullName((Project)Item);
    }
    else
    {
        if(Item is ProjectItem) 
        {
            filePath = ((ProjectItem)Item).get_FileNames(1);
        }
    }
}

In the code above, special handling was required to get the correct file path for the Project object: a combination of the Project.FullName and Project.UniqueName had to be used. The reason is that every project type except the Deployment project (.vdproj) correctly reports the file path in the FullName member. The deployment project does not specify the file extension. However, it does so in the UniqueName member, but this value seems to be either a URI or a relative path. The following method fixes that bug by combining the two members to provide the correct value:

private string GetProjectFullName(Project Project)
{
    string filePath = Project.FullName;
    // Find the file extension of the project FullName.
    int extIndex = filePath.LastIndexOf('.');
    string filePathExt = 
      (extIndex > 0) ? filePath.Substring(extIndex + 1) : "";
    // Find the file extension of the project UniqueName.
    extIndex = Project.UniqueName.LastIndexOf('.');
    string uniqueExt = 
      (extIndex > 0) ? Project.UniqueName.Substring(extIndex + 1) : "";
    // If different use the UniqueName extension.
    if(filePathExt != uniqueExt)
    {
        // If the FullName does not have an extension,
        // add the one from UniqueName.
        if(filePathExt == "") filePath += "." + uniqueExt;
        // Else replace it.
        else filePath = filePath.Replace(filePathExt, uniqueExt);
    }
    return filePath;
}

The following code snippet shows the method used to open File Explorer, navigate to the folder containing Zip file, and select the Zip file:

..
string cmdLine = "/select,\"" + ZipFilePath + "\"";
Process.Start("explorer.exe", cmdLine);
..

The following code snippet shows the method used to open the Zip file using the application associated with the Zip file extension:

..
Process.Start(ZipFilePath);
..

If you follow the source-code, you will realize that it is relatively simple. The most difficult part was to code for the exceptions (bugs?) that the different projects exhibited. The InfoPath project (.ipproj) does not appear to implement the ProjectItem.SubProject or the Project.UniqueName members, and any attempt to address these member results in an exception being thrown. The way around this is to place a try..catch block around the code that uses those constructs.

A Hashtable object was used to collect the include files and is keyed by the file paths. This allows 'no-brainer' adding of items while ensuring that all items are added once only. If you recall the rule-set that is applied in adding files to the Zip file, it is obvious that implicitly many items can be selected more than once.

The performance of the addin is very good, allowing the addin to actually run the method that collects the files every time the menu has to be updated. In the case where no files are effectively included, the menu item is disabled in the QueryStatus method of the addin.

Points of Interest

This article does not discuss the infra-structure code required to get the addin to behave correctly or appear presentable in the VS environment. The addin implements the following features which are not discussed in this article:

The following are regarded as useful modifications to this addin:

History

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralVisual Studio 2008
Cory R Stein
4:12 13 Oct '09  
Do you know if you plan to update this to support Visual Studio 2008?
GeneralVS2005 installation
piotr_fe
15:20 1 Jan '07  
It is not installing when My documents are in the server.
Please use following function for creation of the installation path:

function name: AddSlashIfNecessary
action: adds slash for network path of the MyDocuments folder

BTW: Great tool, but I cant install Frown



Piotr
GeneralThanks and suggestions
peterchen
12:01 19 Nov '06  
Nice, sleek, functional Smile

I'm using it for making regular backups of the solution (poor mans source control)

Two ideas:

(1) allow an automatic timestamp or sequence number for the name
e.g. if I enter c:\arc\mylib%TIME%.zip, replace %TIME% with a time stamp each time you zip. %N% could be replaced with a sequential number (001, 002, ..) - jsut create the first file that isn't there.

(2) [OK] does create zip & close, [Cancel] does cancel. 8Avoids having to click two buttons)

I can think of more, but I don't want to be (to much of) a pain... Wink





Developers, Developers, Developers, Developers, Developers, Developers, Velopers, Develprs, Developers!
We are a big screwed up dysfunctional psychotic happy family - some more screwed up, others more happy, but everybody's psychotic joint venture definition of CP
Linkify!|Fold With Us!

QuestionHow do I add referenced DLLs to the zip [modified]
blackbirdway
7:19 23 Aug '06  
I zip up all the files in the solution, put it on another machine, then launch the solution file. It is missing references to DLLs with copy local set to true. How can I get the DLL's included into the zip files?

Also, I want to add a checkbox that, when checked, would allow me to add ALL the files in the solution to the zip. Where do I modify the code to get this done?
GeneralZipStudio 2005 available - for Visual Studio 2005!
Willem Fourie
9:11 24 Nov '05  
Just a quick port of ZipStudio 1.10 to install and run on Visual Studio 2005.

I will provide a bug-fix release and updated article as soon as I can.

To download ZipStudio 2005, go to Willem's Blog.

Willem
QuestionDeployment project not included
CBoland
10:11 15 Nov '05  
Nice add-in!

I don't see the deployment project for my solution in included files list. Am I missing something, or is this by design?

AnswerRe: Deployment project not included
Willem Fourie
22:25 15 Nov '05  
It is there Smile.

If you extract the ZipStudio_src.zip file (downloadable from this article) using the 'Use folders' option, then the deployment (setup) project is in the {target-dir}\ZipStudio\ZipStudioSetup folder. The project file is named ZipStudioSetup.vdproj.

Willem
GeneralRe: Deployment project not included
CBoland
5:42 16 Nov '05  
My apologies, Willem, I wasn't clear. I'm referring to the deployment project in the solution that I am zipping up.
GeneralRe: Deployment project not included
Willem Fourie
18:13 16 Nov '05  
Apologies for my confusion...

I need some more info. Most of the deployment projects that are part of the solution are added to the zip file - case in point - if you run ZipStudio on its own solution, the ZipStudioSetup project is added.

No specific exclusion of projects are done - all I can think is that when ZipStudio enumerates the projects in solution object provided by VS, that the particular project is not in that collection.



Willem
GeneralUpdate for VS2005
staceyw
16:00 22 Aug '05  
Any chance you could update this for VS2005. I don't see anything under tools. TIA!

--
William Stacey, MVP
http://mvp.support.microsoft.com
GeneralRe: Update for VS2005
Willem Fourie
22:29 22 Aug '05  
I'm planning an update for VS2005, as well as a bug-fix/feature extension version update for both VS2003/5 in the near future.

Watch this space!

Willem
Generalroot folder determination bug
DLKJ
20:42 5 Oct '04  
I have discovered a bug in the root folder determination. Here is a description of my folder structure.

/root/common - this is where I keep common components
/root/proj - this is where the project source is. This is also where the sln file is.

Correct operation should not include the 'root' in the zipfile. However, my testing shows that it does.

By the way, great tool. I look forward to using it. However, this bug makes it rather irritating.
GeneralRe: root folder determination bug
Willem Fourie
1:50 7 Oct '04  
Alas, you are correct Cry. It works correctly when all project directories are rooted from the solution directory, but not in the case you mentioned.

Consider it fixed (in the next release), unless you want to fix it yourself now - the source code is fairly innocuous....

Thanks for the bug report!

Regards,

Willem
GeneralRe: root folder determination bug
DLKJ
3:48 7 Oct '04  
I'll look forward to the next release then.

Actually I did take a look at the codes to try and fix it but couldn't figure it out. I'm a C++ programmer so C# is a bit foreign to me. Perhaps I'll give it another shot later on.

Anyway, if I do manage to fix it, I'll post the patch here.

A possible improvement is in the selection of the files to zip. I almost always want to zip the entire solution. However, I have to make it a point to switch to the file view and select the solution first. This is a little troublesome for me.
Perhaps adding a combobox selection for solution, each project and a 'selected files' would give flexibility here.
GeneralSUO Files
Shawn Carroll
3:33 22 Jun '04  
Hey,

Great little tool here. I think I'll be using this one a lot. I was wondering if it is possible to somehow save the SUO files with the solution. Currently my project depends on it (I have specified paths) and would really find that usefull.

Thanks again for the great tool.
Shawn
GeneralRe: SUO Files
Willem Fourie
4:59 23 Jun '04  
Hi Shawn

The SUO file is not seen as part of the VS Solution set and does not appear in any of the Solution or Project collections. I tried to add it Red faced as a solution-item hoping that this would work and then automatically be included as part of the Zip-file. Of course VS refused to add the file! Eek!

At the solution level, you do not have the 'Show All Files' option - so adding it via this route also does not work.

The only option is to modify the source-code. The best place to do this is in the GetSolutionFiles(..) method (about line 179 of Addin.cs). It seems as if only one SUO file is created for every solution-file (.sln). If this is true, then the
Solution.FullName can be used and a path created changing the extension from .sln to .suo, and then added to the include file list. Although this entails a change to the FileItem class to handle pure path string objects, this should be relatively simple to do.

I think this option is a useful addition to the addin. If you can wait and/or don't want to change the code yourself, I will include this in the next release of this addin.

Thanks for the useful input.

Regards, Willem
GeneralVisual Assist X + ZipStudio
scatter
17:31 17 Jun '04  
If you have Visual Assist X loaded, it will create a "Tools" menu. Evidently, ZipStudio connects to the first Tools menu it finds. If you don't see ZipStudio in the Tools menu, look at the Visual Assist X Tools menu.
GeneralRe: Visual Assist X + ZipStudio
Willem Fourie
0:11 18 Jun '04  
scatter wrote:
If you have Visual Assist X loaded, it will create a "Tools" menu. Evidently, ZipStudio connects to the first Tools menu it finds. If you don't see ZipStudio in the Tools menu, look at the Visual Assist X Tools menu.

Very useful comment - thanks!Smile This issue of finding the addin menu item after installing the addin has been the single biggest issue that users have had up to now. I will address this in the next update of this addin.

Regards, Willem
GeneralZip Studio Version 1.10
Willem Fourie
3:33 15 Jun '04  
I have updated the article and addin. Thank you for all comments on the prior version (Version 1.00). Hopefully a lot of the problems and annoyances have been fixed.

The most up-to-date version of the article and addin source/install files can be found at:

http://home.telkomsa.net/businessware/DotNet/Development/ZipStudio/Article/Article_web.htm

Regards, Willem
GeneralRe: Zip Studio Version 1.10
larry_beck
19:04 17 Jun '04  
Willem - very nice, very very useful add-in!!
GeneralRe: Zip Studio Version 1.10
Willem Fourie
0:13 18 Jun '04  
Big Grin Appreciate the feedback! Thanks!

Regards, Willem
GeneralRelative vs. Explicit Paths
Patrick DellEra
8:25 15 May '04  
To test ZipStudio, I used it on the ZipStudio project. In the zip file created, the paths are explicit ("e:\Visual Studio Projects\ZipStudio\...") instead of relative ("ZipStudio\..."). The original zip file dl'd from here has relative paths, which is what you want.

Any thoughts on why the explicit paths and how to ensure relative paths?

-Patrick
GeneralRe: Relative vs. Explicit Paths
Willem Fourie
11:09 15 May '04  
Patrick,

Thanks for pointing this out.

The paths are shown explicit in the ZipStudio window as they refer to the files that are included in the Zip file.

If you open the created Zip file in WinZip, the paths are the full folder paths without the drive letter and first '\' specified.

For example:

If the folder for the ZipStudio solution is 'E:\Visual Studio Projects\ZipStudio\', then in WinZip the paths are shown as 'Visual Studio Projects\ZipStudio\' as you would expect, and which works fine.

The fact is you are right: I save the files with absolute path names in line 32 of 'ZipArchive.cs':

ZipEntry zipEntry = new ZipEntry(fileToZip);

You can change that to remove the drive letter and first '\' by stripping it out of the string variable fileToZip, which at that point contains the absolute path. This should obviously be done before this line of code is executed.

Hope this works for you.

Regards, Willem
GeneralRe: Relative vs. Explicit Paths
Patrick DellEra
11:24 17 May '04  
Willem Fourie wrote:
You can change that to remove the drive letter and first '\' by stripping it out of the string variable fileToZip, which at that point contains the absolute path. This should obviously be done before this line of code is executed.

Alas, it's not quite that straight forward. Consider: By convention UserA creates her C# projects in e:\projects\csharp. UserB always creates all of her projects in f:\dotnet projects\. When UserA zips up a project called "Foo", using the method above, the paths all would begin projects\Foo\. When UserB unzips the project into her project folder, she ends up with f:\dotnet projects\projects\csharp\Foo, not what she wants.

I've minimally modified ZipStudio to use paths relative to the solution's full name. The modifications use API calls to PathRemoveFileSpec, PathCommonPrefix, and PathStripPath.

I hope you find the modifications useful.

-Patrick
-----------
File: IFileArchive.cs
Description:
Changed definition of CreateArchive to include a parameter for the project file's full name as the root for relative paths.
From:
    void CreateArchive(string ArchiveFilePath, string[]FilePaths);
bTo:b
PRE lang=cs void CreateArchive(string ProjFile, string ArchiveFilePath, string[] FilePaths); File: ZipArchive.cs
Description:
Added using declarations to include interop and stringbuilder
From:
    using FileArchive;
using ICSharpCode.SharpZipLib.Checksums;
bTo:b
PRE lang=cs using FileArchive;
using System.Runtime.InteropServices;
using System.Text;
using ICSharpCode.SharpZipLib.Checksums; File: ZipArchive.cs
Description:
Added constant and import declarations for path manipulation functions.
From:
    public class ZipArchive : IFileArchive
{
#region IFileArchive Members
bTo:b
PRE lang=cs public class ZipArchive : IFileArchive
{
const Int32 MAX_PATH = 260;
[DllImport("shlwapi.dll")]
public static extern Int32 PathCommonPrefix(
[In] String pszFile1,
[In] String pszFile2,
[Out] StringBuilder pszPath
);
[DllImport("shlwapi.dll")]
public static extern Int32 PathRemoveFileSpec([In,Out] StringBuilder pszPath);
[DllImport("shlwapi.dll")]
public static extern void PathStripPath([In,Out] StringBuilder pszPath);

#region IFileArchive Members File: ZipArchive.cs
Description:
Changed definition of CreateArchive and CreateZipFile to include a parameter for the project file's full name as the root for relative paths.
From:
    public void CreateArchive(string ArchiveFilePath, 
string[] FilePaths)
{
this.CreateZipFile(FilePaths, ArchiveFilePath);
}
#endregion
private void CreateZipFile(string[] FilesToZip, string ZippedFile)
bTo:b PRE lang=cs public void CreateArchive(string ProjFile, string ArchiveFilePath,
string[] FilePaths)
{
this.CreateZipFile(ProjFile, FilePaths, ArchiveFilePath);
}
#endregion
private void CreateZipFile(string ProjFile, string[] FilesToZip, string ZippedFile) File: ZipArchive.cs
Description:
Modified the ZipEntry object to be constructed with the relative file name (by calling new function MakeRelativePath)
From:
    ZipEntry zipEntry = new ZipEntry(fileToZip);
bTo:b PRE lang=cs ZipEntry zipEntry = new ZipEntry(MakeRelativePath(ProjFile, fileToZip)); File: ZipArchive.cs
Description:
Added new private function MakeRelativePath
From:
 To:b
PRE lang=cs private string MakeRelativePath(string RootFile, string RelatedFile)
{
// return value
String RelativeFile = "";

try
{
// Extract the RootFile's folder name...
StringBuilder str = new StringBuilder(RootFile);
String RootFolder = "";
// Remove the file name from the path...
Int32 nRet = PathRemoveFileSpec(str);
if( nRet != 0 )
{
// Now get the solution's folder...
PathStripPath(str);
RootFolder = str.ToString();
}

str = new StringBuilder(MAX_PATH);
nRet = PathCommonPrefix(
RootFile,
RelatedFile,
str
);
if( nRet != 0 )
{
// If the entire file spec is in common, we're looking
// at the RootFile.
if( nRet == RelatedFile.Length )
{
str = new StringBuilder(RelatedFile);
PathStripPath(str);
RelativeFile = RootFolder + @"\" + str.ToString();
}
else
{
RelativeFile = RootFolder + RelatedFile.Substring(nRet);
}
}
}
catch
{
// ignore and continue
}
return RelativeFile;
} File: AddIn.cs
Description:
Added solutions's full name as a parameter in creating ZipForm.
From:
    ZipForm zipForm = new ZipForm(this.GetFilePaths(Files), 
bTo:b
PRE lang=cs ZipForm zipForm = new ZipForm(this.DTE.Solution.FullName,
this.GetFilePaths(Files), File: AddIn.cs
Description:
Added new private string to hold solution's full name.
From:
    private ZipFormData _data = null;
public ZipFormData Data
bTo:bPRE lang=cs private ZipFormData _data = null;
private string _SolutionName;

public ZipFormData Data File: AddIn.cs
Description:
Added support for caching the solution's full name.
From:
    public ZipForm(string[] FilePaths, ZipFormData Data)
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
_columnSorter = new ListViewColumnSorter();
bTo:b
PRE lang=cs public ZipForm(string SolutionName, string[] FilePaths, ZipFormData Data)
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
_SolutionName = SolutionName;
_columnSorter = new ListViewColumnSorter(); File: AddIn.cs
Description:
Added parameter to call to CreateArchive.
From:
    archive.CreateArchive(_data.Value(ZipFormData.DataName.SZPath), 
_filePaths);
bTo:b
PRE lang=cs archive.CreateArchive(_SolutionName, _data.Value(ZipFormData.DataName.SZPath),
_filePaths);

GeneralRe: Relative vs. Explicit Paths
Willem Fourie
21:20 17 May '04  
Patrick

Nice job - it works great - thanks Big Grin! I have only two comments to make:

1. It provides the solution to the extraction/zip'ing functionality with re-rooting of the file locations, as I suggested for enhancements in the article.
2. I would look at using the System.IO DirectoryInfo and FileInfo object class functionality to provide the file path manipulations as in your code. I would like to keep the implementation totally C#/.NET if possible.

I am looking forward to incorporate your modifications in the next update of ZipStudio. I really appreciate the effort you have made with cleaning up the path specification of the item files.

Regards, Willem


Last Updated 15 Jun 2004 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010