문제

Windows C/C++ API의 폴더에서 ZIP 파일을 만드는 방법을 찾고 있습니다.Shell32.Application CopyHere 메서드를 사용하여 VBScript에서 이 작업을 수행하는 방법을 찾을 수 있으며 C#에서도 이 작업을 수행하는 방법을 설명하는 튜토리얼을 찾았지만 C API에 대한 내용은 없습니다(C++도 괜찮습니다. 프로젝트는 이미 MFC를 사용하고 있습니다).

누구든지 Windows XP/2003에서 zip 파일을 성공적으로 생성할 수 있는 샘플 C 코드를 공유할 수 있다면 정말 감사하겠습니다.실패하면 MSDN 검색에 많이 나오지 않기 때문에 누군가가 훌륭한 문서나 튜토리얼을 찾을 수 있다면 좋을 것입니다.저는 이를 위해 제3자 라이브러리를 제공할 필요가 없기를 정말로 바라고 있습니다. 왜냐하면 기능은 분명 존재하지만 그것에 액세스하는 방법을 알 수 없기 때문입니다.Google 검색에는 유용한 정보가 전혀 나오지 않고 단지 정보의 일부만이 흥미로울 뿐입니다.커뮤니티의 누군가가 이 문제를 해결하고 후세를 위해 공유할 수 있기를 바랍니다.

도움이 되었습니까?

해결책

편집하다:이 답변은 오래되었지만 승인되었으므로 삭제할 수 없습니다.다음을 참조하세요

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 파일에서만 작동합니다.콘텐츠는 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 아카이브 생성에 적합하게 작동하지만 ZIP_FOLDER로 호출되는 ZipAdd() 함수는 재귀적이지 않습니다. 단지 아카이브에 폴더를 생성할 뿐입니다.아카이브를 반복적으로 압축하려면 AddFolderContent() 함수를 사용해야 합니다.예를 들어 C:\Sample.zip을 만들고 여기에 C: emp 폴더를 추가하려면 다음을 사용합니다.

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

중요 사항:AddFolderContent() 함수는 XZip 라이브러리에 포함된 것처럼 작동하지 않습니다.이는 디렉토리 구조로 재귀되지만 ZipAdd()에 전달된 경로의 버그로 인해 zip 아카이브에 파일을 추가하지 못합니다.이 기능을 사용하려면 소스를 편집하고 다음 줄을 변경해야 합니다.

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)

우리는 이러한 목적으로 XZip을 사용합니다.무료이며 C++ 소스 코드로 제공되며 훌륭하게 작동합니다.

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

빈 zip 파일을 생성하는 위의 코드는 주석 상태와 같이 손상되었지만 제대로 작동하도록 할 수 있었습니다.16진수 편집기에서 빈 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과 같은 타사 앱에서는 테스트되지 않았습니다.

빠른 Google 검색으로 다음 사이트가 나타났습니다. http://www.example-code.com/vcpp/vcUnzip.asp 다운로드 가능한 라이브러리를 사용하여 파일의 압축을 푸는 매우 간단한 예가 있습니다.사용할 수 있는 다른 라이브러리도 많이 있습니다.코드 프로젝트에서 또 다른 예를 볼 수 있습니다. MFC 방식으로 압축 및 압축 풀기 전체 GUI 예제가 있습니다..NET으로 이를 수행하려면 항상 System.Compression 아래에 클래스가 있습니다.

7-Zip 라이브러리도 있습니다 http://www.7-zip.org/sdk.html.여기에는 여러 언어에 대한 소스와 예제가 포함됩니다.

나는 MFC나 Windows 표준 C/C++ API가 내장된 zip 기능에 대한 인터페이스를 제공한다고 생각하지 않습니다.

다른 라이브러리를 제공하고 싶지 않다면 언제든지 프리웨어 zip 라이브러리에 정적으로 링크할 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top