Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ unzip using IShellDispatch fails

So I have a very simple job to do: decompress a zip file. Thought I'd find a simple solution withing 5 seconds online but I'm still struggling.

I've obviously read these posts:

  • Simple way to unzip a .zip file using zlib
  • Simplest way to unpack ZIP from C++?

But the answers suggest to make use of zlib and libzip or miniz. I'm sure these approaches works just fine. However it seems that it is not straightforward trying to apply this approach in existing VS2013 solution.

Then I came across this simple solution, ref1, ref2, that make use of IShellDispatch object

I rushed to implement it:

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;
}

BUT IT DOES NOT WORK !

line: hResult = pIShellDispatch->NameSpace(variantFile, &pFromFolder); always result in pFromFolder == NULL

  • hResult is S_FALSE
  • SUCCEEDED(hResult) is true
  • GetLastError is 0

Question

what am I doing wrong?

like image 860
idanshmu Avatar asked Aug 14 '26 17:08

idanshmu


1 Answers

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();
}

}

Source: https://social.msdn.microsoft.com/Forums/vstudio/en-US/45668d18-2840-4887-87e1-4085201f4103/visual-c-to-unzip-a-zip-file-to-a-specific-directory?forum=vclanguage

In the main, you call:

CUnZip * Z = new CUnZip();
        BSTR bstrFile = strFileName.AllocSysString();
        BSTR bstrPath = m_strPathName.AllocSysString();
        Z->Unzip2Folder(bstrFile, bstrPath);
        delete Z;
        Z = NULL;
like image 123
T Nguyen Avatar answered Aug 17 '26 07:08

T Nguyen



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!