2008-09-23 16 views
11

Windows C/C++ API'lerinde bir klasörden bir ZIP dosyası oluşturmanın bir yolunu arıyorum. Bunu, Shell32.Application CopyHere yöntemini kullanarak VBScript'te yapmanın yolunu bulabilirim ve C# içinde nasıl yapılacağını açıklayan bir öğretici de buldum, ancak C API'sı için hiçbir şey (C++ da gayet iyi, proje zaten MFC kullanıyor).C/C++ içinde bir ZIP dosyası oluşturma (XP/2003)

Windows XP/2003'te başarılı bir şekilde bir zip dosyası oluşturabilen bazı örnek C kodlarını paylaşabilirse gerçekten minnettar olurum. MSDN aramaları çok fazla gelmediğinden, birisi katı dokümanları veya harika olabilecek bir öğretici bulabilirse başarısız olur. Bunun için bir üçüncü parti kitapçığı göndermekten kaçınmayı umuyordum, çünkü işlevselliğin açık olduğu belliydi, ona nasıl erişeceğimi anlayamıyorum. Google aramaları faydalı bir şey ortaya koymaz, sadece bitleri ve bilgi parçalarını telaşlandırır. İşte toplumdaki birisinin bunu sıraya koyduğunu ve bunu posterity için paylaşabileceğini umuyoruz!

+1

Windows'da Win32 API kullanarak sıkıştırılmış bir klasör nasıl oluşturulur: http://ixmx.wordpress.com/2009/09/16/how-to-create-a-compress-folder-in-windows-using-win32 -api/ – anno

+0

Shell32.CopyHere'i C veya C++'dan kullanabilirsiniz, yalnızca COM nesnesini başlatmak için gerekli win32 API'lerini çağırın. – Motes

cevap

4

DÜZENLEME: Bu yanıt eskidir, ancak kabul edilemediği için silemiyorum. [: Bağlantı şimdi bozuldu DÜZENLEME]

----- sonraki

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

----- ORIGIN CEVAP bakın

yapmak

burada buna örnek kod vardır

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

Konunun tamamlamak için izleme işlemlerini gerçekleştirmek için nasıl okumak emin olun.

Düzenleme: yorumuyla, bu kod sadece mevcut zip dosyası üzerinde çalışır, ancak Simon @

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

Bu örnek kodu daha önce buldum, ancak aslında olduğu gibi görünmüyor. ZIP dosyasının zaten mevcut olması koşuluyla, nihayetinde biraz düzenleme yaptıktan sonra çalışıp derledim. Eğer hiç kimse daha eksiksiz bir cevap vermezse bunu kabul ediyorum. – Jay

+1

Boş bir zip oluşturun: DOSYA * f = fopen ("yol", "wb"); fwrite ("\ x80 \ x75 \ x05 \ x06 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0", 22, 1, f); fclose (f); –

+1

Boş bir zip dosyası oluşturmak için sağlanan kod geçerli bir dosya oluşturmaz (winzip, Windows yerleşik ZIP, OS X üzerinde BOMArchiver dahil olmak üzere herhangi bir zip yazılımı tarafından açılmaz veya komut satırında unzip olamaz.) – Jay

1

MFC veya Windows standart C/C++ API'lerinin yerleşik zip işlevine bir arabirim sağladığını düşünmüyorum.

0

Hep statik eğer ücretsiz zip kitaplığına bağlantı olabilir boş zip dosyası oluşturmak için bu kodu verilen Başka bir kütüphane göndermek istemiyorum ...

2

Bu site ile hızlı bir Google araması geldi: http://www.example-code.com/vcpp/vcUnzip.asp Bir dosya indirilebilen bir kütüphane kullanarak unzip çok kısa bir örneği vardır. Çok sayıda başka kütüphane var. Başka bir örnek, tüm gui örneğine sahip olan Zip and Unzip in the MFC way başlıklı Kod Projesi'nde kullanılabilir. .NET ile yapmak isterseniz, her zaman System.Compression altında sınıflar vardır.

Ayrıca 7-Zip libarary http://www.7-zip.org/sdk.html da vardır. Bu, çeşitli diller ve örnekler için kaynak içerir.

13

başka yerde açıklamalarda belirtildiği gibi, bu sadece bir önceden oluşturulan Zip dosyası üzerinde çalışacak. İçerik, zip dosyasında da bulunmamalı veya bir hata görüntülenecektir. İşte kabul edilen cevaba dayanarak oluşturduğum örnek örnek kod. Shell32.lib ve ayrıca kernel32.lib (CreateToolhelp32Snapshot için) bağlantı kurmanız gerekir.Ben sonra daha fazla araştırma beri, yarı fonksiyonel kodu alma rağmen bu yoldan gitmeye karar verdik

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

} 

, Klasör görünür :: CopyHere() yöntemi aslında sizi, yani kendisine geçirilen VOptions saygı duymayan dosyaları üzerine yazmaya zorlamaz veya kullanıcıya hata diyaloglarını gösteremez.

Bunun ışığında, başka bir posterin de bahsettiği XZip kütüphanesini denedim. Bu kitaplık bir Zip arşivi oluşturmak için iyi çalışır, ancak ZIP_FOLDER ile çağrılan ZipAdd() işlevinin özyineli olmadığını unutmayın - yalnızca arşivde bir klasör oluşturur. Bir arşivi yinelemek için AddFolderContent() işlevini kullanmanız gerekir. Örneğin, bir C oluşturmak için: \ Sample.zip ve C ekleyin:

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

Önemli not: buna \ Temp klasörünü, aşağıdaki kullanmak XZip dahil olarak AddFolderContent() fonksiyonu işlevsel değil kütüphane. Dizin yapısına yeniden girer ancak ZipAdd() 'a geçirilen yollardaki bir hata nedeniyle, zip arşivine herhangi bir dosya eklemeyi başaramaz. olarak, bozuldu

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) 
+0

Hala çalışan bir kabuğu algılamak için daha akıllı bir yolu yok mu? ttps: //msdn.microsoft.com/en-us//library/windows/desktop/gg537733 (v = vs85) .aspx] (IShellDispatch.Windows) açık kabuklu pencereleri kendi kendine tanımlanmış aralıklarla kontrol etmek için bkz. – Youka

+0

Bu kod çalışır ancak bu satırdan önce bir iş parçacığı bittiyse 'WaitForMultipleObjects' işlevi sonsuza kadar bekler. msdn belgelerine göre => [WaitForMultipleObjects] (https://msdn.microsoft.com/tr-us/library/windows/desktop/ms687025 (v = vs.85) .aspx) '' Bekleme hala beklemede iken bu tutamaçlardan biri kapalıysa, işlevin davranışı tanımsızdır. ' To Bunu önlemek için, kolları sadece SYNCHRONIZE erişim sağ bayrağı olmalıdır. Yani 'OpenThread (THREAD_ALL_ACCESS, FALSE, te.th32ThreadID)' THNAD_ALL_ACCESS'' yerine '' SYNCHRONIZE' ile değiştirin ve iyi çalışıyor! –

3

boş zip dosyasını oluşturmak için yukarıdaki kodu: Aşağıdaki için

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

: Bu fonksiyonu kullanmak için Kaynak kodunu düzenlemek ve bu hat değiştirmek gerekir yorumlar devlet, ama işe almak için başardı. Altıgen bir editörde boş bir zip açtım ve birkaç farklılık fark ettim. Benim değiştirilmiş örneğim:

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

Bu benim için çalıştı. Sıkıştırılmış klasörü açabildim. Winzip gibi 3. parti uygulamalarla test edilmedi.

+0

İyi, işe yarıyor. Teşekkürler –

İlgili konular