1. 程式人生 > >C++ 呼叫7z SDK 解壓

C++ 呼叫7z SDK 解壓

        7z SDK 解壓編譯後,可以用"C 模式"解壓,也可以用"CPP 模式"。C可以在記憶體中解壓,但是很多時候不成功,是由於malloc分配不到記憶體。CPP不用擔心記憶體問題,但是它解壓的時候佔用CPU較高。

       程式碼:

// Test7z.cpp : 定義控制檯應用程式的入口點。
//

#include "stdafx.h"
#include "Common/IntToString.h"
#include "Common/MyInitGuid.h"
#include "Common/StringConvert.h"

#include "Windows/DLL.h"
#include "Windows/FileDir.h"
#include "Windows/FileFind.h"
#include "Windows/FileName.h"
#include "Windows/NtCheck.h"
#include "Windows/PropVariant.h"
#include "Windows/PropVariantConversions.h"

#include "7Z/CPP/7zip/Common/FileStreams.h"

#include "7Z/CPP/7zip/Archive/IArchive.h"

#include "7Z/CPP/7zip/IPassword.h"
#include "7Z/CPP/7zip/MyVersion.h"

// use another CLSIDs, if you want to support other formats (zip, rar, ...).
// {23170F69-40C1-278A-1000-000110070000}
DEFINE_GUID(CLSID_CFormat7z, 0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x07, 0x00, 0x00);

using namespace NWindows;


typedef UINT32 (WINAPI * CreateObjectFunc)(const GUID *clsID, const GUID *interfaceID, void **outObject);


void PrintString(const UString &s)
{
	printf("%s", (LPCSTR)GetOemString(s));
}
void PrintString(const AString &s)
{
	printf("%s", (LPCSTR)s);
}
void PrintNewLine()
{
	PrintString("\n");
}
void PrintStringLn(const AString &s)
{
	PrintString(s);
	PrintNewLine();
}
void PrintError(const AString &s)
{
	PrintNewLine();
	PrintString(s);
	PrintNewLine();
}

static HRESULT IsArchiveItemProp(IInArchive *archive, UInt32 index, PROPID propID, bool &result)
{
	NCOM::CPropVariant prop;
	RINOK(archive->GetProperty(index, propID, &prop));
	if (prop.vt == VT_BOOL){
		result = VARIANT_BOOLToBool(prop.boolVal);
	}
	else if (prop.vt == VT_EMPTY){
		result = false;
	}
	else{
		return E_FAIL;
	}
	return S_OK;
}
static HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result)
{
	return IsArchiveItemProp(archive, index, kpidIsDir, result);
}


static const wchar_t *kEmptyFileAlias = L"[Content]";


//////////////////////////////////////////////////////////////
// Archive Open callback class


class CArchiveOpenCallback: public IArchiveOpenCallback, public ICryptoGetTextPassword, public CMyUnknownImp
{
public:
	MY_UNKNOWN_IMP1(ICryptoGetTextPassword)


	STDMETHOD(SetTotal)(const UInt64 *files, const UInt64 *bytes);
	STDMETHOD(SetCompleted)(const UInt64 *files, const UInt64 *bytes);
	STDMETHOD(CryptoGetTextPassword)(BSTR *password);

	bool PasswordIsDefined;
	UString Password;

	CArchiveOpenCallback() : PasswordIsDefined(false) {}
};

STDMETHODIMP CArchiveOpenCallback::SetTotal(const UInt64 * /* files */, const UInt64 * /* bytes */)
{
	return S_OK;
}
STDMETHODIMP CArchiveOpenCallback::SetCompleted(const UInt64 * /* files */, const UInt64 * /* bytes */)
{
	return S_OK;
}
STDMETHODIMP CArchiveOpenCallback::CryptoGetTextPassword(BSTR *password)
{
	if (!PasswordIsDefined){
		// You can ask real password here from user
		// Password = GetPassword(OutStream);
		// PasswordIsDefined = true;
		PrintError("Password is not defined");
		return E_ABORT;
	}
	return StringToBstr(Password, password);
}


//////////////////////////////////////////////////////////////
// Archive Extracting callback class

static const wchar_t *kCantDeleteOutputFile = L"ERROR: Can not delete output file ";

static const char *kTestingString    =  "Testing     ";
static const char *kExtractingString =  "Extracting  ";
static const char *kSkippingString   =  "Skipping    ";

static const char *kUnsupportedMethod = "Unsupported Method";
static const char *kCRCFailed = "CRC Failed";
static const char *kDataError = "Data Error";
static const char *kUnknownError = "Unknown Error";

class CArchiveExtractCallback: public IArchiveExtractCallback, public ICryptoGetTextPassword, public CMyUnknownImp
{
public:
	MY_UNKNOWN_IMP1(ICryptoGetTextPassword)

		// IProgress
	STDMETHOD(SetTotal)(UInt64 size);
	STDMETHOD(SetCompleted)(const UInt64 *completeValue);

	// IArchiveExtractCallback
	STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode);
	STDMETHOD(PrepareOperation)(Int32 askExtractMode);
	STDMETHOD(SetOperationResult)(Int32 resultEOperationResult);

	// ICryptoGetTextPassword
	STDMETHOD(CryptoGetTextPassword)(BSTR *aPassword);

private:
	CMyComPtr<IInArchive> _archiveHandler;
	UString _directoryPath;  // Output directory
	UString _filePath;       // name inside arcvhive
	UString _diskFilePath;   // full path to file on disk
	bool _extractMode;
	struct CProcessedFileInfo
	{
		FILETIME MTime;
		UInt32 Attrib;
		bool isDir;
		bool AttribDefined;
		bool MTimeDefined;
	} _processedFileInfo;

	COutFileStream *_outFileStreamSpec;
	CMyComPtr<ISequentialOutStream> _outFileStream;

public:
	void Init(IInArchive *archiveHandler, const UString &directoryPath);

	UInt64 nFilesize;
	UInt64 NumErrors;
	bool PasswordIsDefined;
	UString Password;

	CArchiveExtractCallback() : PasswordIsDefined(false) {}
};

void CArchiveExtractCallback::Init(IInArchive *archiveHandler, const UString &directoryPath)
{
	NumErrors = 0;
	_archiveHandler = archiveHandler;
	_directoryPath = directoryPath;
	NFile::NName::NormalizeDirPathPrefix(_directoryPath);
}

STDMETHODIMP CArchiveExtractCallback::SetTotal(UInt64 size)
{
	nFilesize = size;
	return S_OK;
}
STDMETHODIMP CArchiveExtractCallback::SetCompleted(const UInt64 * completeValue)
{
	printf("%.2f\n", static_cast<float>((float)(*completeValue) / (float)nFilesize * 100.0f));
	return S_OK;
}
STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode)
{
	*outStream = 0;
	_outFileStream.Release();

	{
		// Get Name
		NCOM::CPropVariant prop;
		RINOK(_archiveHandler->GetProperty(index, kpidPath, &prop));

		UString fullPath;
		if (prop.vt == VT_EMPTY){
			fullPath = kEmptyFileAlias;
		}
		else{
			if (prop.vt != VT_BSTR){
				return E_FAIL;
			}
			fullPath = prop.bstrVal;
		}
		_filePath = fullPath;
	}

	if (askExtractMode != NArchive::NExtract::NAskMode::kExtract){
		return S_OK;
	}
	{
		// Get Attrib
		NCOM::CPropVariant prop;
		RINOK(_archiveHandler->GetProperty(index, kpidAttrib, &prop));
		if (prop.vt == VT_EMPTY){
			_processedFileInfo.Attrib = 0;
			_processedFileInfo.AttribDefined = false;
		}
		else{
			if (prop.vt != VT_UI4){
				return E_FAIL;
			}
			_processedFileInfo.Attrib = prop.ulVal;
			_processedFileInfo.AttribDefined = true;
		}
	}

	RINOK(IsArchiveItemFolder(_archiveHandler, index, _processedFileInfo.isDir));

	{
		// Get Modified Time
		NCOM::CPropVariant prop;
		RINOK(_archiveHandler->GetProperty(index, kpidMTime, &prop));
		_processedFileInfo.MTimeDefined = false;
		switch(prop.vt){
		case VT_EMPTY:{
			// _processedFileInfo.MTime = _utcMTimeDefault;
			break;
					  }
		case VT_FILETIME:{
			_processedFileInfo.MTime = prop.filetime;
			_processedFileInfo.MTimeDefined = true;
			break;
						 }
		default:{
			return E_FAIL;
				}
		}
	}
	{
		// Get Size
		NCOM::CPropVariant prop;
		RINOK(_archiveHandler->GetProperty(index, kpidSize, &prop));
		bool newFileSizeDefined = (prop.vt != VT_EMPTY);
		UInt64 newFileSize;
		if (newFileSizeDefined){
			newFileSize = ConvertPropVariantToUInt64(prop);
		}
	}

	{
		// Create folders for file
		int slashPos = _filePath.ReverseFind(WCHAR_PATH_SEPARATOR);
		if (slashPos >= 0){
			NFile::NDirectory::CreateComplexDirectory(_directoryPath + _filePath.Left(slashPos));
		}
	}

	UString fullProcessedPath = _directoryPath + _filePath;
	_diskFilePath = fullProcessedPath;

	if (_processedFileInfo.isDir){
		NFile::NDirectory::CreateComplexDirectory(fullProcessedPath);
	}
	else{
		NFile::NFind::CFileInfoW fi;
		if (fi.Find(fullProcessedPath)){
			if (!NFile::NDirectory::DeleteFileAlways(fullProcessedPath)){
				PrintString(UString(kCantDeleteOutputFile) + fullProcessedPath);
				return E_ABORT;
			}
		}

		_outFileStreamSpec = new COutFileStream;
		CMyComPtr<ISequentialOutStream> outStreamLoc(_outFileStreamSpec);
		if (!_outFileStreamSpec->Open(fullProcessedPath, CREATE_ALWAYS)){
			PrintString((UString)L"can not open output file " + fullProcessedPath);
			return E_ABORT;
		}
		_outFileStream = outStreamLoc;
		*outStream = outStreamLoc.Detach();
	}
	return S_OK;
}
STDMETHODIMP CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode)
{
	_extractMode = false;
	switch (askExtractMode)
	{
	case NArchive::NExtract::NAskMode::kExtract:  _extractMode = true; break;
	};
	switch (askExtractMode)
	{
	case NArchive::NExtract::NAskMode::kExtract:  PrintString(kExtractingString); break;
	case NArchive::NExtract::NAskMode::kTest:  PrintString(kTestingString); break;
	case NArchive::NExtract::NAskMode::kSkip:  PrintString(kSkippingString); break;
	};
	PrintString(_filePath);
	return S_OK;
}
STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 operationResult)
{
	switch(operationResult)
	{
	case NArchive::NExtract::NOperationResult::kOK:
		break;
	default:
		{
			NumErrors++;
			PrintString("     ");
			switch(operationResult)
			{
			case NArchive::NExtract::NOperationResult::kUnSupportedMethod:
				PrintString(kUnsupportedMethod);
				break;
			case NArchive::NExtract::NOperationResult::kCRCError:
				PrintString(kCRCFailed);
				break;
			case NArchive::NExtract::NOperationResult::kDataError:
				PrintString(kDataError);
				break;
			default:
				PrintString(kUnknownError);
			}
		}
	}

	if (_outFileStream != NULL){
		if (_processedFileInfo.MTimeDefined){
			_outFileStreamSpec->SetMTime(&_processedFileInfo.MTime);
		}
		RINOK(_outFileStreamSpec->Close());
	}
	_outFileStream.Release();
	if (_extractMode && _processedFileInfo.AttribDefined){
		NFile::NDirectory::MySetFileAttributes(_diskFilePath, _processedFileInfo.Attrib);
	}
	PrintNewLine();
	return S_OK;
}
STDMETHODIMP CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password)
{
	if (!PasswordIsDefined){
		// You can ask real password here from user
		// Password = GetPassword(OutStream);
		// PasswordIsDefined = true;
		PrintError("Password is not defined");
		return E_ABORT;
	}
	return StringToBstr(Password, password);
}



//////////////////////////////////////////////////////////////
// Archive Creating callback class

struct CDirItem
{
	UInt64 Size;
	FILETIME CTime;
	FILETIME ATime;
	FILETIME MTime;
	UString Name;
	UString FullPath;
	UInt32 Attrib;

	bool isDir() const {
		return (Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0 ;
	}
};

class CArchiveUpdateCallback: public IArchiveUpdateCallback2, public ICryptoGetTextPassword2, public CMyUnknownImp
{
public:
	MY_UNKNOWN_IMP2(IArchiveUpdateCallback2, ICryptoGetTextPassword2)

		// IProgress
		STDMETHOD(SetTotal)(UInt64 size);
	STDMETHOD(SetCompleted)(const UInt64 *completeValue);

	// IUpdateCallback2
	STDMETHOD(EnumProperties)(IEnumSTATPROPSTG **enumerator);
	STDMETHOD(GetUpdateItemInfo)(UInt32 index, Int32 *newData, Int32 *newProperties, UInt32 *indexInArchive);
	STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value);
	STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **inStream);
	STDMETHOD(SetOperationResult)(Int32 operationResult);
	STDMETHOD(GetVolumeSize)(UInt32 index, UInt64 *size);
	STDMETHOD(GetVolumeStream)(UInt32 index, ISequentialOutStream **volumeStream);

	STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *password);

public:
	CRecordVector<UInt64> VolumesSizes;
	UString VolName;
	UString VolExt;

	UString DirPrefix;
	const CObjectVector<CDirItem> *DirItems;

	bool PasswordIsDefined;
	UString Password;
	bool AskPassword;

	bool m_NeedBeClosed;

	UStringVector FailedFiles;
	CRecordVector<HRESULT> FailedCodes;

	CArchiveUpdateCallback(): PasswordIsDefined(false), AskPassword(false), DirItems(0) {};

	~CArchiveUpdateCallback() { Finilize(); }
	HRESULT Finilize();

	void Init(const CObjectVector<CDirItem> *dirItems)
	{
		DirItems = dirItems;
		m_NeedBeClosed = false;
		FailedFiles.Clear();
		FailedCodes.Clear();
	}
};

STDMETHODIMP CArchiveUpdateCallback::SetTotal(UInt64 /* size */)
{
	return S_OK;
}
STDMETHODIMP CArchiveUpdateCallback::SetCompleted(const UInt64 * /* completeValue */)
{
	return S_OK;
}
STDMETHODIMP CArchiveUpdateCallback::EnumProperties(IEnumSTATPROPSTG ** /* enumerator */)
{
	return E_NOTIMPL;
}
STDMETHODIMP CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 /* index */, Int32 *newData, Int32 *newProperties, UInt32 *indexInArchive)
{
	if (newData != NULL){
		*newData = BoolToInt(true);
	}
	if (newProperties != NULL){
		*newProperties = BoolToInt(true);
	}
	if (indexInArchive != NULL){
		*indexInArchive = (UInt32)-1;
	}
	return S_OK;
}
STDMETHODIMP CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
	NWindows::NCOM::CPropVariant prop;
	if (propID == kpidIsAnti){
		prop = false;
		prop.Detach(value);
		return S_OK;
	}

	{
		const CDirItem &dirItem = (*DirItems)[index];
		switch(propID)
		{
		case kpidPath:  prop = dirItem.Name; break;
		case kpidIsDir:  prop = dirItem.isDir(); break;
		case kpidSize:  prop = dirItem.Size; break;
		case kpidAttrib:  prop = dirItem.Attrib; break;
		case kpidCTime:  prop = dirItem.CTime; break;
		case kpidATime:  prop = dirItem.ATime; break;
		case kpidMTime:  prop = dirItem.MTime; break;
		}
	}
	prop.Detach(value);
	return S_OK;
}

HRESULT CArchiveUpdateCallback::Finilize()
{
	if (m_NeedBeClosed){
		PrintNewLine();
		m_NeedBeClosed = false;
	}
	return S_OK;
}

static void GetStream2(const wchar_t *name)
{
	PrintString("Compressing  ");
	if (name[0] == 0){
		name = kEmptyFileAlias;
	}
	PrintString(name);
}

STDMETHODIMP CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream)
{
	RINOK(Finilize());

	const CDirItem &dirItem = (*DirItems)[index];
	GetStream2(dirItem.Name);

	if (dirItem.isDir()){
		return S_OK;
	}
	{
		CInFileStream *inStreamSpec = new CInFileStream;
		CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
		UString path = DirPrefix + dirItem.FullPath;
		if (!inStreamSpec->Open(path)){
			DWORD sysError = ::GetLastError();
			FailedCodes.Add(sysError);
			FailedFiles.Add(path);
			// if (systemError == ERROR_SHARING_VIOLATION)
			{
				PrintNewLine();
				PrintError("WARNING: can't open file");
				// PrintString(NError::MyFormatMessageW(systemError));
				return S_FALSE;
			}
			// return sysError;
		}
		*inStream = inStreamLoc.Detach();
	}
	return S_OK;
}
STDMETHODIMP CArchiveUpdateCallback::SetOperationResult(Int32 /* operationResult */)
{
	m_NeedBeClosed = true;
	return S_OK;
}
STDMETHODIMP CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size)
{
	if (VolumesSizes.Size() == 0){
		return S_FALSE;
	}
	if (index >= (UInt32)VolumesSizes.Size()){
		index = VolumesSizes.Size() - 1;
	}
	*size = VolumesSizes[index];
	return S_OK;
}
STDMETHODIMP CArchiveUpdateCallback::GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream)
{
	wchar_t temp[16];
	ConvertUInt32ToString(index + 1, temp);
	UString res = temp;
	while (res.Length() < 2){
		res = UString(L'0') + res;
	}
	UString fileName = VolName;
	fileName += L'.';
	fileName += res;
	fileName += VolExt;
	COutFileStream *streamSpec = new COutFileStream;
	CMyComPtr<ISequentialOutStream> streamLoc(streamSpec);
	if (!streamSpec->Create(fileName, false)){
		return ::GetLastError();
	}
	*volumeStream = streamLoc.Detach();
	return S_OK;
}
STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)
{
	if (!PasswordIsDefined){
		if (AskPassword){
			// You can ask real password here from user
			// Password = GetPassword(OutStream);
			// PasswordIsDefined = true;
			PrintError("Password is not defined");
			return E_ABORT;
		}
	}
	*passwordIsDefined = BoolToInt(PasswordIsDefined);
	return StringToBstr(Password, password);
}



//////////////////////////////////////////////////////////////////////////
// Main function

#define NT_CHECK_FAIL_ACTION PrintError("Unsupported Windows version"); return 1;

int MY_CDECL main(int numArgs, const char *args[])
{
	NT_CHECK

	int mmm = 0;
	while(mmm++ < 1){
		NWindows::NDLL::CLibrary lib;
		if (!lib.Load(L"7zxr.dll")){
			PrintError("Can not load 7-zip library");
			return 1;
		}
		CreateObjectFunc createObjectFunc = (CreateObjectFunc)lib.GetProc("CreateObject");
		if (createObjectFunc == 0){
			PrintError("Can not get CreateObject");
			return 1;
		}

		char c = 'x';
		UString archiveName = GetUnicodeString("E:\\123.7z");
		{
			bool listCommand;
			if (c == 'l'){
				listCommand = true;
			}
			else if (c == 'x'){
				listCommand = false;
			}
			else{
				PrintError("incorrect command");
				return 1;
			}

			CMyComPtr<IInArchive> archive;
			if (createObjectFunc(&CLSID_CFormat7z, &IID_IInArchive, (void **)&archive) != S_OK){
				PrintError("Can not get class object");
				return 1;
			}

			CInFileStream *fileSpec = new CInFileStream;
			CMyComPtr<IInStream> file = fileSpec;

			if (!fileSpec->Open(archiveName)){
				PrintError("Can not open archive file");
				return 1;
			}

			{
				CArchiveOpenCallback *openCallbackSpec = new CArchiveOpenCallback;
				CMyComPtr<IArchiveOpenCallback> openCallback(openCallbackSpec);
				openCallbackSpec->PasswordIsDefined = false;
				// openCallbackSpec->PasswordIsDefined = true;
				// openCallbackSpec->Password = L"1";

				if (archive->Open(file, 0, openCallback) != S_OK){
					PrintError("Can not open archive");
					return 1;
				}
			}

			if (listCommand){
				// List command
				UInt32 numItems = 0;
				archive->GetNumberOfItems(&numItems);
				for (UInt32 i = 0; i < numItems; i++){
					{
						// Get uncompressed size of file
						NWindows::NCOM::CPropVariant prop;
						archive->GetProperty(i, kpidSize, &prop);
						UString s = ConvertPropVariantToString(prop);
						//PrintString(s);
						//PrintString("  ");
					}
					{
						// Get name of file
						NWindows::NCOM::CPropVariant prop;
						archive->GetProperty(i, kpidPath, &prop);
						UString s = ConvertPropVariantToString(prop);
						//PrintString(s);
					}
					//PrintString("\n");
				}
			}
			else{
				// Extract command
				CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback;
				CMyComPtr<IArchiveExtractCallback> extractCallback(extractCallbackSpec);
				extractCallbackSpec->Init(archive, L"e:\\XSBDownload"); // second parameter is output folder path
				extractCallbackSpec->PasswordIsDefined = false;
				// extractCallbackSpec->PasswordIsDefined = true;
				// extractCallbackSpec->Password = L"1";
				HRESULT result = archive->Extract(NULL, (UInt32)(Int32)(-1), false, extractCallback);
				if (result != S_OK){
					PrintError("Extract Error");
					return 1;
				}
			}
		}
	}

	return 0;
}




demo:http://download.csdn.net/download/sz76211822/10039869