Witam!
W systemach Win XP, 2000, Vista można pakować i rozpakowywać pliki.
Czy system wykorzystuje do tego gotową bibliotekę?
Czy można to robić z wykorzystaniem API np. ładując właściwą bibliotekę i wykorzystując jej funkcje?
Jeśli tak, to jak ta biblioteka sie nazywa(chodzi mi o załadowanie jej) i jakich funkcji, struktur używa?
Chciałbym uniknąć wykorzystanie zew. programów (WinRar'a, ZIP-7).
Pozdrawiam
Biblioteka to zipfldr.dll, nie wiem czy cokolwiek eksportuje, ale możesz poszukać info. Możesz też po prostu sam zaimplementować obsługę zipa zaczynając od NULL.
proponuje jednak uzywac bibliotek innych dostawcow niz ta wbudowana w windoze.. szczerze, wolniejszego zippera/unzipera jeszcze nie widzialem
zipfldr.dll eksportuje interfejsy shellowe, takie jak IShellFolder, więc wszelakie operacje na archiwach są na tyle możliwe, na ile znasz programowanie winshell'a.
Sposób na wylistowanie plików i folderów z pierwszego poziomu znajdziesz w 10-tym poście na stronie http://forum.sources.ru/index.php?showtopic=201707.
Poniżej wstawiłem demo wypakowujące pliki z roota zipa do %temp%\zipdemo
// możliwe małe braki kompatybilości z c++
void ExtractRootFiles()
{
IShellFolder *psfZip;
IShellFolder *psfParent;
ITEMIDLIST *pidl = ILCreateFromPath("D:\\download\\myzip.zip");
if (pidl)
{
ITEMIDLIST *pidlChild;
if (!SHBindToParent(pidl, IID_IShellFolder, (void**)&psfParent, &pidlChild))
{
psfParent->BindToObject(pidlChild, NULL, IID_IShellFolder, (void**)&psfZip);
char szDisplayName[MAX_PATH];
char szSavePath[MAX_PATH];
GetTempPath(MAX_PATH, szSavePath);
strcat(szSavePath, "zipdemo");
CreateDirectory(szSavePath, NULL);
strcat(szSavePath, "\\");
char *pFileName = &szSavePath[strlen(szSavePath)];
IEnumIDList *penum;
psfZip->EnumObjects(NULL, SHCONTF_NONFOLDERS, &penum);
ULONG celtFetched;
ITEMIDLIST *pidlItems;
while (!penum->Next(1, &pidlItems, &celtFetched) && celtFetched)
{
STRRET strDispName;
psfZip->GetDisplayNameOf(pidlItems, SHGDN_INFOLDER, &strDispName);
StrRetToBuf(&strDispName, pidlItems, szDisplayName, MAX_PATH);
printf(" - %s\n", szDisplayName);
IDataObject *dataobj;
if (!psfZip->GetUIObjectOf(0, 1, &pidlItems, IID_IDataObject, 0, (void**)&dataobj))
{
int FormatBits = 0;
FORMATETC fmt;
FORMATETC fmtDescriptor;
FORMATETC fmtContents;
STGMEDIUM mediumContents;
STGMEDIUM mediumDescriptor;
UINT CF_FILEDESCRIPTORA = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA);
UINT CF_FILEDESCRIPTORW = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW);
UINT CF_FILECONTENTS = RegisterClipboardFormat(CFSTR_FILECONTENTS);
IEnumFORMATETC *formats;
dataobj->EnumFormatEtc(DATADIR_GET, &formats);
while (!formats->Next(1, &fmt, &celtFetched) && celtFetched)
{
if ((!(FormatBits & 1)) && ((fmt.cfFormat == CF_FILEDESCRIPTORA) || (fmt.cfFormat == CF_FILEDESCRIPTORW)))
{
FormatBits |= 1;
MoveMemory(&fmtDescriptor, &fmt, sizeof(FORMATETC));
}
else if ((!(FormatBits & 2)) && (fmt.cfFormat == CF_FILECONTENTS))
{
FormatBits |= 2;
MoveMemory(&fmtContents, &fmt, sizeof(FORMATETC));
}
}
formats->Release();
fmtContents.lindex = 0;
// FormatBits musi być równe 3
hr = dataobj->GetData(&fmtDescriptor, &mediumDescriptor);
if (!hr)
{
FILEGROUPDESCRIPTOR *pdsc = GlobalLock(mediumDescriptor.hGlobal);
LARGE_INTEGER liSize;
liSize.LowPart = pdsc->fgd[0].nFileSizeLow;
liSize.HighPart = pdsc->fgd[0].nFileSizeHigh;
GlobalUnlock(mediumDescriptor.hGlobal);
ReleaseStgMedium(&mediumDescriptor);
hr = dataobj->GetData(&fmtContents, &mediumContents);
if (!hr)
{
// zapisz plik w \temp\zipdemo\szDisplayName
strcpy(pFileName, szDisplayName);
IStream *file;
hr = SHCreateStreamOnFile(szSavePath, STGM_READ | STGM_WRITE | STGM_CREATE, &file);
mediumContents.pstm->CopyTo(file, liSize, NULL, NULL);
file->Release();
GlobalUnlock(mediumDescriptor.hGlobal);
ReleaseStgMedium(&mediumContents);
}
}
dataobj->Release();
}
CoTaskMemFree(pidlItems);
}
psfParent->Release();
CoTaskMemFree(pidlChild);
}
CoTaskMemFree(pidl);
}
}
//q:pousuwalem troche whitespaceow zeby lepiej sie miescilo
Witam,
Po poprawieniu dosyć sporej ilości błędów, lista plików w zipie wyświetla mi się w konsoli. Ale kombinuję i kombinuję i nie mogę wykombinować jak go teraz wypakować... Otóż wszystkie funkcje zwracają S_OK, a nawet pusty plik nie zostaje stworzony... Doszedłem już, że wina leży gdzieś przy odczytu z 'mediumContents.pstm'. Help...
wystarczy podpiąć dll-kę,
np 7-zip.dll ma własny dialogbox wraz z progress-em
Chyba się nie zrozumieliśmy...
Skopiowałem powyższy kod do VSC++ 2008 Express, zacząłem poprawiać błędy - na początku kompilatora, potem poszczególne funkcje... (Bo Od razu pierwszy if był pomijany -> funkcja zwracała błąd).
Eh, oto mój, poprawiony, kod:
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
//#include <vcl.h>
#pragma hdrstop
//#pragma argsused
//#pragma link "shell32.lib"
//#pragma link "shlwapi.lib"
#include <shlobj.h>
#include <shlwapi.h>
#include <iostream>
#include <Objbase.h>
// TODO: reference additional headers your program requires here
// unzip.cpp : main project file.
#include "stdafx.h"
#define NO_WIN32_LEAN_AND_MEAN
using namespace System;
using namespace std;
void ExtractRootFiles()
{
printf(" Let's start\n");
IShellFolder *psfZip = NULL;
IShellFolder *psfParent = NULL;
LPITEMIDLIST pidl = ILCreateFromPathA(LPCSTR("C:\\test.zip"));
printf(" 1.if\n");
if (pidl) {
printf(" 2.ini...\n");
LPITEMIDLIST pidlChild;
LPCITEMIDLIST pidlChild2 = NULL;
if (!SHBindToParent(pidl, IID_IShellFolder, (void**)&psfParent, &pidlChild2)) {
if (pidlChild2 == NULL) {printf(" Blad!!\n"); return;}
printf(" 3.szukanie?...\n");
pidlChild = (LPITEMIDLIST) pidlChild2;
//CoTaskMemFree(pidlChild2);
psfParent->BindToObject(pidlChild, NULL, IID_IShellFolder, (void**)&psfZip);
if (psfZip == NULL) {printf(" Blad!!\n"); return;}
char szDisplayName[MAX_PATH];
/*char szSavePath[MAX_PATH];
szSavePath[0]= 'C';
szSavePath[1]= ':';
szSavePath[2]= '\\';
strcat_s(szSavePath, "test");*/
string szSavePath ("C:\\test2\\");
//LPSECURITY_ATTRIBUTES attr = NULL;
//if (CreateDirectory(LPCTSTR("C:\\test2"), attr)) {printf(" true\n");}
//else printf(" false\n");
//szSavePath.append("\\");
printf(" Sciezka: %s\n", szSavePath.c_str());
//char *pFileName = &szSavePath[strlen(szSavePath.c_str())];
//if (*pFileName == NULL) {printf("Blad!\n");}
//printf(" 4.do katalogu\n");
IEnumIDList *penum = NULL;
//IShellFolder *penum2 = NULL;
/*psfZip->BindToObject(pidlChild, NULL, IID_IShellFolder, (void**)&penum);
if (penum == NULL) {printf(" Blad!!\n"); return;}*/
psfZip->EnumObjects(NULL, SHCONTF_NONFOLDERS, &penum);
if (penum == NULL) {printf(" Blad!!\n"); return;}
/*penum2->EnumObjects(NULL, SHCONTF_NONFOLDERS, &penum);
if (penum == NULL) {printf(" Blad!!\n"); return;}*/
ULONG celtFetched;
ITEMIDLIST *pidlItems = NULL;
printf(" 4.pliki:\n");
HRESULT hr;
//hr = penum->Next((ULONG)i, &pidlItems, &celtFetched);
//if (hr == S_FALSE) {printf(" ==S_FALSE\n");}
while (!penum->Next(1, &pidlItems, &celtFetched) && celtFetched+1) {
printf("\n");
//printf(" while:\n");
//getchar();
STRRET strDispName;
//psfZip->BindToObject`
psfZip->GetDisplayNameOf(LPCITEMIDLIST(pidlItems), SHGDN_INFOLDER, &strDispName);
StrRetToBuf(&strDispName, pidlItems, LPWSTR(szDisplayName), MAX_PATH);
printf(" - ");
int i= 0;
while (szDisplayName[2*i] != 0) {
printf("%c", szDisplayName[2*i]);
szDisplayName[i]= szDisplayName[2*i];
i++;
}
szDisplayName[i]= '\0';
printf("\n");
IDataObject *dataobj;
hr = psfZip->GetUIObjectOf(0, 1, (LPCITEMIDLIST*)(&pidlItems), IID_IDataObject, 0, IID_PPV_ARGS_Helper(&dataobj));
if (hr != S_OK) {printf(" blad!\n");}
if (!psfZip->GetUIObjectOf(0, 1, (LPCITEMIDLIST*)(&pidlItems), IID_IDataObject, 0, IID_PPV_ARGS_Helper(&dataobj))) {
printf(" if:\n");
int FormatBits = 0;
FORMATETC fmt;
FORMATETC fmtDescriptor;
FORMATETC fmtContents;
STGMEDIUM mediumContents;
STGMEDIUM mediumDescriptor;
UINT CF_FILEDESCRIPTORA = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA);
UINT CF_FILEDESCRIPTORW = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW);
UINT CF_FILECONTENTS = RegisterClipboardFormat(CFSTR_FILECONTENTS);
IEnumFORMATETC *formats;
hr = dataobj->EnumFormatEtc(DATADIR_GET, &formats);
if (hr != S_OK) {printf(" blad!\n");}
while (!formats->Next(1, &fmt, &celtFetched) && celtFetched) {
//printf(" wh:\n");
if ((!(FormatBits & 1)) && ((fmt.cfFormat == CF_FILEDESCRIPTORA) || (fmt.cfFormat == CF_FILEDESCRIPTORW))) {
//printf(" if:\n");
FormatBits |= 1;
MoveMemory(&fmtDescriptor, &fmt, sizeof(FORMATETC));
//printf(" %d\n", FormatBits);
}
else if ((!(FormatBits & 2)) && (fmt.cfFormat == CF_FILECONTENTS)) {
//printf(" if:\n");
FormatBits |= 2;
MoveMemory(&fmtContents, &fmt, sizeof(FORMATETC));
//printf(" %d\n", FormatBits);
}
//printf(" %d\n", fmtContents.lindex);
}
if (FormatBits == 3) printf(" FormatBits... OK\n");
formats->Release();
fmtContents.lindex = 0;
// FormatBits musi być równe 3
hr = dataobj->GetData(&fmtDescriptor, &mediumDescriptor);
//printf(": %s.\n", (char*) mediumDescriptor.lpszFileName);
if (!hr) {
printf(" jadziem:\n");
FILEGROUPDESCRIPTOR *pdsc = (FILEGROUPDESCRIPTOR*) GlobalLock(mediumDescriptor.hGlobal);
ULARGE_INTEGER liSize;
liSize.LowPart = pdsc->fgd[0].nFileSizeLow;
liSize.HighPart = pdsc->fgd[0].nFileSizeHigh;
if (!GlobalUnlock(mediumDescriptor.hGlobal)) printf(" blad!\n");
ReleaseStgMedium(&mediumDescriptor);
hr = dataobj->GetData(&fmtContents, &mediumContents);
//printf(": %s.\n", (char*) mediumContents.lpszFileName);
if (hr) printf(" blad!\n");
if (!hr) {
szSavePath.append(szDisplayName);
printf(" plik: %s.\n", szDisplayName);
IStream *file;
//
char c[256] = "C:\\test2\\";
strcat(c, szDisplayName);
printf(" zapisuje plik: %s.\n", c);
hr = SHCreateStreamOnFile(LPCWSTR(c), STGM_READ | STGM_WRITE | STGM_CREATE, &file);
if (hr != S_OK) printf(" Nie utworzono pliku!\n");
if (mediumContents.pstm->CopyTo(file, liSize, NULL, NULL) == S_OK) printf(" skopiowano.\n");
char* p;
char** pp= &p;
mediumContents.pstm->Read(pp, 10, NULL);
//file->Read(p ,8, NULL);
printf(" plik: %s...\n", &pp);
//getchar();
if (file->Release() == S_OK) printf(" zamknieto.\n");
GlobalUnlock(mediumDescriptor.hGlobal);
ReleaseStgMedium(&mediumContents);
}
}
dataobj->Release();
}
//CoTaskMemFree(pidlItems);
}
psfParent->Release();
//CoTaskMemFree(pidlChild);
}
CoTaskMemFree(pidl);
}
}
int main()
{
//printf("start?\n");
//getchar();
ExtractRootFiles();
printf("\n\n\ndone!!");
getchar();
return 0;
}
Każdy 'printf' z informacją sukcesu wyświetla się. Ale nawet pusty plik nie zostaje stworzony...
Gdy 'C:\test.zip' zawierał 2 pliki, to nazwy tych plików zostały wyświetlane. Gdy był spakowany folder i w nim pliki, wyświetlona została tylko nazwa tego katalogu. Potrzebuje jednak rozpakować zipa, w którym siedzą 4 katalogi, a w nich po kilkadziesiąt plików (<300KB). Z tego co się 'douczyłem' (z kodami powłoki mam pierwszy raz styczność) wystarczy jeszcze dodać jeden obiekt, ale moje intuicyjne próby nie powiodły się.
Krytykujcie...
Napiszmy to inaczej, używajac IShellFolder tylko chwilowo:
// extractzip.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <shlobj.h>
#include <shlwapi.h>
#define ZIP_PATH _T("D:\\download\\myzip.zip")
#define UNPACK_TO _T("D:\\download\\myzip")
void EnumZipFiles(IStorage *storage, TCHAR *pszTargetDir)
{
IMalloc *memory;
if (CoGetMalloc(1, &memory)) return;
CreateDirectory(pszTargetDir, NULL); // sprawdź błąd
IEnumSTATSTG *enumerator;
if (!storage->EnumElements(0,0,0,&enumerator))
{
ULONG celtFetched;
STATSTG stat;
while (!enumerator->Next(1, &stat, &celtFetched) && celtFetched)
{
if (stat.pwcsName)
{
TCHAR *pszPath = new TCHAR[lstrlen(pszTargetDir)+wcslen(stat.pwcsName)+2];
if (pszPath)
{
#ifdef UNICODE
wsprintf(pszPath, L"%s\\%s", pszTargetDir, stat.pwcsName);
#else
wsprintf(pszPath, "%s\\%S", pszTargetDir, stat.pwcsName);
#endif
if (stat.type == STGTY_STORAGE) // katalog
{
IStorage *subfolder;
if (!storage->OpenStorage(stat.pwcsName, 0, STGM_READ, 0, 0, &subfolder))
{
EnumZipFiles(subfolder, pszPath);
subfolder->Release();
}
}
else if (stat.type == STGTY_STREAM) // plik
{
_tprintf(_T("processing %s "), pszPath);
if (stat.cbSize.QuadPart < 1024ul)
_tprintf(_T("(%d bytes)\n"), stat.cbSize.LowPart);
else if (stat.cbSize.QuadPart < 1048576ul)
_tprintf(_T("(%.2f KB)\n"), (double)(stat.cbSize.LowPart/1024.0));
else
_tprintf(_T("(%.2f MB)\n"), (double)(stat.cbSize.QuadPart/1048576.0));
IStream *stream;
if (!storage->OpenStream(stat.pwcsName, 0, STGM_READ, 0, &stream))
{
IStream *file;
if (!SHCreateStreamOnFile(pszPath, STGM_WRITE | STGM_CREATE, &file))
{
stream->CopyTo(file, stat.cbSize, NULL, NULL);
file->Release();
}
stream->Release();
}
}
delete pszPath;
}
memory->Free(stat.pwcsName);
}
}
enumerator->Release();
}
memory->Release();
}
void ExtractZip(TCHAR *pszZip, TCHAR *pszTargetDir)
{
ITEMIDLIST *pidl = ILCreateFromPath(pszZip);
if (pidl)
{
IShellFolder *psfParent;
ITEMIDLIST *pidlChild;
if (!SHBindToParent(pidl, IID_IShellFolder, (void**)&psfParent, (LPCITEMIDLIST*)&pidlChild))
{
IStorage *storage;
if (!psfParent->BindToObject(pidlChild, NULL, IID_IStorage, (void**)&storage))
{
EnumZipFiles(storage, pszTargetDir);
storage->Release();
}
psfParent->Release();
}
ILFree(pidl);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(0);
ExtractZip(ZIP_PATH, UNPACK_TO);
CoUninitialize();
return 0;
}
WIELKIE DZIĘKI!!!
Działa:
// unzip2.cpp : main project file.
// extractzip.cpp : Defines the entry point for the console application.
//
#include "stdafx.h" //pusty
#include <stdio.h>
#include <shlobj.h>
#include <shlwapi.h>
#include <windows.h>
#define ZIP_PATH ("C:\\test.zip")
#define UNPACK_TO ("C:\\test3")
void EnumZipFiles(IStorage *storage, LPCWSTR pszTargetDir)
{
IMalloc *memory;
if (CoGetMalloc(1, &memory)) return;
if (CreateDirectoryA((LPCSTR)pszTargetDir, NULL)) printf(" Folder %s utworzono.\n", pszTargetDir); //(1.)
else if (GetLastError() == ERROR_ALREADY_EXISTS) printf(" Folder %s juz istnial.\n", pszTargetDir);
else printf(" Nie udalo sie utworzyc folderu %s\n", pszTargetDir);
IEnumSTATSTG *enumerator;
if (!storage->EnumElements(0,0,0,&enumerator))
{
ULONG celtFetched;
STATSTG stat;
while (!enumerator->Next(1, &stat, &celtFetched) && celtFetched)
{
if (stat.pwcsName)
{
TCHAR *pszPath = new TCHAR[lstrlen(pszTargetDir)+wcslen(stat.pwcsName)+2];
if (pszPath)
{
#ifdef UNICODE
wsprintf(pszPath, L"%s", pszTargetDir);
#else
wsprintf(pszPath, "%s", pszTargetDir);
#endif //tak działają powyższe funkcje... :/
char name[256];
name[0]= '\\';
//strcat(name, (char*) stat.pwcsName); //nie dziala
//{
int i= 0;
while (stat.pwcsName[i] != '\0') {
name[i+1]= (char)stat.pwcsName[i];
i++;
}
name[i+1]= '\0';
// } najpewniej ;p (2.)
strcat((char*) pszPath, name);
if (stat.type == STGTY_STORAGE) // katalog
{
IStorage *subfolder;
if (!storage->OpenStorage(stat.pwcsName, 0, STGM_READ, 0, 0, &subfolder))
{
EnumZipFiles(subfolder, pszPath);
subfolder->Release();
}
}
else if (stat.type == STGTY_STREAM) // plik
{
printf((" processing %s "), pszPath);
if (stat.cbSize.QuadPart < 1024ul)
printf(("(%d bytes)\n"), stat.cbSize.LowPart);
else if (stat.cbSize.QuadPart < 1048576ul)
printf(("(%.2f KB)\n"), (double)(stat.cbSize.LowPart/1024.0));
else
printf(("(%.2f MB)\n"), (double)(stat.cbSize.QuadPart/1048576.0));
IStream *stream;
if (!storage->OpenStream(stat.pwcsName, 0, STGM_READ, 0, &stream))
{
IStream *file;
if (!SHCreateStreamOnFileA((LPCSTR)pszPath, STGM_WRITE | STGM_CREATE, &file))
{
stream->CopyTo(file, stat.cbSize, NULL, NULL);
file->Release();
}
stream->Release();
}
}
delete pszPath;
}
memory->Free(stat.pwcsName);
}
}
enumerator->Release();
}
memory->Release();
}
void ExtractZip(LPCWSTR pszZip, LPCWSTR pszTargetDir) {
//printf("Let's start\n");
printf("adres zipa:%s, adres docelowy:%s.\n\n", pszZip, pszTargetDir);
ITEMIDLIST *pidl = ILCreateFromPathA((LPCSTR)pszZip); //(3.)
if (pidl) {
IShellFolder *psfParent;
ITEMIDLIST *pidlChild;
if (!SHBindToParent(pidl, IID_IShellFolder, (void**)&psfParent, (LPCITEMIDLIST*)&pidlChild))
{
IStorage *storage;
if (!psfParent->BindToObject(pidlChild, NULL, IID_IStorage, (void**)&storage))
{
EnumZipFiles(storage, pszTargetDir);
storage->Release();
}
psfParent->Release();
}
ILFree(pidl);
}
}
int main() {
CoInitialize(0);
ExtractZip((LPCWSTR)ZIP_PATH, (LPCWSTR)UNPACK_TO);
CoUninitialize();
printf("--end.\n");
getchar();
return 0;
}
Ale jestem głodny wiedzy: (odnośniki z kodu)
(1.) CreateDirectory: Nie działało. Na wszelkie sposoby. Dopiero CreateDirectoryA zadziałało...
(2.) #ifdef UNICODE...: też nie działało w pełni: kopiowana była tylko pierwsza zmienna, ani '\' ani druga zmienna nie była dodawana... Dopiero 'na piechotę'... ;)
(3.) ILCreateFromPath: Też nie działało. Też dopiero ILCreateFromPathA...
O co tu chodzi?? Mam wrażenie, jakby te UNICODE było włączone, a nie działało.... (bądź odwrotnie....)
Kod jest ok, niepotrzebnie go pozmieniałeś, wszystko przez to, że stdafx wyczyściłeś i ci TCHAR'a nie znał, po co [glowa] . Jak ci stdafx przeszkadza, to możesz <tchar.h> zaincluduować i kod sapero będzie w porząsiu. Dziwne, że ci to w ogóle zadziałało po tym rzutowaniu LPWSTR na LPSTR...
mi VSC++ 2008 Express Edition w 'stdafx.h' nic nie dodaje. A wyczyściłem, dokładniej przekopiowałem całość z stdafx.h do *.cpp dla jasności kodu - żeby już tego nie rozbijać. Nie wiedziałem o '<tchar.h>' więc zrobiłem tak...
Wracając do mojego pytania. Czy da się jakoś wyłączyć te UNICODE??