Я ищу способ создать ZIP-файл из папки в Windows C / C++ API. Я могу найти способ сделать это в VBScript, используя метод Shell32.Application CopyHere, и я нашел руководство, объясняющее, как это сделать и на C#, но ничего для C API (C++ тоже в порядке, проект уже использует MFC).
Я был бы очень признателен, если бы кто-нибудь поделился образцом кода C, который может успешно создать zip-файл в Windows XP / 2003. В противном случае, если бы кто-то мог найти надежные документы или учебное пособие, это было бы здорово, поскольку поисковые запросы MSDN не появляются много. Я действительно надеюсь избежать отправки сторонней библиотеки для этого, потому что функциональность, очевидно, есть, я просто не могу понять, как получить к ней доступ. Поиск в Google не дает ничего полезного, только соблазнительные кусочки информации. Мы надеемся, что кто-то из сообщества разобрался с этим и поделится этим для потомков!
Вы можете использовать Shell32.CopyHere из C или C++, просто вызовите необходимые API Win32 для создания экземпляра COM-объекта.





Я не думаю, что 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-файл уже существует. Если никто другой не предложит более полного ответа, я приму этот.
Создайте пустой почтовый индекс с помощью: 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);
Код, предоставленный для создания пустого zip-файла, не создает допустимого файла (его нельзя открыть никаким программным обеспечением zip, включая winzip, встроенный ZIP-файл Windows, BOMArchiver в OS X или разархивировать в командной строке.
Конкретно код находится в этом комментарии eggheadcafe.com/…
Шестнадцатеричная строка "\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.
Ссылка не работает. Лучше было бы поместить сюда суть ответа, а не только ссылку.
Эту шестнадцатеричную строку можно найти в реестре. См. Данные в HKEY_CLASSES_ROOT \ .zip \ CompressedFolder \ ShellNew
Вы всегда можете статически ссылаться на бесплатную 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++ и прекрасно работает.
Как отмечено в другом месте в комментариях, это будет работать только с уже созданным 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/…, чтобы проверять открытые окна оболочки через определенные интервалы времени, например?
Этот код работает, но функция 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, и все заработает!
Приведенный выше код для создания пустого 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.
Как создать сжатую папку в Windows с помощью Win32 API: ixmx.wordpress.com/2009/09/16/…