- 背景
本人最近工作当中遇到了解压失败的问题,由于工作中使用C++语言,当前的解压方案是起一个进程去调用7z工具来解压,该方法有时会报错,具体原因尚未明确。于是我在想要不直接使用C++代码解压,先看了一下当前的解压第三方库,一个有名的是zlib,当看了一下解压到目录的实现,好家伙,2000行代码,吃不消,后来放弃这条路了。然后就一直在网上查找是否用简单的方式实现,最好不要依赖第三方库,那样还得引入开源备案及遵守开源协议等一些麻烦事。找了好久,终于找到了一篇博文,介绍了一个使用windows api直接解压到一个目录的代码,由于比较久远,原文链接有时间再补上。代码不多,我自己润色了一下(改了一些变量名并加了好多判断),最终实现了。笔者亲测有效,核心代码100行左右。
- 代码实现
注:以下代码需用VS编译!!!
点击查看代码
#include <Windows.h>
#include <Shldisp.h>
#include <stdio.h>
#include <locale.h>
#define FreeResource(A) \
if (A != NULL) { \
A->Release(); \
}
bool UnZipFolder(wchar_t* zipFile, wchar_t* dstDir)
{
bool bReturn = false;
HRESULT hResult;
IShellDispatch* pISD = NULL;
Folder* pFromFolder = NULL;
FolderItems* pFromFolderItems = NULL;
Folder* pToFolder = NULL;
IDispatch* pDispatch = NULL;
BSTR bstrZipFile = NULL;
BSTR bstrDstDir = NULL;
VARIANT vDstDir, vZipFile, vtDispatch, vOpt;
long fromFolderCount = 0;
hResult = CoInitialize(NULL);
if (FAILED(hResult)) {
goto FINAL;
}
hResult = CoCreateInstance(CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, IID_IShellDispatch, (void**)&pISD);
if (FAILED(hResult) || pISD == NULL) {
goto FINAL;
}
bstrZipFile = SysAllocString(zipFile);
if (bstrZipFile == NULL) {
goto FINAL;
}
bstrDstDir = SysAllocString(dstDir);
if (bstrDstDir == NULL) {
goto FINAL;
}
VariantInit(&vZipFile);
vZipFile.vt = VT_BSTR;
vZipFile.bstrVal = bstrZipFile;
VariantInit(&vDstDir);
vDstDir.vt = VT_BSTR;
vDstDir.bstrVal = bstrDstDir;
hResult = pISD->NameSpace(vZipFile, &pFromFolder);
if (FAILED(hResult) || pFromFolder == NULL) {
goto FINAL;
}
hResult = pISD->NameSpace(vDstDir, &pToFolder);
if (FAILED(hResult) || pToFolder == NULL) {
goto FINAL;
}
hResult = pFromFolder->Items(&pFromFolderItems);
if (FAILED(hResult) || pFromFolderItems == NULL) {
goto FINAL;
}
pFromFolderItems->get_Count(&fromFolderCount);
if (fromFolderCount < 1) {
goto FINAL;
}
pFromFolderItems->QueryInterface(IID_IDispatch, (void**)&pDispatch);
if (FAILED(hResult) || pDispatch == NULL) {
goto FINAL;
}
VariantInit(&vtDispatch);
vtDispatch.vt = VT_DISPATCH;
vtDispatch.pdispVal = pDispatch;
VariantInit(&vOpt);
vOpt.vt = VT_I4;
vOpt.lVal = 16 + 4; // Do not display a progress dialog box ~ This will not work properly!
printf("Extracting files ...\n");
hResult = pToFolder->CopyHere(vtDispatch, vOpt);
if (FAILED(hResult)) {
goto FINAL;
}
printf("unzip success\n");
bReturn = true;
FINAL:
FreeResource(pISD);
FreeResource(pFromFolder);
FreeResource(pFromFolderItems);
FreeResource(pToFolder);
FreeResource(pDispatch);
if (bstrZipFile) SysFreeString(bstrZipFile);
if (bstrDstDir) SysFreeString(bstrDstDir);
CoUninitialize();
return bReturn;
}
int wmain(int argc, wchar_t* argv[])
{
setlocale(LC_ALL, "");
wchar_t zipFile[260] = { 0 };
wchar_t dstDir[260] = { 0 };
wcscpy(zipFile, L"E:\\test\\游戏.zip");
wcscpy(dstDir, L"E:\\test\\XXXX");
CreateDirectoryW(dstDir, 0);
UnZipFolder(zipFile, dstDir);
return 0;
}