在 Windows (XP/2003) 上用 C/C++ 创建 ZIP 文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/118547/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 12:59:12  来源:igfitidea点击:

Creating a ZIP file on Windows (XP/2003) in C/C++

c++winapizip

提问by Jay

I am looking for a way to create a ZIP file from a folder in Windows C/C++ APIs. I can find the way to do this in VBScript using the Shell32.Application CopyHere method, and I found a tutorial explaining how to do it in C# also, but nothing for the C API (C++ is fine too, project already uses MFC).

我正在寻找一种从 Windows C/C++ API 中的文件夹创建 ZIP 文件的方法。我可以找到使用 Shell32.Application CopyHere 方法在 VBScript 中执行此操作的方法,并且我找到了一个教程,解释了如何在 C# 中执行此操作,但对于 C API 没有任何帮助(C++ 也很好,项目已经使用 MFC)。

I'd be really grateful if anyone can share some sample C code that can successfully create a zip file on Windows XP/2003. Failing that, if someone can find solid docs or a tutorial that would be great, since MSDN searches don't turn up much. I'm really hoping to avoid having to ship a third-party lib for this, because the functionality is obviously there, I just can't figure out how to access it. Google searches turn up nothing useful, just tantalizing bits and pieces of information. Here's hoping someone in the community has sorted this out and can share it for posterity!

如果有人可以分享一些可以在 Windows XP/2003 上成功创建 zip 文件的示例 C 代码,我将不胜感激。否则,如果有人能找到可靠的文档或教程,那就太好了,因为 MSDN 搜索不会出现太多。我真的希望避免为此发布第三方库,因为功能显然就在那里,我只是不知道如何访问它。谷歌搜索没有发现任何有用的信息,只是一些诱人的信息。希望社区中有人解决了这个问题,并可以分享给后代!

采纳答案by Lou Franco

EDIT: This answer is old, but I cannot delete it because it was accepted. See the next one

编辑:这个答案很旧,但我不能删除它,因为它被接受了。看下一个

https://stackoverflow.com/a/121720/3937

https://stackoverflow.com/a/121720/3937

----- ORIGINAL ANSWER -----

----- 原答案 -----

There is sample code to do that here

有示例代码可以做到这一点here

[EDIT: Link is now broken]

[编辑:链接现在已损坏]

http://www.eggheadcafe.com/software/aspnet/31056644/using-shfileoperation-to.aspx

http://www.eggheadcafe.com/software/aspnet/31056644/using-shfileoperation-to.aspx

Make sure you read about how to handle monitoring for the thread to complete.

确保您阅读了有关如何处理线程的监视以完成的内容。

Edit: From the comments, this code only works on existing zip file, but @Simonprovided this code to create a blank zip file

编辑:根据评论,此代码仅适用于现有的 zip 文件,但 @ Simon提供了此代码来创建一个空白的 zip 文件

FILE* f = fopen("path", "wb");
fwrite("\x50\x4B\x05\x06
#include <windows.h>
#include <shldisp.h>
#include <tlhelp32.h>
#include <stdio.h>

int main(int argc, TCHAR* argv[])
{
    DWORD strlen = 0;
    char szFrom[] = "C:\Temp",
         szTo[] = "C:\Sample.zip";
    HRESULT hResult;
    IShellDispatch *pISD;
    Folder *pToFolder = NULL;
    VARIANT vDir, vFile, vOpt;
    BSTR strptr1, strptr2;

    CoInitialize(NULL);

    hResult = CoCreateInstance(CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, IID_IShellDispatch, (void **)&pISD);

    if  (SUCCEEDED(hResult) && pISD != NULL)
    {
        strlen = MultiByteToWideChar(CP_ACP, 0, szTo, -1, 0, 0);
        strptr1 = SysAllocStringLen(0, strlen);
        MultiByteToWideChar(CP_ACP, 0, szTo, -1, strptr1, strlen);

        VariantInit(&vDir);
        vDir.vt = VT_BSTR;
        vDir.bstrVal = strptr1;
        hResult = pISD->NameSpace(vDir, &pToFolder);

        if  (SUCCEEDED(hResult))
        {
            strlen = MultiByteToWideChar(CP_ACP, 0, szFrom, -1, 0, 0);
            strptr2 = SysAllocStringLen(0, strlen);
            MultiByteToWideChar(CP_ACP, 0, szFrom, -1, strptr2, strlen);

            VariantInit(&vFile);
            vFile.vt = VT_BSTR;
            vFile.bstrVal = strptr2;

            VariantInit(&vOpt);
            vOpt.vt = VT_I4;
            vOpt.lVal = 4;          // Do not display a progress dialog box

            hResult = NULL;
            printf("Copying %s to %s ...\n", szFrom, szTo);
            hResult = pToFolder->CopyHere(vFile, vOpt); //NOTE: this appears to always return S_OK even on error
            /*
             * 1) Enumerate current threads in the process using Thread32First/Thread32Next
             * 2) Start the operation
             * 3) Enumerate the threads again
             * 4) Wait for any new threads using WaitForMultipleObjects
             *
             * Of course, if the operation creates any new threads that don't exit, then you have a problem. 
             */
            if (hResult == S_OK) {
                //NOTE: hard-coded for testing - be sure not to overflow the array if > 5 threads exist
                HANDLE hThrd[5]; 
                HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPALL ,0);  //TH32CS_SNAPMODULE, 0);
                DWORD NUM_THREADS = 0;
                if (h != INVALID_HANDLE_VALUE) {
                    THREADENTRY32 te;
                    te.dwSize = sizeof(te);
                    if (Thread32First(h, &te)) {
                        do {
                            if (te.dwSize >= (FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(te.th32OwnerProcessID)) ) {
                                //only enumerate threads that are called by this process and not the main thread
                                if((te.th32OwnerProcessID == GetCurrentProcessId()) && (te.th32ThreadID != GetCurrentThreadId()) ){
                                    //printf("Process 0x%04x Thread 0x%04x\n", te.th32OwnerProcessID, te.th32ThreadID);
                                    hThrd[NUM_THREADS] = OpenThread(THREAD_ALL_ACCESS, FALSE, te.th32ThreadID);
                                    NUM_THREADS++;
                                }
                            }
                            te.dwSize = sizeof(te);
                        } while (Thread32Next(h, &te));
                    }
                    CloseHandle(h);

                    printf("waiting for all threads to exit...\n");
                    //Wait for all threads to exit
                    WaitForMultipleObjects(NUM_THREADS, hThrd , TRUE , INFINITE);

                    //Close All handles
                    for ( DWORD i = 0; i < NUM_THREADS ; i++ ){
                        CloseHandle( hThrd[i] );
                    }
                } //if invalid handle
            } //if CopyHere() hResult is S_OK

            SysFreeString(strptr2);
            pToFolder->Release();
        }

        SysFreeString(strptr1);
        pISD->Release();
    }

    CoUninitialize();

    printf ("Press ENTER to exit\n");
    getchar();
    return 0;

}
HZIP newZip = CreateZip("C:\Sample.zip", NULL, ZIP_FILENAME);
BOOL retval = AddFolderContent(newZip, "C:", "temp");
if (ZipAdd(hZip, RelativePathNewFileFound, RelativePathNewFileFound, 0, ZIP_FILENAME) != ZR_OK)
ZRESULT ret;
TCHAR real_path[MAX_PATH] = {0};
_tcscat(real_path, AbsolutePath);
_tcscat(real_path, RelativePathNewFileFound);
if (ZipAdd(hZip, RelativePathNewFileFound, real_path, 0, ZIP_FILENAME) != ZR_OK)
FILE* f = fopen("path", "wb"); 
fwrite("\x50\x4B\x05\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 22, 1, f);
fclose(f);
##代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码##", 22, 1, f); fclose(f);

回答by Jay

As noted elsewhere in the comments, this will only work on a already-created Zip file. The content must also not already exist in the zip file, or an error will be displayed. Here is the working sample code I was able to create based on the accepted answer. You need to link to shell32.lib and also kernel32.lib (for CreateToolhelp32Snapshot).

如评论中的其他地方所述,这仅适用于已创建的 Zip 文件。zip 文件中也必须不存在该内容,否则将显示错误。这是我能够根据接受的答案创建的工作示例代码。您需要链接到 shell32.lib 和 kernel32.lib(用于 CreateToolhelp32Snapshot)。

##代码##

I have decided not to go this route despite getting semi-functional code, since after further investigation, it appears the Folder::CopyHere() method does not actually respect the vOptions passed to it, which means you cannot force it to overwrite files or not display error dialogs to the user.

尽管获得了半功能代码,我还是决定不走这条路,因为经过进一步调查,似乎 Folder::CopyHere() 方法实际上并不尊重传递给它的 vOptions,这意味着您不能强制它覆盖文件或不向用户显示错误对话框。

In light of that, I tried the XZip library mentioned by another poster as well. This library functions fine for creating a Zip archive, but note that the ZipAdd() function called with ZIP_FOLDER is not recursive - it merely creates a folder in the archive. In order to recursively zip an archive you will need to use the AddFolderContent() function. For example, to create a C:\Sample.zip and Add the C:\Temp folder to it, use the following:

鉴于此,我也尝试了另一张海报提到的 XZip 库。这个库可以很好地创建 Zip 存档,但请注意,使用 ZIP_FOLDER 调用的 ZipAdd() 函数不是递归的——它只是在存档中创建一个文件夹。为了递归压缩存档,您需要使用 AddFolderContent() 函数。例如,要创建 C:\Sample.zip 并将 C:\Temp 文件夹添加到其中,请使用以下命令:

##代码##

Important note: the AddFolderContent() function is not functional as included in the XZip library. It will recurse into the directory structure but fails to add any files to the zip archive, due to a bug in the paths passed to ZipAdd(). In order to use this function you'll need to edit the source and change this line:

重要说明:AddFolderContent() 函数没有 XZip 库中包含的功能。由于传递给 ZipAdd() 的路径中存在错误,它将递归到目录结构中,但无法将任何文件添加到 zip 存档中。为了使用此功能,您需要编辑源代码并更改此行:

##代码##

To the following:

对以下内容:

##代码##

回答by Sergey Kornilov

We use XZip for this purpose. It's free, comes as C++ source code and works nicely.

为此,我们使用 XZip。它是免费的,作为 C++ 源代码提供并且运行良好。

http://www.codeproject.com/KB/cpp/xzipunzip.aspx

http://www.codeproject.com/KB/cpp/xzipunzip.aspx

回答by Lou Franco

The above code to create an empty zip file is broken, as the comments state, but I was able to get it to work. I opened an empty zip in a hex editor, and noted a few differences. Here is my modified example:

如注释所述,上述创建空 zip 文件的代码已损坏,但我能够使其正常工作。我在十六进制编辑器中打开了一个空的 zip,并注意到了一些不同之处。这是我修改后的示例:

##代码##

This worked for me. I was able to then open the compressed folder. Not tested with 3rd party apps such as winzip.

这对我有用。然后我能够打开压缩文件夹。未使用 winzip 等 3rd 方应用程序进行测试。

回答by Vincent McNabb

A quick Google search came up with this site: http://www.example-code.com/vcpp/vcUnzip.aspwhich has a very short example to unzip a file using a downloadable library. There are plenty of other libraries available. Another example is availaible on Code Project entitled Zip and Unzip in the MFC waywhich has an entire gui example. If you want to do it with .NET then there is always the classes under System.Compression.

一个快速的谷歌搜索出现了这个站点:http: //www.example-code.com/vcpp/vcUnzip.asp,它有一个使用可下载库解压缩文件的非常简短的示例。还有很多其他可用的库。另一个例子在代码项目中可用,名为Zip and Unzip in the MFC way,它有一个完整的 gui 示例。如果你想用 .NET 来做,那么 System.Compression 下总是有类。

There is also the 7-Zip libarary http://www.7-zip.org/sdk.html. This includes source for several languages, and examples.

还有 7-Zip 库http://www.7-zip.org/sdk.html。这包括多种语言的源代码和示例。

回答by Sparr

I do not think that MFC or the Windows standard C/C++ APIs provide an interface to the built in zip functionality.

我不认为 MFC 或 Windows 标准 C/C++ API 为内置 zip 功能提供接口。

回答by EmmEff

You could always statically link to the freeware zip library if you don't want to ship another library...

如果您不想发送另一个库,您始终可以静态链接到免费软件 zip 库...