windows-nt/Source/XPSP1/NT/shell/ext/cabview/cabitms.cpp
2020-09-26 16:20:57 +08:00

856 lines
17 KiB
C++

//*******************************************************************************************
//
// Filename : CabItms.cpp
//
// Implementation file for CMemFile, CCabEnum and CCabExtract
//
// Copyright (c) 1994 - 1996 Microsoft Corporation. All rights reserved
//
//*******************************************************************************************
#include "pch.h"
#include "ccstock.h"
#include "thisdll.h"
#include "resource.h"
#include "fdi.h"
#include "cabitms.h"
class CMemFile
{
public:
CMemFile(HGLOBAL *phMem, DWORD dwSize);
~CMemFile() {}
BOOL Create(LPCTSTR pszFile);
BOOL Open(LPCTSTR pszFile, int oflag);
LONG Seek(LONG dist, int seektype);
UINT Read(LPVOID pv, UINT cb);
UINT Write(LPVOID pv, UINT cb);
HANDLE Close();
private:
HANDLE m_hf;
HGLOBAL *m_phMem;
DWORD m_dwSize;
LONG m_lLoc;
} ;
CMemFile::CMemFile(HGLOBAL *phMem, DWORD dwSize) : m_hf(INVALID_HANDLE_VALUE), m_lLoc(0)
{
m_phMem = phMem;
m_dwSize = dwSize;
if (phMem)
{
*phMem = NULL;
}
}
BOOL CMemFile::Create(LPCTSTR pszFile)
{
if (m_phMem)
{
if (*m_phMem)
{
return(FALSE);
}
*m_phMem = GlobalAlloc(LMEM_FIXED, m_dwSize);
return(*m_phMem != NULL);
}
else
{
if (m_hf != INVALID_HANDLE_VALUE)
{
return(FALSE);
}
m_hf = CreateFile(pszFile,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
return (m_hf != INVALID_HANDLE_VALUE);
}
}
BOOL CMemFile::Open(LPCTSTR pszFile, int oflag)
{
if (m_phMem)
{
return(FALSE);
}
else
{
if (m_hf != INVALID_HANDLE_VALUE)
{
return(FALSE);
}
m_hf = CreateFile(pszFile,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
oflag,
NULL);
return (m_hf != INVALID_HANDLE_VALUE);
}
}
LONG CMemFile::Seek(LONG dist, int seektype)
{
if (m_phMem)
{
if (!*m_phMem)
{
return -1;
}
switch (seektype)
{
case FILE_BEGIN:
break;
case FILE_CURRENT:
dist += m_lLoc;
break;
case FILE_END:
dist = m_dwSize - dist;
break;
default:
return -1;
}
if (dist<0 || dist>(LONG)m_dwSize)
{
return -1;
}
m_lLoc = dist;
return(dist);
}
else
{
return(_llseek((HFILE)HandleToUlong(m_hf), dist, seektype));
}
}
UINT CMemFile::Read(LPVOID pv, UINT cb)
{
if (m_phMem)
{
if (!*m_phMem)
{
return -1;
}
if (cb > m_dwSize - m_lLoc)
{
cb = m_dwSize - m_lLoc;
}
hmemcpy(pv, (LPSTR)(*m_phMem)+m_lLoc, cb);
m_lLoc += cb;
return(cb);
}
else
{
return(_lread((HFILE)HandleToUlong(m_hf), pv, cb));
}
}
UINT CMemFile::Write(LPVOID pv, UINT cb)
{
if (m_phMem)
{
if (!*m_phMem)
{
return -1;
}
if (cb > m_dwSize - m_lLoc)
{
cb = m_dwSize - m_lLoc;
}
hmemcpy((LPSTR)(*m_phMem)+m_lLoc, pv, cb);
m_lLoc += cb;
return(cb);
}
else
{
return(_lwrite((HFILE)HandleToUlong(m_hf), (LPCSTR)pv, cb));
}
}
HANDLE CMemFile::Close()
{
HANDLE hRet;
if (m_phMem)
{
hRet = *m_phMem ? 0 : INVALID_HANDLE_VALUE;
}
else
{
hRet = LongToHandle(_lclose((HFILE)HandleToUlong(m_hf)));
}
delete this;
return(hRet);
}
//*****************************************************************************
//
// CCabEnum
//
// Purpose:
//
// Class encapsulating all the FDI operations
//
// Comments:
//
//*****************************************************************************
class CCabEnum
{
public:
CCabEnum() : m_hfdi(0) {}
~CCabEnum() {}
protected:
static void HUGE * FAR DIAMONDAPI CabAlloc(ULONG cb);
static void FAR DIAMONDAPI CabFree(void HUGE *pv);
static INT_PTR FAR DIAMONDAPI CabOpen(char FAR *pszFile, int oflag, int pmode);
static UINT FAR DIAMONDAPI CabRead(INT_PTR hf, void FAR *pv, UINT cb);
static UINT FAR DIAMONDAPI CabWrite(INT_PTR hf, void FAR *pv, UINT cb);
static int FAR DIAMONDAPI CabClose(INT_PTR hf);
static long FAR DIAMONDAPI CabSeek(INT_PTR hf, long dist, int seektype);
BOOL StartEnum();
BOOL SimpleEnum(LPCTSTR szCabFile, PFNFDINOTIFY pfnCallBack, LPVOID pv);
void EndEnum();
HFDI m_hfdi;
ERF m_erf;
private:
static CMemFile * s_hSpill;
} ;
CMemFile * CCabEnum::s_hSpill = NULL;
void HUGE * FAR DIAMONDAPI CCabEnum::CabAlloc(ULONG cb)
{
return(GlobalAllocPtr(GHND, cb));
}
void FAR DIAMONDAPI CCabEnum::CabFree(void HUGE *pv)
{
GlobalFreePtr(pv);
}
INT_PTR FAR DIAMONDAPI CCabEnum::CabOpen(char FAR *pszFile, int oflag, int pmode)
{
if(!pszFile)
{
return -1;
}
// See if we are opening the spill file.
if( *pszFile=='*' )
{
TCHAR szSpillFile[MAX_PATH];
TCHAR szTempPath[MAX_PATH];
if(s_hSpill != NULL)
return -1;
GetTempPath(ARRAYSIZE(szTempPath), szTempPath);
GetTempFileName(szTempPath, TEXT("fdi"), 0, szSpillFile);
s_hSpill = new CMemFile(NULL, 0);
if (!s_hSpill)
{
return(-1);
}
if (!s_hSpill->Create(szSpillFile))
{
delete s_hSpill;
s_hSpill = NULL;
return(-1);
}
// Set its extent.
if( s_hSpill->Seek( ((FDISPILLFILE FAR *)pszFile)->cbFile-1, 0) == HFILE_ERROR)
{
s_hSpill->Close();
s_hSpill = NULL;
return -1;
}
s_hSpill->Write(szSpillFile, 1);
return (INT_PTR)s_hSpill;
}
CMemFile *hFile = new CMemFile(NULL, 0);
if (!hFile)
{
return(-1);
}
TCHAR szFile[MAX_PATH];
SHAnsiToTChar(pszFile, szFile, ARRAYSIZE(szFile));
while (!hFile->Open(szFile, oflag))
{
#if 1 // TODO: No UI for inserting a disk at this point
delete hFile;
return(-1);
#else
// Failed to open the source.
if (!LoadString (g_hInst, IDS_DISKPROMPT, szText, MAX_STRTABLE_LEN))
return -1;
char szText[MAX_PATH];
wsprintf (g_pErrorBuffer, (LPSTR)szText, (LPSTR)g_pCabName);
// Use hwndIniting to have a parent window
if ( MyMessageBox(g_hwndIniting, g_pErrorBuffer,
MAKEINTRESOURCE(IDS_DISKPROMPT_TIT),
MB_OKCANCEL|MB_ICONSTOP, 0) == IDOK )
continue;
else
return -1;
#endif
}
return((INT_PTR)hFile);
}
UINT FAR DIAMONDAPI CCabEnum::CabRead(INT_PTR hf, void FAR *pv, UINT cb)
{
CMemFile *hFile = (CMemFile *)hf;
return(hFile->Read(pv,cb));
}
UINT FAR DIAMONDAPI CCabEnum::CabWrite(INT_PTR hf, void FAR *pv, UINT cb)
{
CMemFile *hFile = (CMemFile *)hf;
return(hFile->Write(pv,cb));
}
int FAR DIAMONDAPI CCabEnum::CabClose(INT_PTR hf)
{
CMemFile *hFile = (CMemFile *)hf;
// Special case for the deletion of the spill file.
if(hFile == s_hSpill)
{
s_hSpill = NULL;
}
return (int)HandleToUlong(hFile->Close());
}
long FAR DIAMONDAPI CCabEnum::CabSeek(INT_PTR hf, long dist, int seektype)
{
CMemFile *hFile = (CMemFile *)hf;
return(hFile->Seek(dist, seektype));
}
BOOL CCabEnum::StartEnum()
{
if (m_hfdi)
{
// We seem to already be enumerating
return(FALSE);
}
m_hfdi = FDICreate(
CabAlloc,
CabFree,
CabOpen,
CabRead,
CabWrite,
CabClose,
CabSeek,
cpu80386,
&m_erf);
return(m_hfdi != NULL);
}
BOOL CCabEnum::SimpleEnum(LPCTSTR szCabFile, PFNFDINOTIFY pfnCallBack, LPVOID pv)
{
char szCabPath[MAX_PATH];
char szCabName[MAX_PATH];
// Path should be fully qualified
char szFile[MAX_PATH];
SHTCharToAnsi(szCabFile, szFile, ARRAYSIZE(szFile));
lstrcpynA(szCabPath, szFile, sizeof(szCabPath));
LPSTR pszName = PathFindFileNameA(szCabPath);
if (!pszName)
{
return(FALSE);
}
lstrcpyA(szCabName, pszName);
*pszName = '\0';
if (!StartEnum())
{
return(FALSE);
}
BOOL bRet = FDICopy(
m_hfdi,
szCabName,
szCabPath, // path to cabinet files
0, // flags
pfnCallBack,
NULL,
pv);
EndEnum();
return(bRet);
}
void CCabEnum::EndEnum()
{
if (!m_hfdi)
{
return;
}
FDIDestroy(m_hfdi);
m_hfdi = NULL;
}
class CCabItemsCB : private CCabEnum
{
public:
CCabItemsCB(CCabItems::PFNCABITEM pfnCallBack, LPARAM lParam)
{
m_pfnCallBack = pfnCallBack;
m_lParam = lParam;
}
~CCabItemsCB() {}
BOOL DoEnum(LPCTSTR szCabFile)
{
return(SimpleEnum(szCabFile, CabItemsNotify, this));
}
private:
static INT_PTR FAR DIAMONDAPI CabItemsNotify(FDINOTIFICATIONTYPE fdint,
PFDINOTIFICATION pfdin);
CCabItems::PFNCABITEM m_pfnCallBack;
LPARAM m_lParam;
} ;
INT_PTR FAR DIAMONDAPI CCabItemsCB::CabItemsNotify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
{
CCabItemsCB *pThis = (CCabItemsCB *)pfdin->pv;
// uiYield( g_hwndSetup );
TCHAR szFile[MAX_PATH];
if (NULL != pfdin->psz1)
{
// NOTE: CP_UTF8 is not supported on Win9x!
SHAnsiToTCharCP((_A_NAME_IS_UTF & pfdin->attribs) ? CP_UTF8 : CP_ACP,
pfdin->psz1,
szFile,
ARRAYSIZE(szFile));
}
switch (fdint)
{
case fdintCOPY_FILE:
pThis->m_pfnCallBack(pfdin->psz1 ? szFile : NULL,
pfdin->cb,
pfdin->date,
pfdin->time,
pfdin->attribs,
pThis->m_lParam);
break;
default:
break;
} // end switch
return 0;
}
//*****************************************************************************
//
// CCabItems::EnumItems
//
// Purpose:
//
// Enumerate the items in the cab file
//
//
// Comments:
//
// lParam contains pointer to CCabFolder
//
//*****************************************************************************
BOOL CCabItems::EnumItems(PFNCABITEM pfnCallBack, LPARAM lParam)
{
CCabItemsCB cItems(pfnCallBack, lParam);
return(cItems.DoEnum(m_szCabFile));
}
//*****************************************************************************
//
// CCabExtractCB
//
// Purpose:
//
// handles the call back while extracting Cab files
//
//
//*****************************************************************************
class CCabExtractCB : private CCabEnum
{
public:
CCabExtractCB(LPCTSTR szDir, HWND hwndOwner, CCabExtract::PFNCABEXTRACT pfnCallBack,
LPARAM lParam)
{
m_szDir = szDir;
m_hwndOwner = hwndOwner;
m_pfnCallBack = pfnCallBack;
m_lParam = lParam;
m_bTryNextCab = FALSE;
}
~CCabExtractCB() {}
BOOL DoEnum(LPCTSTR szCabFile)
{
return(SimpleEnum(szCabFile, CabExtractNotify, this));
}
private:
static INT_PTR FAR DIAMONDAPI CabExtractNotify(FDINOTIFICATIONTYPE fdint,
PFDINOTIFICATION pfdin);
static int CALLBACK CCabExtractCB::BrowseNotify(HWND hwnd, UINT uMsg, LPARAM lParam,
LPARAM lpData);
LPCTSTR m_szDir;
HWND m_hwndOwner;
CCabExtract::PFNCABEXTRACT m_pfnCallBack;
LPARAM m_lParam;
BOOL m_bTryNextCab;
PFDINOTIFICATION m_pfdin;
} ;
int CALLBACK CCabExtractCB::BrowseNotify(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
CCabExtractCB *pThis = (CCabExtractCB *)lpData;
switch (uMsg)
{
case BFFM_INITIALIZED:
{
// Set initial folder
LPSTR pszEnd = PathAddBackslashA(pThis->m_pfdin->psz3);
if (pszEnd - pThis->m_pfdin->psz3 > 3)
{
// No problems if not drive root
*(pszEnd - 1) = '\0';
}
SendMessage(hwnd, BFFM_SETSELECTION, 1, (LPARAM)pThis->m_pfdin->psz3);
break;
}
default:
return(0);
}
return(1);
}
INT_PTR FAR DIAMONDAPI CCabExtractCB::CabExtractNotify(FDINOTIFICATIONTYPE fdint,
PFDINOTIFICATION pfdin)
{
CCabExtractCB *pThis = (CCabExtractCB *)pfdin->pv;
// uiYield( g_hwndSetup );
switch (fdint)
{
case fdintCABINET_INFO:
pThis->m_bTryNextCab = TRUE;
break;
case fdintNEXT_CABINET:
{
if (pThis->m_bTryNextCab)
{
// Automatically open next cab if already in default dir
pThis->m_bTryNextCab = FALSE;
return(1);
}
pThis->m_pfdin = pfdin;
TCHAR szFormat[80];
TCHAR szTitle[80 + 2*MAX_PATH];
if (pfdin->psz2[0] != '\0')
{
LoadString(g_ThisDll.GetInstance(), IDS_NEXTDISKBROWSE, szFormat, ARRAYSIZE(szFormat));
}
else
{
LoadString(g_ThisDll.GetInstance(), IDS_NEXTCABBROWSE, szFormat, ARRAYSIZE(szFormat));
}
wsprintf(szTitle, szFormat, (LPSTR) (pfdin->psz1), (LPSTR) (pfdin->psz2));
BROWSEINFO bi;
bi.hwndOwner = pThis->m_hwndOwner;
bi.pidlRoot = NULL;
bi.pszDisplayName = NULL;
bi.lpszTitle = szTitle;
bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
bi.lpfn = BrowseNotify;
bi.lParam = (LPARAM)pThis;
LPITEMIDLIST pidl = SHBrowseForFolder(&bi);
if (bi.pidlRoot)
{
ILFree((LPITEMIDLIST)bi.pidlRoot);
}
if (!pidl)
{
return(-1);
}
BOOL bSuccess = SHGetPathFromIDListA(pidl, pfdin->psz3);
ILFree(pidl);
if (bSuccess)
{
PathAddBackslashA(pfdin->psz3);
return(1);
}
return(-1);
}
case fdintCOPY_FILE:
{
TCHAR szFile[MAX_PATH];
if (NULL != pfdin->psz1)
{
// NOTE: CP_UTF8 is not supported on Win9x!
SHAnsiToTCharCP((_A_NAME_IS_UTF & pfdin->attribs) ? CP_UTF8 : CP_ACP,
pfdin->psz1,
szFile,
ARRAYSIZE(szFile));
}
else
{
szFile[0] = TEXT('\0');
}
HGLOBAL *phMem = pThis->m_pfnCallBack(pfdin->psz1 ? szFile : NULL,
pfdin->cb,
pfdin->date,
pfdin->time,
pfdin->attribs,
pThis->m_lParam);
if (!phMem)
{
break;
}
TCHAR szTemp[MAX_PATH];
CMemFile *hFile;
if (pThis->m_szDir == DIR_MEM)
{
*szTemp = '\0';
hFile = new CMemFile(phMem, pfdin->cb);
}
else
{
PathCombine(szTemp, pThis->m_szDir, PathFindFileName(szFile));
hFile = new CMemFile(NULL, 0);
}
if (!hFile)
{
break;
}
if (hFile->Create(szTemp))
{
return((INT_PTR)hFile);
}
delete hFile;
break;
}
case fdintCLOSE_FILE_INFO:
{
CMemFile *hFile = (CMemFile *)pfdin->hf;
return(hFile->Close() == 0);
}
default:
break;
} // end switch
return 0;
}
HRESULT CCabExtract::_DoDragDrop(HWND hwnd, IDataObject* pdo, LPCITEMIDLIST pidlFolder)
{
IShellFolder *psf;
HRESULT hres = SHBindToObject(NULL, IID_IShellFolder, pidlFolder, (LPVOID*)&psf);
// This should always succeed because the caller (SHBrowseForFolder) should
// have weeded out the non-folders.
if (SUCCEEDED(hres))
{
IDropTarget *pdrop;
hres = psf->CreateViewObject(NULL, IID_IDropTarget, (void**)&pdrop);
if (SUCCEEDED(hres)) // Will fail for some targets. (Like Nethood->Entire Network)
{
// May fail if items aren't compatible for drag/drop. (Nethood is one example)
// MK_CONTROL | MKLBUTTON is used to suggest a "copy":
hres = SHSimulateDrop(pdrop, pdo, MK_CONTROL | MK_LBUTTON, NULL, NULL);
pdrop->Release();
}
psf->Release();
}
return hres;
}
int BrowseCallback(HWND hwnd, UINT msg, LPARAM lParam, LPARAM lpData)
{
switch (msg)
{
case BFFM_INITIALIZED:
{
// Set the caption. ('Select a destination')
TCHAR szTitle[100];
LoadString(g_ThisDll.GetInstance(), IDS_EXTRACTBROWSE_CAPTION, szTitle, ARRAYSIZE(szTitle));
SetWindowText(hwnd, szTitle);
// Set the text of the Ok Button.
TCHAR szOK[100];
LoadString(g_ThisDll.GetInstance(), IDS_EXTRACTBROWSE_EXTRACT, szOK, ARRAYSIZE(szOK));
SendMessage(hwnd, BFFM_SETOKTEXT, 0, (LPARAM)szOK);
}
break;
case BFFM_SELCHANGED:
{
LPITEMIDLIST pidl = (LPITEMIDLIST)lParam;
BOOL bEnableOk = FALSE;
IShellFolder *psf;
LPCITEMIDLIST pidlChild;
if (SUCCEEDED(SHBindToIDListParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlChild)))
{
DWORD dwAttributes = SFGAO_FILESYSTEM;
psf->GetAttributesOf(1, &pidlChild, &dwAttributes);
psf->Release();
bEnableOk = dwAttributes & SFGAO_FILESYSTEM; // is FS?
}
SendMessage(hwnd, BFFM_ENABLEOK, (WPARAM) 0, (LPARAM) bEnableOk);
}
break;
}
return 0;
}
BOOL CCabExtract::ExtractToFolder(HWND hwndOwner, IDataObject* pdo, PFNCABEXTRACT pfnCallBack, LPARAM lParam)
{
// ASSERT(pdo);
TCHAR szTitle[120];
LoadString(g_ThisDll.GetInstance(), IDS_EXTRACTBROWSE, szTitle, ARRAYSIZE(szTitle));
BROWSEINFO bi;
bi.hwndOwner = hwndOwner;
bi.pidlRoot = NULL;
bi.pszDisplayName = NULL;
bi.lpszTitle = szTitle;
bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE | BIF_UAHINT;
bi.lpfn = BrowseCallback;
LPITEMIDLIST pidl = SHBrowseForFolder(&bi);
if (!pidl)
{
return(FALSE);
}
BOOL bSuccess = SUCCEEDED(_DoDragDrop(hwndOwner, pdo, pidl));
ILFree(pidl);
return bSuccess;
}
BOOL CCabExtract::ExtractItems(HWND hwndOwner, LPCTSTR szDir, PFNCABEXTRACT pfnCallBack, LPARAM lParam)
{
// ASSERT(szDir);
CCabExtractCB cExtract(szDir, hwndOwner, pfnCallBack, lParam);
// Display Wait cursor until done copying
CWaitCursor cWait;
return(cExtract.DoEnum(m_szCabFile));
}