Question

Je cherche un moyen de créer un fichier ZIP à partir d'un dossier dans les API Windows C / C ++. Je peux trouver le moyen de le faire dans VBScript à l'aide de la méthode Shell32.Application CopyHere et j'ai trouvé un tutoriel expliquant comment le faire également en C #, mais rien pour l'API C (C ++ convient également, le projet utilise déjà MFC).

Je serais vraiment reconnaissant si quelqu'un peut partager un exemple de code C pouvant créer avec succès un fichier zip sur Windows XP / 2003. À défaut, si quelqu'un peut trouver des documents solides ou un didacticiel, ce serait formidable, car les recherches MSDN ne donnent pas beaucoup. J'espère vraiment éviter de devoir envoyer une bibliothèque tierce pour cela, car la fonctionnalité est évidemment présente, je ne vois pas comment y accéder. Les recherches sur Google ne révèlent rien d'utile, elles ne font qu'attirer des éléments d'information. En espérant que quelqu'un de la communauté l'ait résolu et puisse le partager pour la postérité!

Était-ce utile?

La solution

EDIT: Cette réponse est ancienne, mais je ne peux pas la supprimer car elle a été acceptée. Voir la suivante

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

----- RÉPONSE ORIGINALE -----

Il existe un exemple de code pour le faire ici

[EDIT: le lien est maintenant brisé]

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

Assurez-vous de savoir comment gérer le contrôle pour que le thread se termine.

Éditer: D'après les commentaires, ce code ne fonctionne que sur les fichiers zip existants, mais @ Simon a fourni ce code pour créer un fichier zip vierge

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

Autres conseils

Comme indiqué ailleurs dans les commentaires, cela ne fonctionnera que sur un fichier Zip déjà créé. Le contenu ne doit pas non plus exister dans le fichier zip, sinon une erreur sera affichée. Voici l'exemple de code de travail que j'ai pu créer en fonction de la réponse acceptée. Vous devez créer un lien vers shell32.lib et également kernel32.lib (pour 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;

}

J'ai décidé de ne pas suivre cette voie malgré l'obtention d'un code semi-fonctionnel, car après une enquête plus approfondie, il apparaît que la méthode Folder :: CopyHere () ne respecte pas réellement les options vOmées qui lui ont été transmises, ce qui signifie que vous ne pouvez pas le forcer. écraser les fichiers ou ne pas afficher les boîtes de dialogue d'erreur à l'utilisateur.

À la lumière de cela, j'ai aussi essayé la bibliothèque XZip mentionnée par une autre affiche. Cette bibliothèque fonctionne bien pour créer une archive Zip, mais notez que la fonction ZipAdd () appelée avec ZIP_FOLDER n’est pas récursive. Elle crée simplement un dossier dans l’archive. Pour compresser une archive de manière récursive, vous devez utiliser la fonction AddFolderContent (). Par exemple, pour créer un fichier C: \ Sample.zip et y ajouter le dossier C: \ Temp, utilisez ce qui suit:

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

Remarque importante: la fonction AddFolderContent () n’est pas fonctionnelle, contrairement à la bibliothèque XZip. Il retournera dans la structure de répertoires mais n’ajoutera aucun fichier à l’archive zip, à cause d’un bogue dans les chemins passés à ZipAdd () Pour utiliser cette fonction, vous devez éditer la source et changer cette ligne:

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

Pour ce qui suit:

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)

Nous utilisons XZip à cette fin. C'est gratuit, vient comme code source C ++ et fonctionne bien.

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

Le code ci-dessus permettant de créer un fichier zip vide est cassé, comme l'indiquent les commentaires, mais j'ai pu le faire fonctionner. J'ai ouvert un zip vide dans un éditeur hexadécimal et noté quelques différences. Voici mon exemple modifié:

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

Cela a fonctionné pour moi. J'ai pu ensuite ouvrir le dossier compressé. Non testé avec des applications tierces telles que winzip.

Une recherche rapide dans Google a abouti à ce site: http: //www.example -code.com/vcpp/vcUnzip.asp qui contient un exemple très court permettant de décompresser un fichier à l'aide d'une bibliothèque téléchargeable. Il y a beaucoup d'autres bibliothèques disponibles. Un autre exemple est disponible dans Code Project intitulé Zip et Décompressez à la manière MFC avec un exemple complet. Si vous voulez le faire avec .NET, il y a toujours les classes sous System.Compression.

Il existe également la bibliothèque 7-Zip http://www.7-zip.org /sdk.html . Cela inclut des sources pour plusieurs langues et des exemples.

Je ne pense pas que les API C / C ++ standard de MFC ou de Windows fournissent une interface avec la fonctionnalité zip intégrée.

Vous pouvez toujours créer un lien statique vers la bibliothèque ZIP du logiciel gratuit si vous ne souhaitez pas expédier une autre bibliothèque ...

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top