Introduction
Okay, so here I was supposed to write a module for compressing / decompressing files in Windows. I went through a lot of stuff over the net and found some open source libraries to do it. Out of those, I narrowed down to the one provided by Info-Zip. Although no longer actively maintained, this has been in existence for a long time and is known to be stable. This is used in various forms in a number of programs including Mac OS X.
However, on Windows, there is another way to zip files free of cost. I found this article - Easily zip / unzip files using Windows Shell32 on CodeProject which provides a neat way to use Windows routines to zip and unzip files programmatically. The code provided is in VB but since my requirement was in C++, I wrote a small C++ module which is shared here. I found the discussion and code snippets provided here to be very useful.
Zip
To compress and zip files, first we need to create the required zip file. The code below creates “test.zip” in "C:"
Code Snippet
BYTE startBuffer[] = {80, 75, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
FILE *f = fopen("C:\\test.zip", "wb");
fwrite(startBuffer,sizeof(startBuffer),1,f);
fclose(f);
Now that our zip file is created, let's add the files to be compressed inside this zip. For this, we use the CopyHere function wherein we treat our newly created zip file as a folder.
Code Snippet
BSTR source = L"C:\\test.txt\0\0";
BSTR dest = L"C:\\test.zip\\\0\0";
HRESULT hResult;
IShellDispatch *pISD;
Folder *pToFolder = NULL;
VARIANT vDir, vFile, vOpt;
CoInitialize(NULL);
hResult = CoCreateInstance
(CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, IID_IShellDispatch, (void **)&pISD);
if (SUCCEEDED(hResult))
{
VariantInit(&vDir);
vDir.vt = VT_BSTR;
vDir.bstrVal = dest;
hResult = pISD->NameSpace(vDir, &pToFolder);
if (SUCCEEDED(hResult))
{
VariantInit(&vFile);
vFile.vt = VT_BSTR;
vFile.bstrVal = source;
VariantInit(&vOpt);
vOpt.vt = VT_I4;
vOpt.lVal = FOF_NO_UI;
hResult = pToFolder->CopyHere(vFile, vOpt);
Sleep(1000);
pToFolder->Release();
}
pISD->Release();
}
CoUninitialize();
Unzip is similar to zip except that we now have zip (treated as source folder) and destination which anyways is a folder. The code below currently assumes that there already exists the destination folder, however adding a code to check for a folder or create a new folder on the fly should not be difficult.
The minor change (compared to the above code) in unzip comes only in identifying the source files. Here, we use the folderItems, which is essentially a list of all files/folders inside the given folder, instead of a single source file.
Code Snippet
if (SUCCEEDED(hResult))
{
Folder *pFromFolder = NULL;
VariantInit(&vFile);
vFile.vt = VT_BSTR;
vFile.bstrVal = source;
pISD->NameSpace(vFile, &pFromFolder);
FolderItems *fi = NULL;
pFromFolder->Items(&fi);
VariantInit(&vOpt);
vOpt.vt = VT_I4;
vOpt.lVal = FOF_NO_UI;
VARIANT newV;
VariantInit(&newV);
newV.vt = VT_DISPATCH;
newV.pdispVal = fi;
hResult = pToFolder->CopyHere(newV, vOpt);
Sleep(1000);
pFromFolder->Release();
pToFolder->Release();
}