00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
00044 ON_WM_TIMER()
00045 ON_WM_DESTROY()
00046
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
00059
00060 CFilePreviewDlg::CFilePreviewDlg(CDownload* pDownload, CWnd* pParent) : CSkinDialog( CFilePreviewDlg::IDD, pParent )
00061 {
00062
00063
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
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
00089 }
00090
00092
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
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
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
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
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 );
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
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
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
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
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 }