【问题标题】:Creating a ZIP file on Windows (XP/2003) in C/C++使用 C/C++ 在 Windows (XP/2003) 上创建 ZIP 文件
【发布时间】:2010-09-12 05:23:18
【问题描述】:

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

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

【问题讨论】:

  • 如何在 Windows 中使用 Win32 API 创建压缩文件夹:ixmx.wordpress.com/2009/09/16/…
  • 您可以使用 C 或 C++ 的 Shell32.CopyHere,只需调用必要的 win32 API 来实例化 COM 对象。

标签: c++ winapi zip


【解决方案1】:

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

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

}

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

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

HZIP newZip = CreateZip("C:\\Sample.zip", NULL, ZIP_FILENAME);
BOOL retval = AddFolderContent(newZip, "C:", "temp");

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

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)

【讨论】:

  • 难道没有更聪明的方法来检测仍在工作的 shell?[msdn.microsoft.com/en-us//library/windows/desktop/… 以自定义间隔检查打开的 shell 窗口 f.e.?
  • 此代码有效,但如果线程在此行之前完成,则函数 WaitForMultipleObjects 将无限等待。根据 msdn 文档 => WaitForMultipleObjects 它说 If one of these handles is closed while the wait is still pending, the function's behavior is undefined. 为了避免这种情况,句柄必须只有 SYNCHRONIZE 访问权限标志。因此,将 OpenThread(THREAD_ALL_ACCESS, FALSE, te.th32ThreadID); 中的 THREAD_ALL_ACCESS 替换为 SYNCHRONIZE 就可以了!
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

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

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

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

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

    [编辑:链接现已断开]

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

    确保您阅读了有关如何处理要完成的线程的监视的信息。

    编辑:来自 cmets,此代码仅适用于现有 zip 文件,但 @Simon 提供此代码以创建空白 zip 文件

    FILE* f = fopen("path", "wb");
    fwrite("\x50\x4B\x05\x06\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 22, 1, f);
    fclose(f);
    

    【讨论】:

    • 我之前确实找到了该示例代码,但它实际上并没有按原样工作。经过一些调整后,我最终确实让它编译并运行,并且它有点工作,前提是 ZIP 文件已经存在。如果没有其他人提出更完整的答案,我会接受这个。
    • 使用以下命令创建空白 zip:FILE* f = fopen("path", "wb"); fwrite("\x80\x75\x05\x06\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 22 , 1, f); fclose(f);
    • 提供的用于创建空白 zip 文件的代码无法创建有效文件(它无法被任何 zip 软件打开,包括 winzip、Windows 内置 ZIP、OS X 上的 BOMArchiver 或在命令行。
    • 具体代码在这条评论eggheadcafe.com/…
    • 链接已损坏。将答案的要点放在这里会更好,而不仅仅是链接。
    【解决方案4】:

    上述创建空 zip 文件的代码已损坏,如 cmets 所述,但我能够让它工作。我在十六进制编辑器中打开了一个空 zip,并注意到了一些差异。这是我修改后的示例:

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

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

    【讨论】:

      【解决方案5】:

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

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

      【讨论】:

        【解决方案6】:

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

        【讨论】:

          【解决方案7】:

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

          【讨论】:

            猜你喜欢
            • 2019-04-02
            • 1970-01-01
            • 2011-06-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-07-07
            相关资源
            最近更新 更多