所以我有一个非常简单的工作要做:解压缩zip文件。我以为我会在网上找到一个简单的解决方案,但我仍然在苦苦挣扎。
我很明显看过这些帖子:
但答案建议使用zlib
和libzip
或miniz
。
我确定这些方法运行得很好。但是,在现有的VS2013解决方案中尝试应用此方法似乎并不简单。
然后我遇到了这个简单的解决方案,ref1,ref2,它使用了IShellDispatch object
我赶紧实施它:
bool DecompressZIP(_In_ const wpath& pathFile, _In_ const wpath& pathDstDir)
{
BSTR source = _bstr_t(pathFile.string().c_str());
BSTR dest = _bstr_t(pathDstDir.string().c_str());
HRESULT hResult = S_FALSE;
IShellDispatch *pIShellDispatch = NULL;
Folder *pToFolder = NULL;
VARIANT variantDir, variantFile, variantOpt;
CoInitialize(NULL);
hResult = CoCreateInstance(CLSID_Shell, NULL, CLSCTX_INPROC_SERVER,
IID_IShellDispatch, (void **)&pIShellDispatch);
if (SUCCEEDED(hResult) && NULL != pIShellDispatch)
{
VariantInit(&variantDir);
variantDir.vt = VT_BSTR;
variantDir.bstrVal = dest;
hResult = pIShellDispatch->NameSpace(variantDir, &pToFolder);
if (SUCCEEDED(hResult) && NULL != pToFolder)
{
Folder *pFromFolder = NULL;
VariantInit(&variantFile);
variantFile.vt = VT_BSTR;
variantFile.bstrVal = source;
hResult = pIShellDispatch->NameSpace(variantFile, &pFromFolder);
if (SUCCEEDED(hResult) && NULL != pFromFolder)
{
FolderItems *fi = NULL;
pFromFolder->Items(&fi);
VariantInit(&variantOpt);
variantOpt.vt = VT_I4;
variantOpt.lVal = FOF_NO_UI;
VARIANT newV;
VariantInit(&newV);
newV.vt = VT_DISPATCH;
newV.pdispVal = fi;
hResult = pToFolder->CopyHere(newV, variantOpt);
Sleep(1000);
pFromFolder->Release();
pToFolder->Release();
}
}
pIShellDispatch->Release();
}
CoUninitialize();
return true;
}
但它不起作用!
行:
hResult = pIShellDispatch->NameSpace(variantFile, &pFromFolder);
总是会产生pFromFolder == NULL
hResult
是S_FALSE
SUCCEEDED(hResult)
是真的GetLastError
为0 我做错了什么?
答案 0 :(得分:1)
您是否尝试单步执行调试器中的代码?你有几个bug,还有一些不是bug的东西,但是有很多潜力......
首先,正如WhozCraig所说 - 你有两个悬空指针,两个BSTR
。 (事实上,如果你设法让第一个NameSpace
调用成功,你会看到第二个BSTR
更改为某个GUID。显然第二个调用在接受该参数时失败。)< / p>
其次,您使用wpath
代替wstring
或类似的东西。 wpath
在路径组件之间添加斜杠。但是很多Windows代码不能使用正斜杠,只能使用反斜杠。 LoadLibrary()
就是一个例子。实际上,Shell中的所有内容都是另一个(例如,参见this link底部的屏幕截图)。
将wpath
更改为wstring
并将BSTR
更改为_bstr_t
即可使代码正常运行。
当然你还应该摆脱VARIANT
对_variant_t
的青睐,当你真的需要它们时,使用_com_ptr_t
而不是赤裸的指针,最好使用{ {1}}为此。
这样#import
方法需要NameSpace()
而不是_variant_t
,而VARIANT
有_variant_t
的隐式构造函数,所以你可以直接传递函数_bstr_t
,无需摆弄_bstr_t
s 或 VARIANT
。
答案 1 :(得分:1)
bool CUnZip::Unzip2Folder(BSTR lpZipFile, BSTR lpFolder)
{
IShellDispatch *pISD;
Folder *pZippedFile = 0L;
Folder *pDestination = 0L;
long FilesCount = 0;
IDispatch* pItem = 0L;
FolderItems *pFilesInside = 0L;
VARIANT Options, OutFolder, InZipFile, Item;
CoInitialize(NULL);
__try{
if (CoCreateInstance(CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, IID_IShellDispatch, (void **)&pISD) != S_OK)
return 1;
InZipFile.vt = VT_BSTR;
InZipFile.bstrVal = lpZipFile;
pISD->NameSpace(InZipFile, &pZippedFile);
if (!pZippedFile)
{
pISD->Release();
return 1;
}
OutFolder.vt = VT_BSTR;
OutFolder.bstrVal = lpFolder;
pISD->NameSpace(OutFolder, &pDestination);
if (!pDestination)
{
pZippedFile->Release();
pISD->Release();
return 1;
}
pZippedFile->Items(&pFilesInside);
if (!pFilesInside)
{
pDestination->Release();
pZippedFile->Release();
pISD->Release();
return 1;
}
pFilesInside->get_Count(&FilesCount);
if (FilesCount < 1)
{
pFilesInside->Release();
pDestination->Release();
pZippedFile->Release();
pISD->Release();
return 0;
}
pFilesInside->QueryInterface(IID_IDispatch, (void**)&pItem);
Item.vt = VT_DISPATCH;
Item.pdispVal = pItem;
Options.vt = VT_I4;
Options.lVal = 1024 | 512 | 16 | 4;//http://msdn.microsoft.com/en-us/library/bb787866(VS.85).aspx
bool retval = pDestination->CopyHere(Item, Options) == S_OK;
pItem->Release(); pItem = 0L;
pFilesInside->Release(); pFilesInside = 0L;
pDestination->Release(); pDestination = 0L;
pZippedFile->Release(); pZippedFile = 0L;
pISD->Release(); pISD = 0L;
return retval;
}
__finally
{
CoUninitialize();
}
}
主要是你打电话:
CUnZip * Z = new CUnZip();
BSTR bstrFile = strFileName.AllocSysString();
BSTR bstrPath = m_strPathName.AllocSysString();
Z->Unzip2Folder(bstrFile, bstrPath);
delete Z;
Z = NULL;
答案 2 :(得分:0)
我遇到同样的问题,当我使用绝对路径并且路径分隔符号是'\'时,问题是解决问题