// MainFrm.cpp : implmentation of the CMainFrame class
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "resource.h"
#include "aboutdlg.h"
#include "WTLCabViewView.h"
#include "MainFrm.h"
#include "CabFuncs.h"
#include "MyDialogs.h"
#include "DragDropSource.h"
struct __declspec(uuid("DE5BF786-477A-11d2-839D-00C04FD918D0")) IDragSourceHelper;
/////////////////////////////////////////////////////////////////////////////
// Construction
CMainFrame::CMainFrame()
{
}
/////////////////////////////////////////////////////////////////////////////
// Message handlers
BOOL CMainFrame::PreTranslateMessage(MSG* pMsg)
{
if ( CFrameWindowImpl<CMainFrame>::PreTranslateMessage(pMsg) )
return TRUE;
return m_view.PreTranslateMessage ( pMsg );
}
BOOL CMainFrame::OnIdle()
{
UIUpdateToolBar();
return FALSE;
}
LRESULT CMainFrame::OnCreate ( LPCREATESTRUCT lpcs )
{
HWND hWndToolBar = CreateSimpleToolBarCtrl(m_hWnd, IDR_MAINFRAME, FALSE, ATL_SIMPLE_TOOLBAR_PANE_STYLE);
CreateSimpleReBar ( ATL_SIMPLE_REBAR_NOBORDER_STYLE );
AddSimpleReBarBand ( hWndToolBar );
CreateSimpleStatusBar();
m_hWndClient = m_view.Create ( m_hWnd, rcDefault );
m_view.Init();
// Init MRU list
CMenuHandle mainMenu = GetMenu();
CMenuHandle fileMenu = mainMenu.GetSubMenu(0);
m_mru.SetMaxEntries(9);
m_mru.SetMenuHandle ( fileMenu );
m_mru.ReadFromRegistry ( APP_SETTINGS_KEY );
// Init UI stuff
UIAddToolBar ( hWndToolBar );
UISetCheck ( ID_VIEW_TOOLBAR, 1 );
UISetCheck ( ID_VIEW_STATUS_BAR, 1 );
// Start in tile mode on XP+. On pre-XP, start in report mode and disable
// the tile view command.
if ( g_bXPOrLater )
{
m_view.SetViewMode ( LV_VIEW_TILE );
CheckViewControls ( IDC_VIEW_TILES );
}
else
{
UIEnable ( IDC_VIEW_TILES, false );
CMenuHandle(GetMenu()).EnableMenuItem ( IDC_VIEW_TILES, MF_BYCOMMAND|MF_GRAYED );
m_view.SetViewMode ( LV_VIEW_DETAILS );
CheckViewControls ( IDC_VIEW_DETAILS );
}
// Register object for message filtering and idle updates
CMessageLoop* pLoop = _Module.GetMessageLoop();
ATLASSERT(pLoop != NULL);
pLoop->AddMessageFilter(this);
pLoop->AddIdleHandler(this);
return 0;
}
void CMainFrame::OnDestroy()
{
// Unregister object for message filtering and idle updates
CMessageLoop* pLoop = _Module.GetMessageLoop();
ATLASSERT(pLoop != NULL);
pLoop->RemoveMessageFilter(this);
pLoop->RemoveIdleHandler(this);
// Save the MRU
m_mru.WriteToRegistry ( APP_SETTINGS_KEY );
// Clean up temp files
std::vector<CString>::const_iterator it;
for ( it = g_vecsTempFiles.begin(); it != g_vecsTempFiles.end(); it++ )
DeleteFile ( *it );
SetMsgHandled(false);
}
void CMainFrame::OnEndSession ( BOOL bSessionEnding, UINT uReason )
{
if ( bSessionEnding )
{
// Save the MRU
m_mru.WriteToRegistry ( APP_SETTINGS_KEY );
// Clean up temp files
std::vector<CString>::const_iterator it;
for ( it = g_vecsTempFiles.begin(); it != g_vecsTempFiles.end(); it++ )
DeleteFile ( *it );
}
}
/////////////////////////////////////////////////////////////////////////////
// Command handlers
void CMainFrame::OnFileOpen ( UINT uCode, int nID, HWND hwndCtrl )
{
CMyFileDialog dlg ( true, _T("cab"), 0U, OFN_HIDEREADONLY|OFN_FILEMUSTEXIST,
IDS_OPENFILE_FILTER, *this );
if ( IDOK == dlg.DoModal ( *this ) )
ViewCab ( dlg.m_szFileName );
// Some interesting CABs to look at, if you have the Win 98 CABs lying around:
// win98_21.cab - 6 files, all continued to next cab
// win98_22.cab - has files from prev cab and continued in next cab
// driver14.cab - only has a file from the prev cab
}
void CMainFrame::OnMRUMenuItem ( UINT uCode, int nID, HWND hwndCtrl )
{
CString sFile;
// Read the selected filename from the MRU list, and open that file.
if ( m_mru.GetFromList ( nID, sFile ) )
ViewCab ( sFile, nID );
}
void CMainFrame::OnFileExit ( UINT uCode, int nID, HWND hwndCtrl )
{
PostMessage ( WM_CLOSE );
}
void CMainFrame::OnViewToolBar ( UINT uCode, int nID, HWND hwndCtrl )
{
static BOOL bVisible = TRUE; // initially visible
CReBarCtrl rebar = m_hWndToolBar;
int nBandIndex = rebar.IdToIndex ( ATL_IDW_BAND_FIRST ); // toolbar is first band
bVisible = !bVisible;
rebar.ShowBand ( nBandIndex, bVisible );
UISetCheck ( ID_VIEW_TOOLBAR, bVisible );
UpdateLayout();
}
void CMainFrame::OnViewStatusBar ( UINT uCode, int nID, HWND hwndCtrl )
{
BOOL bVisible = !::IsWindowVisible ( m_hWndStatusBar );
::ShowWindow ( m_hWndStatusBar, bVisible ? SW_SHOWNOACTIVATE : SW_HIDE );
UISetCheck ( ID_VIEW_STATUS_BAR, bVisible );
UpdateLayout();
}
void CMainFrame::OnAppAbout ( UINT uCode, int nID, HWND hwndCtrl )
{
CAboutDlg dlg;
dlg.DoModal ( *this );
}
void CMainFrame::OnViewIcons ( UINT uCode, int nID, HWND hwndCtrl )
{
m_view.SetViewMode ( LV_VIEW_ICON );
CheckViewControls ( nID );
}
void CMainFrame::OnViewSmallIcons ( UINT uCode, int nID, HWND hwndCtrl )
{
m_view.SetViewMode ( LV_VIEW_SMALLICON );
CheckViewControls ( nID );
}
void CMainFrame::OnViewList ( UINT uCode, int nID, HWND hwndCtrl )
{
m_view.SetViewMode ( LV_VIEW_LIST );
CheckViewControls ( nID );
}
void CMainFrame::OnViewDetails ( UINT uCode, int nID, HWND hwndCtrl )
{
m_view.SetViewMode ( LV_VIEW_DETAILS );
CheckViewControls ( nID );
}
void CMainFrame::OnViewTiles ( UINT uCode, int nID, HWND hwndCtrl )
{
ATLASSERT(g_bXPOrLater);
m_view.SetViewMode ( LV_VIEW_TILE );
CheckViewControls ( nID );
}
/////////////////////////////////////////////////////////////////////////////
// Notify handlers
LRESULT CMainFrame::OnListBeginDrag ( NMHDR* phdr )
{
NMLISTVIEW* pnmlv = (NMLISTVIEW*) phdr;
std::vector<CDraggedFileInfo> vec;
CComObjectStack2<CDragDropSource> dropsrc;
DWORD dwEffect = 0;
HRESULT hr;
CComPtr<IDragSourceHelper> pdsh;
// Get a list of the files being dragged (minus files that we can't extract
// from the current CAB).
if ( !m_view.GetDraggedFileInfo ( vec ) )
{
ATLTRACE("Error: Couldn't get list of files dragged (or only partial files were dragged)\n");
return 0; // do nothing
}
// Init the drag/drop data object.
if ( !dropsrc.Init ( m_sCurrentCabFilePath, vec ) )
{
ATLTRACE("Error: Couldn't init drop source object\n");
return 0; // do nothing
}
// On 2K+, init a drag source helper object that will do the fancy drag
// image when the user drags into Explorer (or another target that supports
// the drag/drop helper).
hr = pdsh.CoCreateInstance ( CLSID_DragDropHelper );
if ( SUCCEEDED(hr) )
{
CComQIPtr<IDataObject> pdo;
if ( pdo = dropsrc.GetUnknown() )
pdsh->InitializeFromWindow ( m_view, &pnmlv->ptAction, pdo );
}
// Start the drag/drop!
hr = dropsrc.DoDragDrop ( DROPEFFECT_COPY, &dwEffect );
if ( FAILED(hr) )
ATLTRACE("Error: DoDragDrop() failed, error: 0x%08X\n", hr);
else
{
// If we found any files continued into other CABs, update the UI.
const std::vector<CDraggedFileInfo>& vecResults = dropsrc.GetDragResults();
std::vector<CDraggedFileInfo>::const_iterator it;
for ( it = vecResults.begin(); it != vecResults.end(); it++ )
{
if ( it->bPartialFile )
m_view.UpdateContinuedFile ( *it );
}
}
return 0;
}
/////////////////////////////////////////////////////////////////////////////
// Other methods
void CMainFrame::ViewCab ( LPCTSTR szCabFilename, int nMRUID )
{
if ( EnumCabContents ( szCabFilename ) )
{
m_sCurrentCabFilePath = szCabFilename;
// If this CAB file was already in the MRU list, move it to the
// top of the list. Otherwise, add it to the list.
if ( 0 == nMRUID )
m_mru.AddToList ( szCabFilename );
else
m_mru.MoveToTop ( nMRUID );
}
else
{
// We couldn't read the contents of this CAB file, so remove it from
// the MRU list if it was in there.
if ( 0 != nMRUID )
m_mru.RemoveFromList ( nMRUID );
}
}
bool CMainFrame::EnumCabContents ( LPCTSTR szCabFilename )
{
CWaitCursor w;
TCHAR szCabDir[MAX_PATH], szCabTitle[MAX_PATH];
ERF erf = {0};
FDICABINETINFO info = {0};
int hf = 0;
HFDI hfdi = NULL;
// Check that the passed-in file exists.
if ( !PathFileExists ( szCabFilename ) )
{
AtlMessageBox ( *this, IDS_FILE_NOT_FOUND, IDS_MSGBOX_TITLE, MB_ICONERROR );
return false;
}
// The CAB API takes the CAB file path as separate dir/name parts,
// so split up the path.
lstrcpyn ( szCabDir, szCabFilename, countof(szCabDir) );
PathRemoveFileSpec ( szCabDir );
PathAddBackslash ( szCabDir );
lstrcpyn ( szCabTitle, PathFindFileName ( szCabFilename ), countof(szCabTitle) );
// Init the CAB decompression engine.
hfdi = FDICreate ( cab_Alloc, cab_Free, cab_Open, cab_Read, cab_Write,
cab_Close, cab_Seek, 0, &erf );
if ( NULL == hfdi )
{
CString sMsg;
sMsg.Format ( IDS_FDICREATE_FAILED, erf.erfOper );
AtlMessageBox ( *this, (LPCTSTR) sMsg, IDS_MSGBOX_TITLE, MB_ICONERROR );
return false;
}
// Open the CAB file for reading.
hf = cab_Open ( T2A(LPTSTR(szCabFilename)), _O_BINARY|_O_RDONLY, 0 );
if ( -1 == hf )
{
AtlMessageBox ( *this, IDS_OPEN_CAB_ERROR, IDS_MSGBOX_TITLE, MB_ICONERROR );
FDIDestroy ( hfdi );
return false;
}
// Check that it's a valid CAB file.
if ( !FDIIsCabinet ( hfdi, hf, &info ) )
{
cab_Close ( hf );
AtlMessageBox ( *this, IDS_INVALID_CAB_ERROR, IDS_MSGBOX_TITLE, MB_ICONERROR );
FDIDestroy ( hfdi );
return false;
}
cab_Close ( hf );
m_view.Clear();
m_view.SetRedraw ( false );
// Enum the contents of the CAB.
if ( !FDICopy ( hfdi, T2A(szCabTitle), T2A(szCabDir), 0, fdi_Notify, NULL, this ) )
{
CString sMsg;
m_view.SetRedraw();
sMsg.Format ( IDS_FDICOPY_FAILED, erf.erfOper );
AtlMessageBox ( *this, (LPCTSTR) sMsg, IDS_MSGBOX_TITLE, MB_ICONERROR );
FDIDestroy ( hfdi );
return false;
}
FDIDestroy ( hfdi );
// We're done, so fix up the column widths and update the frame's title
// text to show the CAB filename.
m_view.SetColumnWidth ( 0, LVSCW_AUTOSIZE_USEHEADER );
m_view.SetColumnWidth ( 1, LVSCW_AUTOSIZE_USEHEADER );
m_view.SetColumnWidth ( 2, LVSCW_AUTOSIZE_USEHEADER );
m_view.SetColumnWidth ( 3, LVSCW_AUTOSIZE_USEHEADER );
m_view.SetColumnWidth ( 4, LVSCW_AUTOSIZE_USEHEADER );
m_view.SetColumnWidth ( 5, 150 );
m_view.SetRedraw();
m_view.RedrawWindow();
// Show the CAB name in the frame window title.
CString sTitle;
sTitle.Format ( _T("%s - %s"), (LPCTSTR) _S(IDR_MAINFRAME), szCabTitle );
SetWindowText ( sTitle );
return true;
}
void CMainFrame::CheckViewControls ( int nIDToCheck )
{
ATLASSERT(nIDToCheck >= IDC_VIEW_ICONS && nIDToCheck <= IDC_VIEW_TILES);
// Uncheck all 5 view toolbar buttons, then check the one whose ID was
// passed in.
UISetCheck ( IDC_VIEW_ICONS, false );
UISetCheck ( IDC_VIEW_SMALL_ICONS, false );
UISetCheck ( IDC_VIEW_LIST, false );
UISetCheck ( IDC_VIEW_DETAILS, false );
UISetCheck ( IDC_VIEW_TILES, false );
UISetCheck ( nIDToCheck, true );
// CUpdateUI doesn't support radio checks in menus, so we handle
// the menu separately.
CheckMenuRadioItem ( GetMenu(), IDC_VIEW_ICONS, IDC_VIEW_TILES,
nIDToCheck, MF_BYCOMMAND );
}
/////////////////////////////////////////////////////////////////////////////
// FDICopy() callbacks
int DIAMONDAPI CMainFrame::fdi_Notify (
FDINOTIFICATIONTYPE message, PFDINOTIFICATION pInfo )
{
CMainFrame* pThis = (CMainFrame*) pInfo->pv;
switch ( message )
{
case fdintCABINET_INFO:
return pThis->Notify_CabInfo ( A2CT(pInfo->psz1), A2CT(pInfo->psz2),
A2CT(pInfo->psz3), pInfo->setID,
pInfo->iCabinet );
break;
case fdintPARTIAL_FILE:
return pThis->Notify_PartialFile ( A2CT(pInfo->psz1), A2CT(pInfo->psz2),
A2CT(pInfo->psz3) );
break;
case fdintCOPY_FILE:
return pThis->Notify_CopyFile ( A2CT(pInfo->psz1), pInfo->cb,
pInfo->date, pInfo->time,
pInfo->attribs, pInfo->iFolder );
break;
case fdintENUMERATE:
return pThis->Notify_Enumerate ( pInfo->cb, pInfo->iFolder, pInfo->setID );
break;
}
return 0;
}
int CMainFrame::Notify_CabInfo (
LPCTSTR szCabName, LPCTSTR szDiskName, LPCTSTR szCabDir,
USHORT uCabID, USHORT uCabNumber )
{
ATLTRACE("fdi_Notify: fdintCABINET_INFO\n");
ATLTRACE(" >> cab name: %s\n", szCabName);
ATLTRACE(" >> disk name: %s\n", szDiskName);
ATLTRACE(" >> cab dir: %s\n", szCabDir);
ATLTRACE(" >> cab ID: %hu\n", uCabID);
ATLTRACE(" >> cab #: %hu\n", uCabNumber);
return 0; // proceed with FDICopy
}
int CMainFrame::Notify_PartialFile (
LPCTSTR szFilename, LPCTSTR szStartingCabName, LPCTSTR szStartingDiskName )
{
ATLTRACE("fdi_Notify: fdintPARTIAL_FILE\n");
ATLTRACE(" >> file name: %s\n", szFilename);
ATLTRACE(" >> cab name: %s\n", szStartingCabName);
ATLTRACE(" >> disk name: %s\n", szStartingDiskName);
m_view.AddPartialFile ( szFilename, szStartingCabName, szStartingDiskName );
return 0; // proceed with FDICopy
}
int CMainFrame::Notify_Enumerate (
long lCurrPos, USHORT cFilesLeft, USHORT uCabID )
{
ATLTRACE("fdi_Notify: fdintENUMERATE\n");
ATLTRACE(" >> current pos: %ld\n", lCurrPos);
ATLTRACE(" >> # files left: %hu\n", cFilesLeft);
ATLTRACE(" >> cab ID: %hu\n", uCabID);
return 0; // proceed with FDICopy
}
int CMainFrame::Notify_CopyFile (
LPCTSTR szFilename, long cbyUncompressedSize, USHORT uDate, USHORT uTime,
USHORT uAttribs, USHORT uFolderIdx )
{
ATLTRACE("fdi_Notify: fdintCOPY_FILE\n");
ATLTRACE(" >> file name: %s\n", szFilename);
ATLTRACE(" >> uncomp. size: %ld\n", cbyUncompressedSize);
ATLTRACE(" >> file date: %hu\n", uDate);
ATLTRACE(" >> file time: %hu\n", uTime);
ATLTRACE(" >> file attribs: %hu\n", uAttribs);
ATLTRACE(" >> folder index: %hu\n", uFolderIdx);
m_view.AddFile ( szFilename, cbyUncompressedSize, uDate, uTime, uAttribs );
return 0; // don't extract this file, we just wanted the attributes
}