Crear un archivo ZIP en Windows (XP / 2003) en C / C ++

Estoy buscando una forma de crear un archivo ZIP desde una carpeta en las API de Windows C / C ++. Puedo encontrar la manera de hacerlo en VBScript utilizando el método Shell32.Application CopyHere, y encontré un tutorial que explica cómo hacerlo en C # también, pero nada para la API C (C ++ también está bien, el proyecto ya usa MFC).

Estaría muy agradecido si alguien puede compartir algún código C de muestra que pueda crear exitosamente un archivo zip en Windows XP / 2003. De lo contrario, si alguien puede encontrar documentos sólidos o un tutorial, sería genial, ya que las búsquedas de MSDN no aparecen demasiado. Realmente espero evitar tener que enviar una lib de terceros para esto, porque la funcionalidad está obviamente allí, simplemente no puedo entender cómo acceder a ella. Las búsquedas de Google no encuentran nada útil, solo atormentando pedazos de información. ¡Esperamos que alguien en la comunidad haya resuelto esto y pueda compartirlo para la posteridad!

EDITAR: esta respuesta es antigua, pero no puedo borrarla porque fue aceptada. Mira el siguiente

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

—– RESPUESTA DE ORIGEN —–

Hay un código de muestra para hacer eso aquí

[EDIT: Enlace ahora está roto]

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

Asegúrese de leer acerca de cómo manejar la monitorización de la secuencia para completar.

Editar: a partir de los comentarios, este código solo funciona en un archivo zip existente, pero @ Simon proporcionó este código para crear un archivo zip en blanco

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

Como se señaló en otra parte de los comentarios, esto solo funcionará en un archivo Zip ya creado. El contenido tampoco debe existir en el archivo comprimido, o se mostrará un error. Aquí está el código de muestra de trabajo que pude crear basado en la respuesta aceptada. Necesita vincular a shell32.lib y también a kernel32.lib (para 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; } 

He decidido no seguir esta ruta a pesar de obtener un código semifuncional, ya que después de una investigación más exhaustiva, parece que el método Folder :: CopyHere () no respeta las vOpciones que se le pasaron, lo que significa que no puede forzarlo a sobrescribir archivos o no mostrar diálogos de error para el usuario.

A la luz de eso, probé la biblioteca XZip mencionada por otro póster también. Esta biblioteca funciona bien para crear un archivo Zip, pero tenga en cuenta que la función ZipAdd () llamada con ZIP_FOLDER no es recursiva, simplemente crea una carpeta en el archivo. Para comprimir de manera recursiva un archivo, deberá usar la función AddFolderContent (). Por ejemplo, para crear un C: \ Sample.zip y agregarle la carpeta C: \ Temp, use lo siguiente:

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

Nota importante: la función AddFolderContent () no es funcional como se incluye en la biblioteca XZip. Volverá a aparecer en la estructura del directorio, pero no agrega ningún archivo al archivo zip, debido a un error en las rutas pasadas a ZipAdd (). Para usar esta función necesitarás editar la fuente y cambiar esta línea:

 if (ZipAdd(hZip, RelativePathNewFileFound, RelativePathNewFileFound, 0, ZIP_FILENAME) != ZR_OK) 

A lo siguiente:

 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) 

Usamos XZip para este propósito. Es gratis, viene en código fuente C ++ y funciona muy bien.

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

El código anterior para crear un archivo zip vacío está roto, como dicen los comentarios, pero pude hacer que funcione. Abrí un zip vacío en un editor hexadecimal y noté algunas diferencias. Aquí está mi ejemplo modificado:

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

Esto funcionó para mí. Pude abrir la carpeta comprimida. No probado con aplicaciones de terceros como winzip.

Se creó una búsqueda rápida en Google con este sitio: http://www.example-code.com/vcpp/vcUnzip.asp, que tiene un ejemplo muy breve para descomprimir un archivo utilizando una biblioteca descargable. Hay muchas otras bibliotecas disponibles. Otro ejemplo está disponible en Code Project titulado Zip and Unzip en el modo MFC que tiene un ejemplo completo de gui. Si desea hacerlo con .NET, siempre hay las clases en System.Compression.

También está la libarary 7-Zip http://www.7-zip.org/sdk.html . Esto incluye fuente para varios idiomas y ejemplos.

No creo que MFC o las API C / C ++ estándar de Windows proporcionen una interfaz para la funcionalidad integrada de zip.

Siempre puede vincular estáticamente a la biblioteca zip freeware si no desea enviar otra biblioteca …