CBXShell/CBXShell/cbxArchive.h

790 lines
21 KiB
C++

///////////////////////////////////////////////
// v4.6
//////////////////////////////////////////////
// CCBXShell functionality implementation
#ifndef _CBXARCHIVE_442B998D_B9C0_4AB0_BB2A_BC9C0AA10053_
#define _CBXARCHIVE_442B998D_B9C0_4AB0_BB2A_BC9C0AA10053_
#ifndef STRICT
#define STRICT
#endif
#include <shlObj.h>
#include <shlwapi.h>
#pragma comment(lib,"shlwapi.lib")
//#include "gdiplus.h" // uncomment if needed
//#pragma comment(lib,"gdiplus.lib")
//ATL headers
//#include <atlstr.h> // uncomment if needed
#include <atlimage.h>
#include <atlfile.h>
// WTL headers
#include <atlgdi.h>
#include "unrar.h"
#ifdef _WIN64
#pragma comment(lib,"unrar64.lib")
#else
#pragma comment(lib,"unrar.lib")
#endif
#include "unzip.h"
#define CBXMEM_MAXBUFFER_SIZE 33554432 //32mb
#define CBXTYPE int
#define CBXTYPE_NONE 0
#define CBXTYPE_ZIP 1
#define CBXTYPE_CBZ 2
#define CBXTYPE_RAR 3
#define CBXTYPE_CBR 4
#define CBX_APP_KEY _T("Software\\T800 Productions\\{9E6ECB90-5A61-42BD-B851-D3297D9C7F39}")
namespace __cbx {
// unused
//template <class T> class CBuffer
//{
//public:
// CBuffer(){m_buf=NULL;}
// virtual ~CBuffer(){ ::CoTaskMemFree(m_buf); m_buf=NULL;}
//public:
// T* Allocate(SIZE_T s, BOOL bAutozero=FALSE)
// {
// m_buf=::CoTaskMemAlloc(s*sizeof(T));//COM compatible //'new' throws
// if (m_buf && bAutozero) SecureZeroMemory(m_buf, s*sizeof(T));
// return (T*)m_buf;
// }
// operator LPVOID () {return m_buf;}
// operator T* () {return (T*)m_buf;}
//private:
// LPVOID m_buf;
//};
//typedef CBuffer<BYTE> CByteBuffer;
class CUnzip
{
public:
CUnzip() { hz=NULL; }
virtual ~CUnzip(){::CloseZip(hz);}
public:
bool Open(LPCTSTR zfile)
{
if (zfile==NULL) return false;
HZIP temp_hz=::OpenZip(zfile, NULL);//try new
if (temp_hz==NULL) return false;
Close();//close old
hz=temp_hz;
if (ZR_OK!=::GetZipItem(hz,-1, &maindirEntry)) return false;
return true;
}
bool GetItem(int zi)
{
zr=::GetZipItem(hz, zi, &ZipEntry);
return (ZR_OK==zr);
}
bool UnzipItemToMembuffer(int index, void *z,unsigned int len)
{
zr=::UnzipItem(hz, index, z, len);
return (ZR_OK==zr);
}
void Close()
{
CloseZip(hz);
hz=NULL;//critical!
}
inline BOOL ItemIsDirectory() {return (BOOL)(CUnzip::GetItemAttributes() & 0x0010);}
int GetItemCount() const {return maindirEntry.index;}
long GetItemPackedSize() const {return ZipEntry.comp_size;}
long GetItemUnpackedSize() const {return ZipEntry.unc_size;}
DWORD GetItemAttributes() const {return ZipEntry.attr;}
LPCTSTR GetItemName() {return ZipEntry.name;}
private:
ZIPENTRY ZipEntry, maindirEntry;
HZIP hz;
ZRESULT zr;
};
// unrar wrapper
typedef const RARHeaderDataEx* LPCRARHeaderDataEx;
typedef const RAROpenArchiveDataEx* LPCRAROpenArchiveDataEx;
class CUnRar
{
public:
CUnRar() { if (RAR_DLL_VERSION>RARGetDllVersion()) throw RAR_DLL_VERSION; _init(); }
virtual ~CUnRar(){Close();_init();}
public:
BOOL Open(LPCTSTR rarfile, BOOL bListingOnly=TRUE, char* cmtBuf=NULL, UINT cmtBufSize=0, char* password=NULL)
{
if (m_harc) return FALSE;//must close old first
SecureZeroMemory(&m_arcinfo, sizeof(RAROpenArchiveDataEx));
#ifndef UNICODE
m_arcinfo.ArcName=(PTCHAR)rarfile;
#else
m_arcinfo.ArcNameW=(PTCHAR)rarfile;
#endif
m_arcinfo.OpenMode=bListingOnly ? RAR_OM_LIST : RAR_OM_EXTRACT;
m_arcinfo.CmtBuf=cmtBuf;
m_arcinfo.CmtBufSize=cmtBufSize;
m_harc=RAROpenArchiveEx(&m_arcinfo);
if (m_harc==NULL || m_arcinfo.OpenResult!=0) return FALSE;
if (password) RARSetPassword(m_harc,password);
RARSetCallback(m_harc, __rarCallbackProc, (LPARAM)this);
return TRUE;
}
BOOL Close() { if (m_harc) m_ret=RARCloseArchive(m_harc); return (m_ret!=0);}
inline LPCRAROpenArchiveDataEx GetArchiveInfo() {return &m_arcinfo;}
inline LPCRARHeaderDataEx GetItemInfo() {return &m_iteminfo;}
inline void SetPassword(char* password) {RARSetPassword(m_harc, password);}
inline int GetLastError() {return m_ret;}
//inline UINT GetArchiveFlags() {return m_arcinfo.Flags;}
//inline UINT GetItemFlags(){return m_iteminfo.Flags;}
inline BOOL IsArchiveVolume() {return (BOOL)(m_arcinfo.Flags & 0x0001);}
inline BOOL IsArchiveComment() {return (BOOL)(m_arcinfo.Flags & 0x0002);}
inline BOOL IsArchiveLocked() {return (BOOL)(m_arcinfo.Flags & 0x0004);}
inline BOOL IsArchiveSolid() {return (BOOL)(m_arcinfo.Flags & 0x0008);}
inline BOOL IsArchivePartN() {return (BOOL)(m_arcinfo.Flags & 0x0010);}
inline BOOL IsArchiveSigned() {return (BOOL)(m_arcinfo.Flags & 0x0020);}
inline BOOL IsArchiveRecoveryRecord() {return (BOOL)(m_arcinfo.Flags & 0x0040);}
inline BOOL IsArchiveEncryptedHeaders() {return (BOOL)(m_arcinfo.Flags & 0x0080);}
inline BOOL IsArchiveFirstVolume() {return (BOOL)(m_arcinfo.Flags & 0x0100);}
BOOL ReadItemInfo()
{
SecureZeroMemory(&m_iteminfo, sizeof(RARHeaderDataEx));
m_ret=RARReadHeaderEx(m_harc, &m_iteminfo);
return (m_ret==0);
}
inline BOOL IsItemDirectory() {return ((m_iteminfo.Flags & 0x00E0)==0x00E0);}
inline LPCTSTR GetItemName()
{
#ifdef UNICODE
return (LPCTSTR)(GetItemInfo()->FileNameW);
#else
return (LPCTSTR)CUnRar::GetItemInfo()->FileName;
#endif
}
//MAKEUINT64
inline UINT64 GetItemPackedSize64() {return ((((UINT64)m_iteminfo.PackSizeHigh)<<32) | m_iteminfo.PackSize);}
inline UINT64 GetItemUnpackedSize64() {return ((((UINT64)m_iteminfo.UnpSizeHigh)<<32) | m_iteminfo.UnpSize);}
virtual BOOL ProcessItem()
{
m_ret=RARProcessFileW(m_harc,RAR_TEST,NULL,NULL);
if (m_ret!=0) return FALSE;
return TRUE;
}
virtual BOOL SkipItem()
{
m_ret=RARProcessFile(m_harc,RAR_SKIP,NULL,NULL);
return (m_ret==0);
}
virtual BOOL SkipItems(UINT64 si)
{
UINT64 _i;//0 skips?
for (_i=0; _i<si; _i++) {if (!ReadItemInfo() || !SkipItem()) return FALSE;}
return TRUE;
}
virtual int CallbackProc(UINT msg, LPARAM UserData, LPARAM P1, LPARAM P2)
{
if (msg==UCM_PROCESSDATA) return ProcessItemData((LPBYTE)P1,(ULONG)P2);
return -1;
}
virtual int ProcessItemData(LPBYTE pBuf, ULONG dwBufSize)
{
if (m_pIs)
{
ULONG br=0;
if (S_OK==m_pIs->Write(pBuf, dwBufSize, &br))
if (br==dwBufSize) return 1;
}
return -1;
}
void SetIStream(IStream* pIs){_ASSERTE(pIs);m_pIs=pIs;}
private:
HANDLE m_harc;
RARHeaderDataEx m_iteminfo;
RAROpenArchiveDataEx m_arcinfo;
int m_ret;
IStream* m_pIs;
void _init()
{
m_harc=NULL;
m_pIs=NULL;
m_ret=0;
SecureZeroMemory(&m_arcinfo, sizeof(RAROpenArchiveDataEx));
SecureZeroMemory(&m_iteminfo, sizeof(RARHeaderDataEx));
}
//raw callback function
public:
static int PASCAL __rarCallbackProc(UINT msg,LPARAM UserData,LPARAM P1,LPARAM P2)
{
CUnRar* _pc=(CUnRar*)UserData;
return _pc->CallbackProc(msg,UserData,P1,P2);
}
};
class CCBXArchive
{
public:
CCBXArchive()
{
m_bSort=TRUE;//default
//GetRegSettings();
m_thumbSize.cx=m_thumbSize.cy=0;
m_cbxType=CBXTYPE_NONE;
m_pIs=NULL;
}
virtual ~CCBXArchive()
{
if (m_pIs) {m_pIs->Release(); m_pIs=NULL;}
}
public:
////////////////////////////////////////
// IPersistFile::Load
HRESULT OnLoad(LPCOLESTR wszFile)
{
//ATLTRACE("IPersistFile::Load\n");
#ifndef UNICODE
USES_CONVERSION;
m_cbxFile=OLE2T((WCHAR*)wszFile);
#else
m_cbxFile=wszFile;
#endif
m_cbxType=GetCBXType(PathFindExtension(m_cbxFile));
return S_OK;
}
////////////////////////////////////
// IExtractImage::GetLocation(LPWSTR pszPathBuffer, DWORD cchMax, DWORD *pdwPriority, const SIZE *prgSize, DWORD dwRecClrDepth, DWORD *pdwFlags)
HRESULT OnGetLocation(const SIZE *prgSize, DWORD *pdwFlags)
{
//ATLTRACE("IExtractImage2::GetLocation\n");
m_thumbSize.cx=prgSize->cx;
m_thumbSize.cy=prgSize->cy;
*pdwFlags |= (IEIFLAG_CACHE | IEIFLAG_REFRESH);//cache thumbnails
//if (*pdwFlags & IEIFLAG_ASYNC) return E_PENDING;//Windows XP and earlier
#ifdef _DEBUG
if (*pdwFlags & IEIFLAG_ASYNC) ATLTRACE("\nIExtractImage::GetLocation : IEIFLAG_ASYNC flag set\n");
#endif
return NOERROR;
}
////////////////////////////////////
// IExtractImage2::GetDateStamp(FILETIME *pDateStamp)
HRESULT OnGetDateStamp(FILETIME *pDateStamp)
{
//ATLTRACE("IExtractImage2::GetDateStamp\n");
FILETIME ftCreationTime, ftLastAccessTime, ftLastWriteTime;
CAtlFile _f;
if (S_OK!=_f.Create(m_cbxFile,GENERIC_READ,FILE_SHARE_READ,OPEN_EXISTING,0)) return E_FAIL;
//alternatively GetFileInformationByHandle?
if (!GetFileTime(_f, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime)) return E_FAIL;
*pDateStamp = ftLastWriteTime;
return NOERROR;
}
////////////////////////////////////
//IExtractImage::Extract(HBITMAP* phBmpThumbnail)
HRESULT OnExtract(HBITMAP* phBmpThumbnail)
{
*phBmpThumbnail=NULL;
//ATLTRACE("IExtractImage::Extract\n");
try {
switch (m_cbxType)
{
case CBXTYPE_ZIP:
case CBXTYPE_CBZ:
{
CUnzip _z;
if (!_z.Open(m_cbxFile)) return E_FAIL;
j=_z.GetItemCount();
if (j==0) return E_FAIL;
CString prevname;//helper vars
int thumbindex=-1;
for (i=0; i<j; i++)
{
if (!_z.GetItem(i)) break;
if (_z.ItemIsDirectory() || (_z.GetItemUnpackedSize() > CBXMEM_MAXBUFFER_SIZE)) continue;
if ((_z.GetItemPackedSize()==0) || (_z.GetItemUnpackedSize()==0)) continue;
if (IsImage(_z.GetItemName()))
{
if (thumbindex<0) thumbindex=i;// assign thumbindex if already sorted
if (!m_bSort) break;//if NoSort
if (prevname.IsEmpty()) prevname=_z.GetItemName();//can't compare empty string
//take only first alphabetical name
if (-1==StrCmpLogicalW(_z.GetItemName(), prevname))
{
thumbindex=i;
prevname=_z.GetItemName();
}
}
}//for loop
if (thumbindex<0) return E_FAIL;
//go to thumb index
if (!_z.GetItem(thumbindex)) return E_FAIL;
//create thumb //GHND
HGLOBAL hG = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, (SIZE_T)_z.GetItemUnpackedSize());
if (hG)
{
bool b=false;
LPVOID pBuf=::GlobalLock(hG);
if (pBuf)
b=_z.UnzipItemToMembuffer(thumbindex, pBuf, _z.GetItemUnpackedSize());
if (::GlobalUnlock(hG)==0 && GetLastError()==NO_ERROR)
{
if (b)
{
IStream* pIs=NULL;
if (S_OK==CreateStreamOnHGlobal(hG, TRUE, (LPSTREAM*)&pIs))//autofree hG
{
*phBmpThumbnail= ThumbnailFromIStream(pIs, &m_thumbSize);
pIs->Release();
pIs=NULL;
}
}
}
//GlobalFree(hG);//autofreed
}
return ((*phBmpThumbnail) ? S_OK : E_FAIL);
}//dtors!
break;
case CBXTYPE_RAR:
case CBXTYPE_CBR:
{
CUnRar _r;
__int64 thumbindex=-1;
if (m_bSort)
{
thumbindex=FindThumbnailSortRAR(m_cbxFile);
if (thumbindex<0) return E_FAIL;
}
if (!_r.Open(m_cbxFile, FALSE)) return E_FAIL;
if (m_bSort)
{
//archive flags already checked, go to thumbindex
if (!_r.SkipItems(thumbindex)) return E_FAIL;
if (!_r.ReadItemInfo()) return E_FAIL;
}
else
{
//skip solid (long processing time), volumes or encrypted file headers
if (_r.IsArchiveSolid() || _r.IsArchiveVolume() || _r.IsArchiveEncryptedHeaders()) return E_FAIL;
while (_r.ReadItemInfo())
{
//skip directory/empty/ file bigger than 32mb
if (!(_r.IsItemDirectory() || (_r.GetItemPackedSize64()==0) ||
(_r.GetItemUnpackedSize64()==0) || (_r.GetItemUnpackedSize64() > CBXMEM_MAXBUFFER_SIZE)))
{
if (IsImage(_r.GetItemName())) {thumbindex=TRUE; break;}
}
_r.SkipItem();//don't forget
}
}//else
if (thumbindex<0) return E_FAIL;
//create thumb
IStream* pIs = NULL;
HGLOBAL hG = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, (SIZE_T)_r.GetItemUnpackedSize64());
if (hG)
{
if (S_OK==CreateStreamOnHGlobal(hG, TRUE, (LPSTREAM*)&pIs))
{
_r.SetIStream(pIs);
if (_r.ProcessItem()) *phBmpThumbnail= ThumbnailFromIStream(pIs, &m_thumbSize);
}
}
GlobalFree(hG);
pIs->Release();
return ((*phBmpThumbnail) ? S_OK : E_FAIL );
}//dtors!
break;
default:return E_FAIL;
}
}
catch (...){ ATLTRACE("exception in IExtractImage::Extract\n"); return S_FALSE;}
return S_OK;
}
//////////////////////////////
//IQueryInfo::GetInfoTip(DWORD dwFlags, LPWSTR *ppwszTip)
HRESULT OnGetInfoTip(LPWSTR *ppwszTip)
{
//ATLTRACE("IQueryInfo::GetInfoTip\n");
try
{
CString tip;
__int64 _fs;
if (!GetFileSizeCrt(m_cbxFile, _fs)) return E_FAIL;
TCHAR _tf[16];// SecureZeroMemory?
switch (m_cbxType)
{
case CBXTYPE_ZIP:
if (_fs==0) tip=_T("ZIP Archive\nSize: 0 bytes");
else
{
if (GetImageCountZIP(m_cbxFile, i,j))
tip.Format(_T("ZIP Archive\n%d Images\n%d Files\nSize: %s"),
i, j, StrFormatByteSize64(_fs, _tf, 16));
else tip.Format(_T("ZIP Archive\nSize: %s"), StrFormatByteSize64(_fs, _tf, 16));
}
break;
case CBXTYPE_CBZ:
if (_fs==0) tip=_T("ZIP Image Archive\nSize: 0 bytes");
else
{
if (GetImageCountZIP(m_cbxFile, i,j))
tip.Format(_T("ZIP Image Archive\n%d Images\n%d Files\nSize: %s"),
i, j, StrFormatByteSize64(_fs, _tf, 16));
else tip.Format(_T("ZIP Image Archive\nSize: %s"), StrFormatByteSize64(_fs, _tf, 16));
}
break;
case CBXTYPE_RAR:
if (_fs==0) tip=_T("RAR Archive\nSize: 0 bytes");
else
{
if (GetImageCountRAR(m_cbxFile, i,j))
tip.Format(_T("RAR Archive\n%d Images\n%d Files\nSize: %s"),
i, j, StrFormatByteSize64(_fs, _tf, 16));
else tip.Format(_T("RAR Archive\nSize: %s"), StrFormatByteSize64(_fs, _tf, 16));
}
break;
case CBXTYPE_CBR:
if (_fs==0) tip=_T("RAR Image Archive\nSize: 0 bytes");
else
{
if (GetImageCountRAR(m_cbxFile, i,j))
tip.Format(_T("RAR Image Archive\n%d Images\n%d Files\nSize: %s"),
i, j, StrFormatByteSize64(_fs, _tf, 16));
else tip.Format(_T("RAR Image Archive\nSize: %s"), StrFormatByteSize64(_fs, _tf, 16));
}
break;
default: ATLTRACE("IQueryInfo::GetInfoTip : CBXTYPE_NONE\n");return E_FAIL;
}
*ppwszTip = (WCHAR*) ::CoTaskMemAlloc( (tip.GetLength()+1)*sizeof(WCHAR) );//caller must call CoTaskMemFree
if (*ppwszTip==NULL) return E_FAIL;
if (0!=::wcscpy_s(*ppwszTip, tip.GetLength()+1, tip)) return E_FAIL;
return S_OK;
}
catch (...){ ATLTRACE("exception in IQueryInfo::GetInfoTip\n"); return S_FALSE;}
return S_FALSE;
}
private:
CString m_cbxFile;//overcome MAX_PATH limit?
SIZE m_thumbSize;
int i,j;//helpers
CBXTYPE m_cbxType;
IStream* m_pIs;
BOOL m_bSort;
BOOL m_showIcon;
private:
inline BOOL GetFileSizeCrt(LPCTSTR pszFile, __int64 &fsize)
{
struct _stat64 _s;
_s.st_size=0;
if (0!=::_tstat64(pszFile, &_s)) return FALSE;
fsize=_s.st_size;
return TRUE;
}
inline BOOL StrEqual(LPCTSTR psz1,LPCTSTR psz2) {return (::StrCmpI(psz1, psz2)==0);}
BOOL IsImage(LPCTSTR szFile)
{
LPWSTR _e=PathFindExtension(szFile);
if (StrEqual(_e, _T(".bmp"))) return TRUE;
if (StrEqual(_e, _T(".ico"))) return TRUE;
if (StrEqual(_e, _T(".gif"))) return TRUE;
if (StrEqual(_e, _T(".jpg"))) return TRUE;
if (StrEqual(_e, _T(".jpe"))) return TRUE;
if (StrEqual(_e, _T(".jfif"))) return TRUE;
if (StrEqual(_e, _T(".jpeg"))) return TRUE;
if (StrEqual(_e, _T(".png"))) return TRUE;
if (StrEqual(_e, _T(".tif"))) return TRUE;
if (StrEqual(_e, _T(".tiff"))) return TRUE;
return FALSE;
}
inline CBXTYPE GetCBXType(LPCTSTR szExt)
{
if (StrEqual(szExt, _T(".cbz"))) return CBXTYPE_CBZ;
if (StrEqual(szExt, _T(".zip"))) return CBXTYPE_ZIP;
if (StrEqual(szExt, _T(".cbr"))) return CBXTYPE_CBR;
if (StrEqual(szExt, _T(".rar"))) return CBXTYPE_RAR;
//by popular demand
if (StrEqual(szExt, _T(".epub"))) return CBXTYPE_CBZ;
if (StrEqual(szExt, _T(".phz"))) return CBXTYPE_CBZ;
return CBXTYPE_NONE;
}
BOOL GetImageCountZIP(LPCTSTR cbzFile, int &imagecount, int &filecount)
{
imagecount=0;
filecount=0;
CUnzip _z;
if (!_z.Open(cbzFile)) return FALSE;
//empty zip is still valid
if (_z.GetItemCount()==0) return TRUE;
int _i;
for (_i=0; _i<_z.GetItemCount(); _i++)
{
if (!_z.GetItem(_i)) return FALSE;
//skip dirs
if (_z.ItemIsDirectory()) continue;
if (IsImage(_z.GetItemName())) imagecount+=1;
filecount+=1;
}
return TRUE;
}
BOOL GetImageCountRAR(LPCTSTR cbrFile, int &imagecount, int &filecount)
{
imagecount=0;
filecount=0;
CUnRar cr;
if (!cr.Open(cbrFile)) return FALSE;
//enum solid / skip volumes or encrypted file header archives
if (cr.IsArchiveVolume() || cr.IsArchiveEncryptedHeaders()) return FALSE;
while (cr.ReadItemInfo())
{
//skip dirs
if (!cr.IsItemDirectory())
{
if (IsImage(cr.GetItemName())) imagecount+=1;
filecount+=1;
}
if (!cr.SkipItem()) return FALSE;
}
return TRUE;
}
static inline BOOL Draw(
CImage ci,
_In_ HDC hDestDC,
_In_ int xDest,
_In_ int yDest,
_In_ int nDestWidth,
_In_ int nDestHeight,
_In_ int xSrc,
_In_ int ySrc,
_In_ int nSrcWidth,
_In_ int nSrcHeight,
_In_ Gdiplus::InterpolationMode interpolationMode) throw()
{
Gdiplus::Bitmap bm((HBITMAP)ci, NULL);
if (bm.GetLastStatus() != Gdiplus::Ok)
{
return FALSE;
}
Gdiplus::Graphics dcDst(hDestDC);
dcDst.SetInterpolationMode(interpolationMode);
Gdiplus::Rect destRec(xDest, yDest, nDestWidth, nDestHeight);
Gdiplus::Status status = dcDst.DrawImage(&bm, destRec, xSrc, ySrc, nSrcWidth, nSrcHeight, Gdiplus::Unit::UnitPixel);
return status == Gdiplus::Ok;
}
HBITMAP ThumbnailFromIStream(IStream* pIs, const LPSIZE pThumbSize)
{
ATLASSERT(pIs);
CImage ci;//uses gdi+ internally
if (S_OK!=ci.Load(pIs)) return NULL;
//check size
int tw=ci.GetWidth();
int th=ci.GetHeight();
float cx = (float)pThumbSize->cx;
float cy = (float)pThumbSize->cy;
float rx = cx/(float)tw;
float ry = cy/(float)th;
//if bigger size
if ((rx<1) || (ry<1))
{
CDC hdcNew=::CreateCompatibleDC(NULL);
if (hdcNew.IsNull()) return NULL;
hdcNew.SetStretchBltMode(HALFTONE);
hdcNew.SetBrushOrg(0,0, NULL);
//variables retain values until assignment
tw=(int)(min(rx,ry)*tw);//C424 warning workaround
th=(int)(min(rx,ry)*th);
CBitmap hbmpNew;
hbmpNew.CreateCompatibleBitmap(ci.GetDC(), tw,th);
ci.ReleaseDC();//don't forget!
if (hbmpNew.IsNull()) return NULL;
HBITMAP hbmpOld=hdcNew.SelectBitmap(hbmpNew);
hdcNew.FillSolidRect(0,0, tw,th, RGB(255,255,255));//white background
Draw(ci, hdcNew, 0, 0, tw, th, 0, 0, ci.GetWidth(), ci.GetHeight(), Gdiplus::InterpolationMode::InterpolationModeHighQualityBicubic);//too late for error checks
if(m_showIcon)
DrawIcon(hdcNew, 0, 0, zipIcon);
hdcNew.SelectBitmap(hbmpOld);
return hbmpNew.Detach();
}
return ci.Detach();
}
////unused
//HBITMAP ThumbnailFromBuffer(LPCBYTE pBuf, const ULONG dwBufSize, const LPSIZE pThumbSize)
//{
// HBITMAP hBmp = NULL;
// IStream* pIs = NULL;
// HGLOBAL hG = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwBufSize);
// if (hG)
// {
// if (S_OK==CreateStreamOnHGlobal(hG, TRUE, (LPSTREAM*)&pIs))
// {
// ULONG br;
// if (S_OK==pIs->Write(pBuf, dwBufSize, &br))//transfer buffer data
// {
// if (br==dwBufSize) hBmp=ThumbnailFromIStream(pIs, pThumbSize);
// }
// }
// }
// GlobalFree(hG);
// pIs->Release();
//return hBmp;
//}
__int64 FindThumbnailSortRAR(LPCTSTR pszFile)
{
CUnRar _r;
if (!_r.Open(pszFile)) return -1;
//skip solid (long processing time), volumes or encrypted file headers
if (_r.IsArchiveSolid() || _r.IsArchiveVolume() || _r.IsArchiveEncryptedHeaders()) return -1;
UINT64 _ps,_us;//my speed optimization?
CString prevname;
__int64 thumbindex=-1;
__int64 i=-1;//start at none (-1)
while (_r.ReadItemInfo())
{
i+=1;
_ps=_r.GetItemPackedSize64();
_us=_r.GetItemUnpackedSize64();
//skip directory/emtpy file/bigger than 32mb
if (_r.IsItemDirectory() || (_us>CBXMEM_MAXBUFFER_SIZE) || (_ps==0) || (_us==0))
{_r.SkipItem();continue;}
//take only index of first alphabetical name
if (IsImage(_r.GetItemName()))
{
//can't compare empty string
if (prevname.IsEmpty()) prevname=_r.GetItemName();
if (thumbindex<0) thumbindex=i;// assign thumbindex if already sorted
//sort by name
if (-1==StrCmpLogicalW(_r.GetItemName(), prevname))
{
thumbindex=i;
prevname=_r.GetItemName();
}
}
_r.SkipItem();//don't forget
}
return thumbindex;
}
public:
void LoadRegistrySettings()
{
DWORD _d;
CRegKey _rk;
if (ERROR_SUCCESS==_rk.Open(HKEY_CURRENT_USER, CBX_APP_KEY, KEY_READ))
{
if (ERROR_SUCCESS==_rk.QueryDWORDValue(_T("NoSort"), _d))
m_bSort=(_d==FALSE);
if (ERROR_SUCCESS == _rk.QueryDWORDValue(_T("ShowIcon"), _d))
m_showIcon = (_d == TRUE);
}
}
#ifdef _DEBUG
public:
void debug_SetSort(BOOL bS=TRUE) {m_bSort=bS;}
#endif
};//class _CCBXArchive
}//namespace __cbx
#endif//_CBXARCHIVE_442B998D_B9C0_4AB0_BB2A_BC9C0AA10053_