Windows 11,原生 7zip 支持

问题描述 投票:0回答:1

自win11最近(23H2)添加了对rar/7zip等的原生支持。是否有任何 API 可以使用 c++ 中的 API? (或者它只是资源管理器的东西,不能被应用程序使用) 我需要这个用于演示场景相关目的。

c++ winapi
1个回答
0
投票

这里有一些示例代码(为简单起见,使用 Visual Studio 中的 ATL),可以在最新版本的 Windows 11 上从存档文件(zip、7z、rar 等)中提取文件。

但是一些评论:

  1. 它使用未记录的接口
    ITransferSource2
    (恕我直言,应该记录该接口)。它应该支持
    IStream
    IStorage
    ITransferSource
    MoveItem
    但它似乎不起作用。
  2. 某些格式的速度可能会非常慢,例如 .7z 和 .rar。实际上,它的运行速度应该与 Windows Shell UI 本身的速度大致相同(我的经验表明,与 7Zip 本身相比,复制粘贴 .7z 文件需要很长时间)。恕我直言,这大大降低了人们对该功能的兴趣。
#include <windows.h>
#include <atlbase.h>
#include <shobjidl_core.h>
#include <shlguid.h>

// this is an undocumented interface
DECLARE_INTERFACE_IID_(ITransferSource2, ITransferSource, "D6B78E20-B98A-49FA-AE7E-2BA7FCE522F5")
{
public:
    virtual HRESULT WINAPI IsCopySupported(IShellItem* psiSource, IShellItem* psiDest, BOOL* fSupported) = 0;
    virtual HRESULT WINAPI CopyItem(IShellItem* psiSource, IShellItem* psiDest, PCWSTR pszNameDst, TRANSFER_SOURCE_FLAGS flags, int, IShellItem**) = 0;
    virtual HRESULT WINAPI LastCopyError(int*) = 0;
};

void ExtractItemToTarget(IShellItem* item, IShellItem* target, bool recursive)
{
    // enumerate item's children
    CComPtr<IEnumShellItems> items;
    ATLASSERT(SUCCEEDED(item->BindToHandler(nullptr, BHID_EnumItems, IID_PPV_ARGS(&items))));

    do
    {
        CComPtr<IShellItem> child;
        items->Next(1, &child, 0);
        if (!child)
            break;

        // get relative name
        CComHeapPtr<wchar_t> name;
        ATLASSERT(SUCCEEDED(child->GetDisplayName(SIGDN_PARENTRELATIVEPARSING, &name)));

        // get full path for display
        CComHeapPtr<wchar_t> path;
        ATLASSERT(SUCCEEDED(child->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING, &path)));
        wprintf(L"Processing '%s'...\n", path.m_pData);

        // folder or item?
        SFGAOF folder = 0;
        if (SUCCEEDED(child->GetAttributes(SFGAO_FOLDER, &folder)) && folder)
        {
            if (recursive)
            {
                CComPtr<ITransferDestination> destination;
                ATLASSERT(SUCCEEDED(target->BindToHandler(nullptr, BHID_Transfer, IID_PPV_ARGS(&destination))));

                // ensure directory exists. we create a directory even for an empty folder
                CComPtr<IShellItem> childTarget;
                CComPtr<IShellItemResources> resources;
                ATLASSERT(SUCCEEDED(destination->CreateItem(name, FILE_ATTRIBUTE_DIRECTORY, 0, TSF_OVERWRITE_EXIST, IID_PPV_ARGS(&childTarget), IID_PPV_ARGS(&resources))));

                // go deep down
                ExtractItemToTarget(child, childTarget, recursive);
            }
        }
        else
        {
            // extract file (here we overwrite)
            CComPtr<ITransferSource> source;
            ATLASSERT(SUCCEEDED(item->BindToHandler(nullptr, BHID_Transfer, IID_PPV_ARGS(&source))));

            CComPtr<ITransferSource2> source2;
            ATLASSERT(SUCCEEDED(source.QueryInterface(&source2)));

            CComPtr<IShellItem> newItem;
            ATLASSERT(SUCCEEDED(source2->CopyItem(child, target, name, TSF_OVERWRITE_EXIST, 0, &newItem)));
        }
        child.Release();
    } while (true);
}

int main()
{
    ATLASSERT(SUCCEEDED(CoInitialize(nullptr)));
    {
        // should support zip 7z (slow!) gz bz2 tar rar (slow!) tgz tbz2 tzst txz zst xz
        CComPtr<IShellItem> file;
        ATLASSERT(SUCCEEDED(SHCreateItemFromParsingName(L"c:\\mypath\\my.zip", nullptr, IID_PPV_ARGS(&file))));

        // target path, create directory
        auto targetPath = L"c:\\target";
        CreateDirectory(targetPath, nullptr);

        CComPtr<IShellItem> target;
        ATLASSERT(SUCCEEDED(SHCreateItemFromParsingName(targetPath, nullptr, IID_PPV_ARGS(&target))));

        // extract file into target folder
        ExtractItemToTarget(file, target, true);
    }
    CoUninitialize();
    return 0;
}

© www.soinside.com 2019 - 2024. All rights reserved.