|

Introduction
This is a follow up article to the one that I wrote about decompressing Zip files. With this code you can use the Windows Shell API in C# to compress Zip files and do so without having to show the Copy Progress window shown above. Normally when you use the Shell API to compress a Zip file, it will show a Copy Progress window even when you set the options to tell Windows not to show it. To get around this, you move the Shell API code to a separate executable and then launch that executable using the .NET Process class being sure to set the process window style to 'Hidden'.
Background
Ever needed to compress Zip files and needed a better Zip than what comes with many of the free compression libraries out there? I.e. you needed to compress folders and subfolders as well as files. Windows Zipping can compress more than just individual files. All you need is a way to programmatically get Windows to silently compress these Zip files. Of course you could spend $300 on one of the commercial Zip components, but it's hard to beat free if all you need is to compress folder hierarchies.
Using the code
The following code shows how to use the Windows Shell API to compress a Zip file. First you create an empty Zip file. To do this create a properly constructed byte array and then save that array as a file with a '.zip' extension. How did I know what bytes to put into the array? Well I just used Windows to create a Zip file with a single file compressed inside. Then I opened the Zip with Windows and deleted the compressed file. That left me with an empty Zip. Next I opened the empty Zip file in a hex editor (Visual Studio) and looked at the hex byte values and converted them to decimal with Windows Calc and copied those decimal values into my byte array code. The source folder points to a folder you want to compress. The destination folder points to the empty Zip file you just created. This code as is will compress the Zip file, however it will also show the Copy Progress window. To make this code work, you will also need to set a reference to a COM library. In the References window, go to the COM tab and select the library labeled 'Microsoft Shell Controls and Automation'.
byte[] emptyzip = new byte[]{80,75,5,6,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
FileStream fs = File.Create(args[1]);
fs.Write(emptyzip, 0, emptyzip.Length);
fs.Flush();
fs.Close();
fs = null;
Shell32.ShellClass sc = new Shell32.ShellClass();
Shell32.Folder SrcFlder = sc.NameSpace(args[0]);
Shell32.Folder DestFlder = sc.NameSpace(args[1]);
Shell32.FolderItems items = SrcFlder.Items();
DestFlder.CopyHere(items, 20);
System.Threading.Thread.Sleep(1000);
The sample solution included with this article shows how to put this code into a console application and then launch this console app to compress the Zip without showing the Copy Progress window.
The code below shows a button click event handler that contains the code used to launch the console application so that there is no UI during the compress: private void btnUnzip_Click(object sender, System.EventArgs e)
{
if(txtZipFileName.Text.Trim() == "")
{
MessageBox.Show("You must enter what" +
" you want the name of the zip file to be");
txtZipFileName.BackColor = Color.Yellow;
return;
}
else
{
txtZipFileName.BackColor = Color.White;
}
System.Diagnostics.ProcessStartInfo i =
new System.Diagnostics.ProcessStartInfo(
AppDomain.CurrentDomain.BaseDirectory + "zip.exe");
i.CreateNoWindow = true;
string args = "";
if(txtSource.Text.IndexOf(" ") != -1)
{
args += "\"" + txtSource.Text + "\"";
}
else
{
args += txtSource.Text;
}
string dest = txtDestination.Text;
if(dest.EndsWith(@"\") == false)
{
dest += @"\";
}
if(txtZipFileName.Text.ToUpper().EndsWith(".ZIP") == false)
{
txtZipFileName.Text += ".zip";
}
dest += txtZipFileName.Text;
if(dest.IndexOf(" ") != -1)
{
args += " " + "\"" + dest + "\"";
}
else
{
args += " " + dest;
}
i.Arguments = args;
i.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
System.Diagnostics.Process p = System.Diagnostics.Process.Start(i);
p.WaitForExit();
MessageBox.Show("Complete");
}
Points of Interest
- It's free!
- You can use Windows to create the Zip file instead of an expensive Zip library to work with folder hierarchies.
- Works with or without showing the Copy Progress window.
- Uses the Windows Shell API which has a lot of of interesting Windows integration possibilities.
| You must Sign In to use this message board. |
|
| | Msgs 1 to 25 of 83 (Total in Forum: 83) (Refresh) | FirstPrevNext |
|
|
 |
|
|
i want to know that what is the maximum size that can be zipped by this application. i have a image file of size 5.88Mb and some other files in the Folder, when i zip that folder only up to that file which size is 5.88 mb is zipped and not other files. What i have to Do beacause if a remove that file then it worked fine but not with that file.
Please give me any solution so that all the files of that folder can be zipped.
Thanks Anil Pandey
Anil Pandey
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
This code uses Windows to do the zipping so it can do anything Windows can do. However if you read through the comments of the other posters below you will see where we came up with bug fixes and other enhancements that are not in the article itself. You can also try downloading the version at http://GeraldGibson.net to get a newer version of the code that will probably fix your problem.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Thanks a lot for the app, the app works fine when I try to zip small files, like if I have 3 files each 50K size it works fine, but when I have 3 files (each 50MB) it break up in the middle and do not finish the zipping, I am guessing it has to do something with putting the thread to sleep, I tried changing the sleep time to 10000 from 1000, this time it finishes the zipping but not closing so my application is waiting to hear from this app and freezes, any idea how I can resolve this appreciate your help Sri
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
 |
|
|
Unzip giving following error
Exception.Message: The system cannot find the file specified. STACK TRACE: at Shell32.ShellClass.NameSpace(Object vDir)
Why I am getting this error?
any help appreciated!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
This is a very helpful article, so first and foremost thank you Gerald.
I ran into a problem w/ the code when I tried copying a folder that included blank folders. The blank folders caused an error message.
To avoid this, pass the SrcFldr object directly to CopyHere
ORIGINAL CODE: Shell32.FolderItems items = SrcFlder.Items(); DestFlder.CopyHere(items, 20);
UPDATED CODE: DestFlder.CopyHere(SrcFlder, 20);
This has worked perfectly for me.
Kevin
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Thanks for the update!
If you look through the comments on this article and my other zip article or look at the similiar article at http://geraldgibson.net you will see that another reader and I found the same problem and posted updates in the comments and then made a system that did work with empty folders... however you seem to have accomplished the same thing in about 1/30th the code... oh well thats how it goes sometimes!
Thanks again,
GG
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I can't get this code or any variation to run since the Process.Start call throws an exception that it can't find the file. The Current AppDomain is the folder that I started my app out of and it obviously doesn't have those two executables. How is this supposed to work?
Puzzled.
- Lutz
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I just downloaded the zip file included with this article and there are two zip.exe files in there.. just look around.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I want Password protected zip file is this example support password protedted file?
Shahzad Aslam Software Engineer Softech Systems Limited
Email: shehzadaslam@hotmail.com
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
1. the 2 code examples - are the related somehow ?
2. if i use the shell example and i need to know when the zipping ends, how can i do that? (is there anyway to get the thread name that it makes or something)
thanks
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hello,Thanks for excellent Code Can I ask you 2 question? 1)I don't understand How works Unzip procedure..Can you make an example? 2)I need to know when zip process ends...How can I? Thanks
Carlo Ingrassia
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
Hello. Thanks for making your code available. I don't doubt that it compresses the file. However, I don't see anything in the code that indicates that it is actually compressing the file rather than just copying it. Does the Shell32.Folder.CopyHere method implicitly compress the file being copied?
Thanks again!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
Hi Gerald,
You have created an excellent utility and it is running fine. Can I use this utility on my application? Is it Free?
Thanks,
Gopal
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
100% free. Of coarse if you want to feed my ego by adding a mention of this web page or my website GeraldGibson.Net then all the better!
Thanks for taking the time to try this out and then comment.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
For compressing (and decompressing utilizing both your editorials), I find that it cannot be done. The program crashes. I used your sample code. I compiled it with VS 2003 and 2005 and it crashes when attempting to zip. I created my own code and it also crashes based on the sample codes given in your editorial, but not straight from the source code. I debugged to the point where it crashes. For instance:
byte[] emptyzip = new byte[] { 80, 75, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; FileStream fs = File.Create(AppDomain.CurrentDomain.BaseDirectory + "\\data.zip"); fs.Write(emptyzip, 0, emptyzip.Length); fs.Flush(); fs.Close(); // works
Shell32.ShellClass sc = new Shell32.ShellClass(); Shell32.Folder DestFlder = sc.NameSpace(AppDomain.CurrentDomain.BaseDirectory + "\\data.zip"); // problem Shell32.Folder SrcFlder = sc.NameSpace(textBoxattachment.Text); // WORKS Shell32.FolderItems items = SrcFlder.Items(); // WORKS DestFlder.CopyHere(items, 8); System.Threading.Thread.Sleep(1000);
Anything that the Shell32.Folder looks at a file .zip, it would crash the program. Now if it was a regular folder inserted for the DestFlder, then it would work, no crashes, copyhere works. Inject anything with .zip and it won't work. I have Windows XP w/SP2 and WinRAR registered to take care of .zip files. Don't exactly know why DestFlder fails if it has a pointer at some zip file as the destination. Any ideas?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I remember in the comments in one of the articles that someone had a similar problem caused by not copying a Interop file into the same folder as the app doing the ziping. You may want to look to see if this is the issue you are having.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
When compiling, I see in my debug/release folders that the Interop.Shell32.dll file exists. Shell32 is properly linked in the source code, hence Interop was created, I presume by so. And so does your sample source code too, contains the Interop file. So I'm at the point where I don't know why as it keeps crashing when it looks for the .zip file and won't accept it. Any other ideas?
Gerald Gibson Jr wrote: I remember in the comments in one of the articles that someone had a similar problem caused by not copying a Interop file into the same folder as the app doing the ziping. You may want to look to see if this is the issue you are having.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
What I just did was went to where I keep my sample for this project and copied out of the debug folder three files to a directory called c:\test\testzip\
In this folder I copied these files: Sample.exe, zip.exe, Interop.Shell32.dll
Then I double clicked the Sample.exe and filed in the three input boxes and clicked the Zip button.
That worked correctly.
You may want to try this same test. Also at http://GeraldGibson.Net I have a somewhat newer version of this article posted which you may want to try out. Also I dont see why it would cause an issue but in your code where it says... AppDomain.CurrentDomain.BaseDirectory + "\\data.zip". You may want to try removing the \\
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Removing the double back slashes didn't do anything. It has to do with the call to storing the destination to a zip file. Copy the three files to an isolated folder as such suggested did not work. I get this error mssage from your sample:
zip.exe - Common Language Runtime Debugging Services
Application has generated an exception that could not be handled.
Process id=0xe54 (3668), Thread id=0xca4 (3236).
Click OK to terminate the application. Click CANCEL to debug the application.
That's it. So I have no clue what's going on. I doubt you've experienced this error before though. I'm still puzzled why it works for many others, but I have yet to find anybody else having the same problem as me on the Internet when I search for my problem.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Well the one thing that was floating around in the back of my mind was you said you have another app registered as the zip handler in Windows? Maybe that is the problem. Perhaps that other app is some how interfering with the Shell API? Try to do this test on another PC.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
General News Question Answer Joke Rant Admin
|