当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《使用C/C++在Windows(XP/2003)上创建ZIP文件》经验,为你挑选了3个好方法。

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

如果有人可以分享一些可以在Windows XP/2003上成功创建zip文件的示例C代码,我将非常感激.如果失败了,如果有人可以找到可靠的文档或教程,那将是很好的,因为MSDN搜索不会出现太多问题.我真的希望避免为此运送第三方库,因为功能显然存在,我只是无法弄清楚如何访问它.谷歌的搜索没有任何用处,只是引人入胜的信息.这里希望社区中有人对此进行整理,并为后人分享!



1> Jay..:

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

#include 
#include 
#include 
#include 

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

重要说明:AddFolderContent()函数不能正常运行,因为它包含在XZip库中.它将递归到目录结构中,但由于传递给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)



2> Sergey Korni..:

我们将XZip用于此目的.它是免费的,来自C++源代码并且运行良好.

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



3> Lou Franco..:

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

/sf/ask/17360801/

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

这里有示例代码

[编辑:链接现在断开]

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

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

编辑:从注释,此代码仅适用于现有的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);

推荐阅读
可爱的天使keven_464
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有