Pergunta

Eu estou procurando uma maneira de criar um arquivo ZIP a partir de uma pasta no APIs do Windows C / C ++. Posso encontrar a maneira de fazer isso no VBScript usando o método Shell32.Application CopyHere, e eu encontrei um tutorial explicando como fazê-lo em C # também, mas nada para a API C (C ++ é muito fina, o projeto já usa MFC).

Eu ficaria muito grato se alguém pode compartilhar algum código C de amostra que pode criar com êxito um arquivo zip no Windows XP / 2003. Falhando isso, se alguém pode encontrar docs sólido ou um tutorial que seria ótimo, já que pesquisas MSDN não aparecer muito. Estou realmente esperando para evitar ter que enviar uma lib de terceiros para isso, porque a funcionalidade é, obviamente, lá, eu simplesmente não consigo descobrir como acessá-lo. Pesquisas do Google transformar-se nada de útil, apenas tentadora pedaços de informações. Aqui está esperando que alguém na comunidade tem resolvido isso e pode compartilhá-la para a posteridade!

Foi útil?

Solução

EDIT: Essa resposta é antiga, mas eu não posso excluí-lo porque ele foi aceito. Ver a próxima

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

----- resposta original -----

Não há código de exemplo para fazer isso aqui

[EDIT: Link está agora quebrado]

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

Certifique-se de ler sobre como lidar com o monitoramento para o segmento para ser concluído.

Edit: A partir dos comentários, este código só funciona em arquivo zip existente, mas @ Simon forneceu este código para criar um arquivo em branco 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);

Outras dicas

Como observado em outros lugares nos comentários, isso só funcionará em um já criado Zip arquivo. O conteúdo deve também não existir no arquivo zip, ou um erro será exibido. Aqui está o código de exemplo de trabalho que eu era capaz de criar com base na resposta aceite. Você precisa link para shell32.lib e também kernel32.lib (para 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;

}

Eu decidi não ir por esse caminho apesar de começar código semi-funcional, uma vez que após uma investigação mais aprofundada, parece que o método de pasta :: CopyHere () na verdade não respeitar as VOptions passados ??para ele, o que significa que você não pode forçá-lo a arquivos de substituir ou não os diálogos de erro de exibição para o usuário.

À luz do que, eu tentei a biblioteca XZip mencionado por outro cartaz também. Este funções de biblioteca muito bem para criar um arquivo Zip, mas nota que a função ZipAdd () chamado com ZIP_FOLDER não é recursiva - ele apenas cria uma pasta no arquivo. A fim de forma recursiva zip um arquivo que você vai precisar usar a função AddFolderContent (). Por exemplo, para criar um C: \ Sample.zip e Adicionar a pasta C: \ Temp para isso, use o seguinte:

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

Nota importante: a função AddFolderContent () não é funcional como incluído na biblioteca XZip. Ele irá recorrer para a estrutura de diretórios, mas não consegue adicionar nenhum arquivo para o arquivo zip, devido a um bug nos caminhos passados ??para ZipAdd (). Para utilizar esta função você precisa editar a origem e alterar esta linha:

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

Para o seguinte:

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)

Nós usamos XZip para esta finalidade. É gratuito, vem como código-fonte C ++ e funciona muito bem.

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

O código acima para criar um arquivo zip vazio é quebrado, como o estado de comentários, mas eu era capaz de fazê-lo funcionar. Abri um zip vazio em um editor hexadecimal, e notou algumas diferenças. Aqui está o meu exemplo 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);

Isso funcionou para mim. Eu era capaz de, em seguida, abra a pasta compactada. Não testado com 3o partido aplicações como o WinZip.

Uma rápida pesquisa no Google surgiu com este site: http: //www.example -code.com/vcpp/vcUnzip.asp que tem um muito curto exemplo para descompactar um arquivo usando uma biblioteca de download. Há uma abundância de outras bibliotecas disponíveis. Outro exemplo é availaible no Projeto Código intitulada Zip e de descompactação no maneira MFC que tem todo um exemplo gui. Se você quiser fazê-lo com .NET, em seguida, há sempre as classes sob System.Compression.

Há também o 7-Zip libarary http://www.7-zip.org /sdk.html . Isto inclui fonte para várias línguas, e exemplos.

Eu não acho que MFC ou o padrão do Windows C / C ++ APIs fornecem uma interface para o construído em funcionalidade zip.

Você pode sempre ligar estaticamente à biblioteca zip gratuito se você não quiser enviar outra biblioteca ...

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top