自win11最近(23H2)添加了对rar/7zip等的原生支持。是否有任何 API 可以使用 c++ 中的 API? (或者它只是资源管理器的东西,不能被应用程序使用) 我需要这个用于演示场景相关目的。
这里有一些示例代码(为简单起见,使用 Visual Studio 中的 ATL),可以在最新版本的 Windows 11 上从存档文件(zip、7z、rar 等)中提取文件。
但是一些评论:
ITransferSource2
(恕我直言,应该记录该接口)。它应该支持 IStream
或 IStorage
或 ITransferSource
的 MoveItem
但它似乎不起作用。#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;
}