13

Windows C/C++ API のフォルダーから ZIP ファイルを作成する方法を探しています。Shell32.Application CopyHere メソッドを使用して VBScript でこれを行う方法を見つけることができます。C# でもそれを行う方法を説明するチュートリアルを見つけましたが、C API については何もありません (C++ も問題なく、プロジェクトは既に MFC を使用しています)。

Windows XP/2003 で zip ファイルを正常に作成できるサンプル C コードを誰かが共有できれば、本当に感謝しています。それができない場合は、MSDN の検索ではあまりヒットしないため、誰かが確かなドキュメントやチュートリアルを見つけることができれば、それは素晴らしいことです。機能は明らかにそこにあるので、これにサードパーティのライブラリを出荷する必要がないように本当に望んでいますが、アクセス方法がわかりません。Google の検索では、有益な情報は何も得られず、ほんの少しの情報しか得られません。コミュニティの誰かがこれを整理し、後世のために共有できることを願っています!

4

7 に答える 7

13

コメントの他の場所で述べたように、これは既に作成された 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:\Temp フォルダーを追加するには、次のコマンドを使用します。

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)
于 2008-09-23T15:26:09.150 に答える
7

この目的のためにXZipを使用します。これは無料で、C ++ソースコードとして提供され、うまく機能します。

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

于 2008-09-23T03:26:56.320 に答える
5

編集:この回答は古いですが、受け入れられたため削除できません。次も見る

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

----- 元の回答 -----

ここにそれを行うサンプルコードがあります

[編集: リンクは現在壊れています]

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

スレッドが完了するまでの監視の処理方法について必ずお読みください。

編集:コメントから、このコードは既存のzipファイルでのみ機能しますが、@ Simonはこのコードを提供して空の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);
于 2008-09-23T01:20:38.357 に答える
4

コメントにあるように、空の 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 などのサードパーティ製アプリではテストされていません。

于 2008-10-23T18:02:49.320 に答える
2

Google ですばやく検索すると、http: //www.example-code.com/vcpp/vcUnzip.aspというサイトが見つかりました。このサイトには、ダウンロード可能なライブラリを使用してファイルを解凍するための非常に短い例があります。他にもたくさんのライブラリがあります。もう 1 つの例は、MFC の方法で Zip および Unzipというタイトルの Code Project で入手できます。これには、GUI の例全体があります。.NET で実行する場合は、System.Compression の下に常にクラスがあります。

7-Zip ライブラリhttp://www.7-zip.org/sdk.htmlもあります。これには、いくつかの言語のソースと例が含まれています。

于 2008-09-23T01:21:49.023 に答える
1

MFC や Windows 標準の C/C++ API が、組み込みの zip 機能へのインターフェイスを提供するとは思いません。

于 2008-09-23T01:19:55.720 に答える
0

別のライブラリを出荷したくない場合は、いつでもフリーウェアの zip ライブラリに静的にリンクできます...

于 2008-09-23T01:20:40.447 に答える