Создание ZIP-файла в Windows (XP / 2003) на C / C++

Я ищу способ создать ZIP-файл из папки в Windows C / C++ API. Я могу найти способ сделать это в VBScript, используя метод Shell32.Application CopyHere, и я нашел руководство, объясняющее, как это сделать и на C#, но ничего для C API (C++ тоже в порядке, проект уже использует MFC).

Я был бы очень признателен, если бы кто-нибудь поделился образцом кода C, который может успешно создать zip-файл в Windows XP / 2003. В противном случае, если бы кто-то мог найти надежные документы или учебное пособие, это было бы здорово, поскольку поисковые запросы MSDN не появляются много. Я действительно надеюсь избежать отправки сторонней библиотеки для этого, потому что функциональность, очевидно, есть, я просто не могу понять, как получить к ней доступ. Поиск в Google не дает ничего полезного, только соблазнительные кусочки информации. Мы надеемся, что кто-то из сообщества разобрался с этим и поделится этим для потомков!

Как создать сжатую папку в Windows с помощью Win32 API: ixmx.wordpress.com/2009/09/16/…

anno 08.09.2010 18:44

Вы можете использовать Shell32.CopyHere из C или C++, просто вызовите необходимые API Win32 для создания экземпляра COM-объекта.

Motes 03.12.2013 22:43
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
13
2
36 090
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Я не думаю, что MFC или стандартные API C / C++ Windows предоставляют интерфейс для встроенных функций zip.

Ответ принят как подходящий

Обновлено: этот ответ старый, но я не могу его удалить, потому что он был принят. Смотрите следующий

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

----- ОРИГИНАЛЬНЫЙ ОТВЕТ -----

Вот пример кода для этого

[Обновлено: ссылка теперь не работает]

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

Убедитесь, что вы прочитали о том, как обрабатывать мониторинг для завершения потока.

Обновлено: из комментариев этот код работает только с существующим zip-файлом, но @ Саймон предоставил этот код для создания пустого 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-файл уже существует. Если никто другой не предложит более полного ответа, я приму этот.

Jay 23.09.2008 06:18

Создайте пустой почтовый индекс с помощью: 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, е); fclose (f);

Simon Buchan 23.09.2008 07:26

Код, предоставленный для создания пустого zip-файла, не создает допустимого файла (его нельзя открыть никаким программным обеспечением zip, включая winzip, встроенный ZIP-файл Windows, BOMArchiver в OS X или разархивировать в командной строке.

Jay 23.09.2008 18:59

Конкретно код находится в этом комментарии eggheadcafe.com/…

Martin Beckett 25.05.2009 08:39

Шестнадцатеричная строка "\x80\x75\x05\x06\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - неправильный. Вместо шестнадцатеричного 0x80 должно быть десятичное число 80 и т. д. Это означает шестнадцатеричную строку это: "\x50\x4B\x05\x06\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", которая, как я подтвердил, работает при открытии файла с помощью проводника Windows 8.1.

Cheers and hth. - Alf 01.05.2014 15:48

Ссылка не работает. Лучше было бы поместить сюда суть ответа, а не только ссылку.

Werner Henze 10.12.2014 17:26

Эту шестнадцатеричную строку можно найти в реестре. См. Данные в HKEY_CLASSES_ROOT \ .zip \ CompressedFolder \ ShellNew

Vladyslav Litunovsky 08.01.2019 18:10

Вы всегда можете статически ссылаться на бесплатную zip-библиотеку, если не хотите отправлять другую библиотеку ...

Быстрый поиск в Google дал этот сайт: http://www.example-code.com/vcpp/vcUnzip.asp, на котором есть очень короткий пример распаковки файла с использованием загружаемой библиотеки. Доступно множество других библиотек. Другой пример доступен в Code Project под названием Архивировать и разархивировать в MFC, в котором есть полный пример графического интерфейса. Если вы хотите сделать это с помощью .NET, всегда есть классы в System.Compression.

Также существует библиотека 7-Zip http://www.7-zip.org/sdk.html. Сюда входят исходники для нескольких языков и примеры.

Для этого мы используем XZip. Это бесплатно, поставляется как исходный код C++ и прекрасно работает.

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

Как отмечено в другом месте в комментариях, это будет работать только с уже созданным 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-архива, но обратите внимание, что функция ZipAdd (), вызываемая с помощью ZIP_FOLDER, не является рекурсивной - она ​​просто создает папку в архиве. Чтобы рекурсивно заархивировать архив, вам нужно будет использовать функцию AddFolderContent (). Например, чтобы создать C: \ Sample.zip и добавить в него папку C: \ Temp, используйте следующее:

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

Важное примечание: функция AddFolderContent () не работает, поскольку она включена в библиотеку XZip. Он рекурсивно войдет в структуру каталогов, но не сможет добавить файлы в zip-архив из-за ошибки в путях, переданных в ZipAdd (). Чтобы использовать эту функцию, вам нужно отредактировать источник и изменить эту строку:

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)

Нет ли более разумного способа обнаружить все еще работающую оболочку? [msdn.microsoft.com/en-us//library/windows/desktop/…, чтобы проверять открытые окна оболочки через определенные интервалы времени, например?

Youka 02.09.2016 20:56

Этот код работает, но функция WaitForMultipleObjects ждет бесконечность, если поток завершился до этой строки. Согласно документации msdn => WaitForMultipleObjects Он говорит If one of these handles is closed while the wait is still pending, the function's behavior is undefined.. Чтобы избежать этого, дескрипторы должны иметь только флаг права доступа SYNCHRONIZE. Так что замените THREAD_ALL_ACCESS на OpenThread(THREAD_ALL_ACCESS, FALSE, te.th32ThreadID); на SYNCHRONIZE, и все заработает!

thibsc 03.03.2017 23:24

Приведенный выше код для создания пустого zip-файла не работает, как указано в комментариях, но мне удалось заставить его работать. Я открыл пустой 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.

Другие вопросы по теме