Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

DlgFilePreview.cpp

Go to the documentation of this file.
00001 //
00002 // DlgFilePreview.cpp
00003 //
00004 // Copyright (c) Shareaza Development Team, 2002-2005.
00005 // This file is part of SHAREAZA (www.shareaza.com)
00006 //
00007 // Shareaza is free software; you can redistribute it
00008 // and/or modify it under the terms of the GNU General Public License
00009 // as published by the Free Software Foundation; either version 2 of
00010 // the License, or (at your option) any later version.
00011 //
00012 // Shareaza is distributed in the hope that it will be useful,
00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 // GNU General Public License for more details.
00016 //
00017 // You should have received a copy of the GNU General Public License
00018 // along with Shareaza; if not, write to the Free Software
00019 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020 //
00021 
00022 #include "StdAfx.h"
00023 #include "Shareaza.h"
00024 #include "Settings.h"
00025 #include "Transfers.h"
00026 #include "Downloads.h"
00027 #include "Download.h"
00028 #include "FragmentedFile.h"
00029 #include "TransferFile.h"
00030 #include "DlgFilePreview.h"
00031 #include "FileExecutor.h"
00032 #include "Plugins.h"
00033 
00034 #ifdef _DEBUG
00035 #define new DEBUG_NEW
00036 #undef THIS_FILE
00037 static char THIS_FILE[] = __FILE__;
00038 #endif
00039 
00040 IMPLEMENT_DYNAMIC(CFilePreviewDlg, CSkinDialog)
00041 
00042 BEGIN_MESSAGE_MAP(CFilePreviewDlg, CSkinDialog)
00043         //{{AFX_MSG_MAP(CFilePreviewDlg)
00044         ON_WM_TIMER()
00045         ON_WM_DESTROY()
00046         //}}AFX_MSG_MAP
00047         ON_WM_CLOSE()
00048 END_MESSAGE_MAP()
00049 
00050 BEGIN_INTERFACE_MAP(CFilePreviewDlg, CSkinDialog)
00051         INTERFACE_PART(CFilePreviewDlg, IID_IDownloadPreviewSite, DownloadPreviewSite)
00052 END_INTERFACE_MAP()
00053 
00054 CPtrList CFilePreviewDlg::m_pWindows;
00055 
00056 
00058 // CFilePreviewDlg dialog
00059 
00060 CFilePreviewDlg::CFilePreviewDlg(CDownload* pDownload, CWnd* pParent) : CSkinDialog( CFilePreviewDlg::IDD, pParent )
00061 {
00062         //{{AFX_DATA_INIT(CFilePreviewDlg)
00063         //}}AFX_DATA_INIT
00064         
00065         m_pDownload     = NULL;
00066         m_pPlugin       = NULL;
00067         m_bThread       = FALSE;
00068         m_hThread       = NULL;
00069         m_pPlugin       = NULL;
00070         
00071         SetDownload( pDownload );
00072 }
00073 
00074 CFilePreviewDlg::~CFilePreviewDlg()
00075 {
00076         if ( POSITION pos = m_pWindows.Find( this ) ) m_pWindows.RemoveAt( pos );
00077         ASSERT( m_pDownload == NULL );
00078 }
00079 
00080 void CFilePreviewDlg::DoDataExchange(CDataExchange* pDX)
00081 {
00082         CSkinDialog::DoDataExchange( pDX );
00083         //{{AFX_DATA_MAP(CFilePreviewDlg)
00084         DDX_Control(pDX, IDCANCEL, m_wndCancel);
00085         DDX_Control(pDX, IDC_PROGRESS, m_wndProgress);
00086         DDX_Control(pDX, IDC_PREVIEW_STATUS, m_wndStatus);
00087         DDX_Control(pDX, IDC_FILE_NAME, m_wndName);
00088         //}}AFX_DATA_MAP
00089 }
00090 
00092 // CFilePreviewDlg operations
00093 
00094 void CFilePreviewDlg::SetDownload(CDownload* pDownload)
00095 {
00096         ASSERT( m_pDownload == NULL );
00097         m_pDownload = pDownload;
00098         ASSERT( m_pDownload != NULL );
00099         
00100         m_sSourceName = pDownload->m_sLocalName;
00101         m_sRemoteName = pDownload->m_sRemoteName;
00102         
00103         int nPos = m_sSourceName.ReverseFind( '\\' );
00104         
00105         if ( nPos >= 0 )
00106         {
00107                 for ( int nCount = 0 ; nCount < 20 ; nCount++ )
00108                 {
00109                         if ( nCount > 0 )
00110                         {
00111                                 m_sTargetName.Format( _T("%sPreview (%i) of %s"),
00112                                         (LPCTSTR)m_sSourceName.Left( nPos + 1 ), nCount,
00113                                         (LPCTSTR)m_sSourceName.Mid( nPos + 1 ) );
00114                         }
00115                         else
00116                         {
00117                                 m_sTargetName.Format( _T("%sPreview of %s"),
00118                                         (LPCTSTR)m_sSourceName.Left( nPos + 1 ),
00119                                         (LPCTSTR)m_sSourceName.Mid( nPos + 1 ) );
00120                         }
00121                         
00122                         if ( GetFileAttributes( m_sTargetName ) == 0xFFFFFFFF ) break;
00123                 }
00124         }
00125 
00126         // if user changes extension or extension is lost
00127         LPCTSTR pszExt1 = _tcsrchr( m_sSourceName, '.' );
00128         LPCTSTR pszExt2 = _tcsrchr( m_sRemoteName, '.' );
00129         if ( ! pszExt1 && pszExt2 || pszExt1 && pszExt2 && _tcsicmp( pszExt1, pszExt2 ) != 0 ) 
00130                 m_sTargetName += pszExt2;
00131 
00132     if ( !m_pDownload->GetEmptyFragmentList().empty() )
00133     {
00134         FF::SimpleFragmentList oRanges = inverse( m_pDownload->GetEmptyFragmentList() );
00135 
00136         for ( FF::SimpleFragmentList::ConstIterator pFragment
00137             = oRanges.begin(); pFragment != oRanges.end(); ++pFragment )
00138             {
00139                     m_pRanges.Add( DWORD( pFragment->begin() ) );
00140                     m_pRanges.Add( DWORD( pFragment->length() ) );
00141             }
00142                 
00143             if ( ( GetAsyncKeyState( VK_CONTROL ) & 0x8000 ) == 0x8000 )
00144             {
00145                     while ( m_pRanges.GetSize() > 2 ) m_pRanges.RemoveAt( 2 );
00146             }
00147     }
00148 }
00149 
00150 BOOL CFilePreviewDlg::Create()
00151 {
00152         ASSERT( m_hWnd == NULL );
00153         ASSERT( m_pDownload != NULL );
00154         
00155         LPCTSTR lpszTemplateName = MAKEINTRESOURCE( IDD );
00156         
00157         HINSTANCE hInst         = AfxFindResourceHandle( lpszTemplateName, RT_DIALOG );
00158         HRSRC hResource         = ::FindResource( hInst, lpszTemplateName, RT_DIALOG );
00159         HGLOBAL hTemplate       = LoadResource( hInst, hResource );
00160         
00161         LPCDLGTEMPLATE lpDialogTemplate = (LPCDLGTEMPLATE)LockResource( hTemplate );
00162         
00163         BOOL bResult = CreateDlgIndirect( lpDialogTemplate, NULL, hInst );
00164         
00165         UnlockResource( hTemplate );
00166         FreeResource( hTemplate );
00167         
00168         return bResult;
00169 }
00170 
00171 void CFilePreviewDlg::OnSkinChange(BOOL bSet)
00172 {
00173         for ( POSITION pos = m_pWindows.GetHeadPosition() ; pos ; )
00174         {
00175                 CFilePreviewDlg* pDlg = (CFilePreviewDlg*)m_pWindows.GetNext( pos );
00176                 
00177                 if ( bSet )
00178                 {
00179                         pDlg->SkinMe( NULL, ID_DOWNLOADS_LAUNCH_COPY );
00180                         pDlg->Invalidate();
00181                 }
00182                 else
00183                 {
00184                         pDlg->m_pSkin = NULL;
00185                 }
00186         }
00187 }
00188 
00189 void CFilePreviewDlg::CloseAll()
00190 {
00191         for ( POSITION pos = m_pWindows.GetHeadPosition() ; pos ; )
00192         {
00193                 delete (CFilePreviewDlg*)m_pWindows.GetNext( pos );
00194         }
00195         m_pWindows.RemoveAll();
00196 }
00197 
00199 // CFilePreviewDlg message handlers
00200 
00201 BOOL CFilePreviewDlg::OnInitDialog() 
00202 {
00203         CSkinDialog::OnInitDialog();
00204         
00205         SkinMe( NULL, ID_DOWNLOADS_LAUNCH_COPY );
00206         
00207         m_nRange        = 100;
00208         m_nPosition     = 0;
00209         m_nScaled       = m_nOldScaled = 0;
00210         
00211         if ( theApp.m_bRTL ) m_wndProgress.ModifyStyleEx( WS_EX_LAYOUTRTL, 0, 0 );
00212         m_wndStatus.GetWindowText( m_sStatus ); 
00213         m_wndProgress.SetRange( 0, 1000 );
00214         m_wndProgress.SetPos( 0 );
00215         m_sOldStatus = m_sStatus;
00216         
00217         m_wndName.SetWindowText( m_sRemoteName );
00218         m_wndCancel.EnableWindow( FALSE );
00219         
00220         m_bThread = TRUE;
00221         m_bCancel = FALSE;
00222         
00223         CWinThread* pThread = AfxBeginThread( ThreadStart, this, THREAD_PRIORITY_NORMAL );
00224         m_hThread = pThread->m_hThread;
00225         
00226         return TRUE;
00227 }
00228 
00229 void CFilePreviewDlg::OnCancel() 
00230 {
00231         if ( m_bThread )
00232         {
00233                 m_pSection.Lock();
00234                 m_bCancel = TRUE;
00235                 if ( m_pPlugin != NULL ) m_pPlugin->Cancel();
00236                 m_pSection.Unlock();
00237         }
00238         else
00239         {
00240                 PostMessage( WM_CLOSE );
00241         }
00242 }
00243 
00244 void CFilePreviewDlg::OnTimer(UINT nIDEvent) 
00245 {
00246         if ( nIDEvent == 3 )
00247         {
00248                 PostMessage( WM_CLOSE );
00249                 return;
00250         }
00251         
00252         CSingleLock pLock( &m_pSection, TRUE );
00253         
00254         if ( nIDEvent == 2 && m_sExecute.GetLength() > 0 )
00255         {
00256                 CString strExecute = m_sExecute;
00257                 m_sExecute.Empty();
00258                 pLock.Unlock();
00259                 CFileExecutor::Execute( strExecute, TRUE );
00260                 return;
00261         }
00262         
00263         if ( m_nScaled != m_nOldScaled )
00264         {
00265                 m_wndProgress.SetPos( m_nScaled );
00266                 m_nOldScaled = m_nScaled;
00267         }
00268         
00269         if ( m_sStatus != m_sOldStatus )
00270         {
00271                 m_wndStatus.SetWindowText( m_sStatus );
00272                 m_sOldStatus = m_sStatus;
00273         }
00274         
00275         if ( ! m_wndCancel.IsWindowEnabled() ) m_wndCancel.EnableWindow( TRUE );
00276 }
00277 
00278 void CFilePreviewDlg::OnClose()
00279 {
00280         DestroyWindow();
00281 }
00282 
00283 void CFilePreviewDlg::OnDestroy() 
00284 {
00285         if ( m_hThread != NULL )
00286         {
00287         int nAttempt = 100;
00288                 for ( ; nAttempt > 0 ; nAttempt-- )
00289                 {
00290                         DWORD nCode;
00291                         if ( ! GetExitCodeThread( m_hThread, &nCode ) ) break;
00292                         if ( nCode != STILL_ACTIVE ) break;
00293                         Sleep( 50 );
00294                 }
00295                 
00296                 if ( nAttempt == 0 )
00297                 {
00298                         TerminateThread( m_hThread, 0 );
00299                         theApp.Message( MSG_DEBUG, _T("WARNING: Terminating CFilePreviewDlg thread.") );
00300                         Sleep( 250 );
00301                 }
00302         }
00303         
00304         m_bThread       = FALSE;
00305         m_hThread       = NULL;
00306         
00307         if ( m_pDownload != NULL )
00308         {
00309                 if ( Transfers.m_pSection.Lock( 1000 ) )
00310                 {
00311                         if ( Downloads.Check( m_pDownload ) ) m_pDownload->m_pPreviewWnd = NULL;
00312                         Transfers.m_pSection.Unlock();
00313                 }
00314                 m_pDownload = NULL;
00315         }
00316         
00317         CSkinDialog::OnDestroy();
00318 }
00319 
00320 void CFilePreviewDlg::PostNcDestroy() 
00321 {
00322         CSkinDialog::PostNcDestroy();
00323         delete this;
00324 }
00325 
00327 // CFilePreviewDlg thread run
00328 
00329 UINT CFilePreviewDlg::ThreadStart(LPVOID pParam)
00330 {
00331         CFilePreviewDlg* pClass = (CFilePreviewDlg*)pParam;
00332         pClass->OnRun();
00333         return 0;
00334 }
00335 
00336 void CFilePreviewDlg::OnRun()
00337 {
00338         HANDLE hFile = CreateFile( m_sSourceName, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
00339                 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
00340         
00341         if ( hFile != INVALID_HANDLE_VALUE )
00342         {
00343                 if ( ! RunPlugin( hFile ) && ! m_bCancel ) RunManual( hFile );
00344                 CloseHandle( hFile );
00345         }
00346         
00347         m_bThread = FALSE;
00348         PostMessage( WM_TIMER, 3 );
00349 }
00350 
00352 // CFilePreviewDlg plugin execution
00353 
00354 BOOL CFilePreviewDlg::RunPlugin(HANDLE hFile)
00355 {
00356         CString strType;
00357         
00358         int nExtPos = m_sTargetName.ReverseFind( '.' );
00359         if ( nExtPos > 0 ) strType = m_sTargetName.Mid( nExtPos );
00360         CharLower( strType.GetBuffer() );
00361         strType.ReleaseBuffer();
00362         
00363         if ( ! LoadPlugin( strType ) ) return FALSE;
00364         
00365         HRESULT hr = S_FALSE;
00366         
00367         if ( SUCCEEDED( m_pPlugin->SetSite( &m_xDownloadPreviewSite ) ) )
00368         {
00369                 BSTR bsFile = m_sTargetName.AllocSysString();
00370                 hr = m_pPlugin->Preview( hFile, bsFile );
00371                 SysFreeString( bsFile );
00372         }
00373         
00374         m_pSection.Lock();
00375         m_pPlugin->Release();
00376         m_pPlugin = NULL;
00377         m_pSection.Unlock();
00378         
00379         CoUninitialize();
00380         
00381         if ( hr != S_OK ) Sleep( 1000 );
00382         
00383         return ( hr != S_FALSE );       // Fall through if it's S_FALSE
00384 }
00385 
00386 BOOL CFilePreviewDlg::LoadPlugin(LPCTSTR pszType)
00387 {
00388         CLSID pCLSID;
00389         
00390         if ( ! Plugins.LookupCLSID( _T("DownloadPreview"), pszType, pCLSID ) ) return FALSE;
00391         
00392         if ( FAILED( CoInitializeEx( NULL, COINIT_MULTITHREADED ) ) ) return FALSE;
00393         
00394         HRESULT hResult = CoCreateInstance( pCLSID, NULL, CLSCTX_INPROC_SERVER,
00395                 IID_IDownloadPreviewPlugin, (void**)&m_pPlugin );
00396         
00397         if ( SUCCEEDED( hResult ) )
00398         {
00399                 return TRUE;
00400         }
00401         else
00402         {
00403                 CoUninitialize();
00404                 return FALSE;
00405         }
00406 }
00407 
00409 // CFilePreviewDlg manual execution
00410 
00411 #define BUFFER_SIZE 40960
00412 
00413 BOOL CFilePreviewDlg::RunManual(HANDLE hFile)
00414 {
00415         HANDLE hTarget = CreateFile( m_sTargetName, GENERIC_WRITE, FILE_SHARE_READ,
00416                 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
00417         
00418         if ( hTarget == INVALID_HANDLE_VALUE ) return FALSE;
00419         
00420         m_nRange = m_nPosition = 0;
00421         
00422         for ( int nRange = 0 ; nRange < m_pRanges.GetSize() ; nRange += 2 )
00423         {
00424                 m_nRange += m_pRanges.GetAt( nRange + 1 );
00425         }
00426         
00427         UpdateProgress( TRUE, m_nRange, TRUE, m_nPosition );
00428         
00429         BYTE* pData = new BYTE[ BUFFER_SIZE ];
00430         
00431         for ( int nRange = 0 ; nRange < m_pRanges.GetSize() ; nRange += 2 )
00432         {
00433                 DWORD nOffset = m_pRanges.GetAt( nRange );
00434                 DWORD nLength = m_pRanges.GetAt( nRange + 1 );
00435                 
00436                 SetFilePointer( hFile, nOffset, 0, FILE_BEGIN );
00437                 // SetFilePointer( hTarget, nOffset, 0, FILE_BEGIN );
00438                 
00439                 while ( nLength )
00440                 {
00441                         DWORD nChunk = min( DWORD(BUFFER_SIZE), nLength );
00442                         
00443                         ReadFile( hFile, pData, nChunk, &nChunk, NULL );
00444                         
00445                         if ( nChunk == 0 )
00446                         {
00447                                 theApp.Message( MSG_DEBUG, _T("Preview: read error.") );
00448                                 m_bCancel = TRUE;
00449                         }
00450                         
00451                         WriteFile( hTarget, pData, nChunk, &nChunk, NULL );
00452                         
00453                         if ( nChunk == 0 )
00454                         {
00455                                 theApp.Message( MSG_DEBUG, _T("Preview: write error.") );
00456                                 m_bCancel = TRUE;
00457                         }
00458                         
00459                         nLength -= nChunk;
00460                         
00461                         if ( m_bCancel ) break;
00462                         
00463                         UpdateProgress( FALSE, 0, TRUE, m_nPosition + nChunk );
00464                 }
00465         }
00466         
00467         delete [] pData;
00468         
00469         CloseHandle( hTarget );
00470         
00471         if ( m_bCancel )
00472         {
00473                 DeleteFile( m_sTargetName );
00474                 return FALSE;
00475         }
00476         
00477         QueueDeleteFile( m_sTargetName );
00478         ExecuteFile( m_sTargetName );
00479         
00480         return TRUE;
00481 }
00482 
00484 // CFilePreviewDlg utilities
00485 
00486 BOOL CFilePreviewDlg::QueueDeleteFile(LPCTSTR pszFile)
00487 {
00488         CSingleLock pLock( &Transfers.m_pSection );
00489 
00490         if ( pLock.Lock( 500 ) )
00491         {
00492                 if ( Downloads.Check( m_pDownload ) )
00493                 {
00494                         m_pDownload->AddPreviewName( pszFile );
00495                         return TRUE;
00496                 }
00497         }
00498 
00499         return FALSE;
00500 }
00501 
00502 BOOL CFilePreviewDlg::ExecuteFile(LPCTSTR pszFile)
00503 {
00504         m_pSection.Lock();
00505         m_sExecute = pszFile;
00506         PostMessage( WM_TIMER, 2 );
00507         m_pSection.Unlock();
00508 
00509         return TRUE;
00510 }
00511 
00512 void CFilePreviewDlg::UpdateProgress(BOOL bRange, QWORD nRange, BOOL bPosition, QWORD nPosition)
00513 {
00514         m_pSection.Lock();
00515         
00516         if ( bRange ) m_nRange = nRange;
00517         if ( bPosition ) m_nPosition = nPosition;
00518         
00519         m_nScaled = (DWORD)( (double)m_nPosition / (double)m_nRange * 1000.0f );
00520         BOOL bRefresh = ( m_nScaled != m_nOldScaled );
00521         
00522         m_pSection.Unlock();
00523         if ( bRefresh ) PostMessage( WM_TIMER, 1 );
00524 }
00525 
00527 // CFilePreviewDlg IDownloadPreviewSite
00528 
00529 IMPLEMENT_UNKNOWN(CFilePreviewDlg, DownloadPreviewSite)
00530 
00531 STDMETHODIMP CFilePreviewDlg::XDownloadPreviewSite::GetSuggestedFilename(BSTR FAR* psFile)
00532 {
00533         METHOD_PROLOGUE( CFilePreviewDlg, DownloadPreviewSite )
00534         pThis->m_sTargetName.SetSysString( psFile );
00535         return S_OK;
00536 }
00537 
00538 STDMETHODIMP CFilePreviewDlg::XDownloadPreviewSite::GetAvailableRanges(SAFEARRAY FAR* FAR* pArray)
00539 {
00540         METHOD_PROLOGUE( CFilePreviewDlg, DownloadPreviewSite )
00541         
00542         SAFEARRAYBOUND pBound[2] = { { pThis->m_pRanges.GetSize() / 2, 0 }, { 2, 0 } };
00543         *pArray = SafeArrayCreate( VT_I4, 2, pBound );
00544         
00545         DWORD* pTarget;
00546         SafeArrayAccessData( *pArray, (void**)&pTarget );
00547         
00548         for ( int nRange = 0 ; nRange < pThis->m_pRanges.GetSize() ; nRange++, pTarget++ )
00549         {
00550                 *pTarget = pThis->m_pRanges.GetAt( nRange );
00551         }
00552         
00553         SafeArrayUnaccessData( *pArray );
00554         
00555         return S_OK;
00556 }
00557 
00558 STDMETHODIMP CFilePreviewDlg::XDownloadPreviewSite::SetProgressRange(DWORD nRange)
00559 {
00560         METHOD_PROLOGUE( CFilePreviewDlg, DownloadPreviewSite )
00561         pThis->UpdateProgress( TRUE, nRange, FALSE, 0 );
00562         return S_OK;
00563 }
00564 
00565 STDMETHODIMP CFilePreviewDlg::XDownloadPreviewSite::SetProgressPosition(DWORD nPosition)
00566 {
00567         METHOD_PROLOGUE( CFilePreviewDlg, DownloadPreviewSite )
00568         pThis->UpdateProgress( FALSE, 0, TRUE, nPosition );
00569         return S_OK;
00570 }
00571 
00572 STDMETHODIMP CFilePreviewDlg::XDownloadPreviewSite::SetProgressMessage(BSTR sMessage)
00573 {
00574         METHOD_PROLOGUE( CFilePreviewDlg, DownloadPreviewSite )
00575         pThis->m_pSection.Lock();
00576         pThis->m_sStatus = sMessage;
00577         pThis->m_pSection.Unlock();
00578         pThis->PostMessage( WM_TIMER );
00579         return S_OK;
00580 }
00581 
00582 STDMETHODIMP CFilePreviewDlg::XDownloadPreviewSite::QueueDeleteFile(BSTR sTempFile)
00583 {
00584         METHOD_PROLOGUE( CFilePreviewDlg, DownloadPreviewSite )
00585         return pThis->QueueDeleteFile( CString( sTempFile ) ) ? S_OK : E_FAIL;
00586 }
00587 
00588 STDMETHODIMP CFilePreviewDlg::XDownloadPreviewSite::ExecuteFile(BSTR sFile)
00589 {
00590         METHOD_PROLOGUE( CFilePreviewDlg, DownloadPreviewSite )
00591         return pThis->ExecuteFile( CString( sFile ) ) ? S_OK : E_FAIL;
00592 }

Generated on Thu Dec 15 10:39:39 2005 for Shareaza 2.2.1.0 by  doxygen 1.4.2