windows-nt/Source/XPSP1/NT/admin/pchealth/upload/client/uploadmanager/mpcupload.cpp
2020-09-26 16:20:57 +08:00

1110 lines
25 KiB
C++

/******************************************************************************
Copyright (c) 2000 Microsoft Corporation
Module Name:
MPCUpload.cpp
Abstract:
This file contains the implementation of the CMPCUpload class, which is
used as the entry point into the Upload Library.
Revision History:
Davide Massarenti (Dmassare) 04/15/99
created
******************************************************************************/
#include "stdafx.h"
#include <Sddl.h>
////////////////////////////////////////////////////////////////////////////////
static const WCHAR l_ConfigFile [] = L"%WINDIR%\\PCHEALTH\\UPLOADLB\\CONFIG\\CONFIG.XML";
static const WCHAR l_DirectoryFile[] = L"upload_library.db";
static const DWORD l_dwVersion = 0x03004C55; // UL 03
static const DATE l_SecondsInDay = (86400.0);
////////////////////////////////////////////////////////////////////////////////
MPC::CComObjectGlobalNoLock<CMPCUpload> g_Root;
////////////////////////////////////////////////////////////////////////////////
CMPCUpload::CMPCUpload()
{
__ULT_FUNC_ENTRY( "CMPCUpload::CMPCUpload" );
//
// Seed the random-number generator with current time so that
// the numbers will be different every time we run.
//
srand( ::GetTickCount() );
m_dwLastJobID = rand(); // DWORD m_dwLastJobID
// List m_lstActiveJobs
// CMPCTransportAgent m_mpctaThread;
m_fDirty = false; // mutable bool m_fDirty
m_fPassivated = false; // mutable bool m_fPassivated;
(void)MPC::_MPC_Module.RegisterCallback( this, (void (CMPCUpload::*)())Passivate );
}
CMPCUpload::~CMPCUpload()
{
MPC::_MPC_Module.UnregisterCallback( this );
Passivate();
}
////////////////////////////////////////
HRESULT CMPCUpload::Init()
{
__ULT_FUNC_ENTRY( "CMPCUpload::Init" );
HRESULT hr;
MPC::wstring str( l_ConfigFile ); MPC::SubstituteEnvVariables( str );
bool fLoaded;
MPC::SmartLock<_ThreadModel> lock( this );
//
// Load configuration.
//
g_Config.Load( str, fLoaded );
//
// Initialize Transport Agent
//
__MPC_EXIT_IF_METHOD_FAILS(hr, m_mpctaThread.LinkToSystem( this ));
//
// Load queue from disk.
//
if(FAILED(hr = InitFromDisk()))
{
//
// If, for any reason, loading failed, discard all the jobs and recreate a clean database...
//
CleanUp();
m_fDirty = true;
}
//
// Remove objects marked as DON'T QUEUE.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, RemoveNonQueueableJob( false ) );
//
// Remove entry from Task Scheduler
//
(void)Handle_TaskScheduler( false );
hr = S_OK;
__ULT_FUNC_CLEANUP;
__ULT_FUNC_EXIT(hr);
}
void CMPCUpload::Passivate()
{
__ULT_FUNC_ENTRY( "CMPCUpload::Passivate" );
MPC::SmartLock<_ThreadModel> lock( NULL );
//
// Stop the worker thread before starting the cleanup.
//
m_mpctaThread.Thread_Wait();
lock = this; // Get the lock.
if(m_fPassivated == false)
{
//
// Remove objects marked as DON'T QUEUE.
//
(void)RemoveNonQueueableJob( false );
//
// See if we need to reschedule ourself.
//
{
bool fNeedTS = false;
Iter it;
//
// Search for active jobs.
//
for(it = m_lstActiveJobs.begin(); it != m_lstActiveJobs.end(); it++)
{
CMPCUploadJob* mpcujJob = *it;
UL_STATUS ulStatus;
(void)mpcujJob->get_Status( &ulStatus );
switch(ulStatus)
{
case UL_ACTIVE :
case UL_TRANSMITTING:
case UL_ABORTED : fNeedTS = true; break;
}
}
if(fNeedTS)
{
(void)Handle_TaskScheduler( true );
}
}
CleanUp();
m_fPassivated = true;
}
}
void CMPCUpload::CleanUp()
{
__ULT_FUNC_ENTRY( "CMPCUpload::CleanUp" );
IterConst it;
//
// Release all the jobs.
//
for(it = m_lstActiveJobs.begin(); it != m_lstActiveJobs.end(); it++)
{
CMPCUploadJob* mpcujJob = *it;
mpcujJob->Unlink();
mpcujJob->Release();
}
m_lstActiveJobs.clear();
}
/////////////////////////////////////////////////////////////////////////////
HRESULT CMPCUpload::CreateChild( /*[in/out]*/ CMPCUploadJob*& mpcujJob )
{
__ULT_FUNC_ENTRY( "CMPCUpload::CreateChild" );
HRESULT hr;
CMPCUploadJob_Object* newobj;
MPC::SmartLock<_ThreadModel> lock( this );
mpcujJob = NULL;
__MPC_EXIT_IF_METHOD_FAILS(hr, newobj->CreateInstance( &newobj )); newobj->AddRef();
newobj->LinkToSystem( this );
m_lstActiveJobs.push_back( mpcujJob = newobj );
hr = S_OK;
__ULT_FUNC_CLEANUP;
__ULT_FUNC_EXIT(hr);
}
HRESULT CMPCUpload::ReleaseChild( /*[in/out]*/ CMPCUploadJob*& mpcujJob )
{
__ULT_FUNC_ENTRY( "CMPCUpload::ReleaseChild" );
MPC::SmartLock<_ThreadModel> lock( this );
if(mpcujJob)
{
m_lstActiveJobs.remove( mpcujJob );
mpcujJob->Unlink ();
mpcujJob->Release();
mpcujJob = NULL;
}
__ULT_FUNC_EXIT(S_OK);
}
HRESULT CMPCUpload::WrapChild( /*[in]*/ CMPCUploadJob* mpcujJob, /*[out]*/ IMPCUploadJob* *pVal )
{
__ULT_FUNC_ENTRY( "CMPCUpload::WrapChild" );
HRESULT hr;
CComPtr<CMPCUploadJobWrapper> wrap;
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &wrap ));
__MPC_EXIT_IF_METHOD_FAILS(hr, wrap->Init( mpcujJob ));
__MPC_EXIT_IF_METHOD_FAILS(hr, wrap.QueryInterface( pVal ));
hr = S_OK;
__ULT_FUNC_CLEANUP;
__ULT_FUNC_EXIT(hr);
}
/////////////////////////////////////////////////////////////////////////////
bool CMPCUpload::CanContinue()
{
__ULT_FUNC_ENTRY( "CMPCUpload::CanContinue" );
bool fRes = false;
DWORD dwMode = 0;
IterConst it;
MPC::SmartLock<_ThreadModel> lock( this );
//
// If no connection is available, there's no reason to continue.
//
if(::InternetGetConnectedState( &dwMode, 0 ) == TRUE)
{
//
// Search for at least one pending job.
//
for(it = m_lstActiveJobs.begin(); it != m_lstActiveJobs.end(); it++)
{
CMPCUploadJob* mpcujJob = *it;
UL_STATUS usStatus;
(void)mpcujJob->get_Status( &usStatus );
switch(usStatus)
{
case UL_ACTIVE :
case UL_TRANSMITTING:
case UL_ABORTED :
// This job can be executed, so we can continue.
fRes = true; __ULT_FUNC_LEAVE;
}
}
}
__ULT_FUNC_CLEANUP;
__ULT_FUNC_EXIT(fRes);
}
/////////////////////////////////////////////////////////////////////////////
HRESULT CMPCUpload::InitFromDisk()
{
__ULT_FUNC_ENTRY( "CMPCUpload::InitFromDisk" );
HRESULT hr;
HANDLE hFile = NULL;
MPC::wstring str;
MPC::wstring str_bak;
str = g_Config.get_QueueLocation(); str.append( l_DirectoryFile );
str_bak = str + L"_backup";
//
// First of all, try to open the backup file, if present.
//
hFile = ::CreateFileW( str_bak.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if(hFile == INVALID_HANDLE_VALUE)
{
//
// No backup present, so open the real file.
//
hFile = ::CreateFileW( str.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
}
else
{
//
// backup present, so delete the corrupted .db file.
//
(void)MPC::DeleteFile( str );
}
if(hFile == INVALID_HANDLE_VALUE)
{
hFile = NULL; // For cleanup.
DWORD dwRes = ::GetLastError();
if(dwRes != ERROR_FILE_NOT_FOUND)
{
__MPC_SET_WIN32_ERROR_AND_EXIT(hr, dwRes );
}
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
}
//
// Load the real data from storage.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, Load( MPC::Serializer_File( hFile ) ));
hr = S_OK;
__ULT_FUNC_CLEANUP;
if(hFile) ::CloseHandle( hFile );
//
// "RescheduleJobs" should be executed after the file is closed...
//
if(SUCCEEDED(hr))
{
hr = RescheduleJobs( true );
}
__ULT_FUNC_EXIT(hr);
}
HRESULT CMPCUpload::UpdateToDisk()
{
__ULT_FUNC_ENTRY( "CMPCUpload::UpdateToDisk" );
HRESULT hr;
HANDLE hFile = NULL;
MPC::wstring str;
MPC::wstring str_bak;
str = g_Config.get_QueueLocation(); str.append( l_DirectoryFile );
str_bak = str + L"_backup";
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::MakeDir( str ) );
//
// First of all, remove any old backup.
//
(void)MPC::DeleteFile( str_bak );
//
// Then, make a backup of current file.
//
(void)MPC::MoveFile( str, str_bak );
//
// Create the new file.
//
__MPC_EXIT_IF_INVALID_HANDLE__CLEAN(hr, hFile, ::CreateFileW( str.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL ));
__MPC_EXIT_IF_METHOD_FAILS(hr, Save( MPC::Serializer_File( hFile ) ));
//
// Remove the backup.
//
(void)MPC::DeleteFile( str_bak );
hr = S_OK;
__ULT_FUNC_CLEANUP;
if(hFile)
{
::FlushFileBuffers( hFile );
::CloseHandle ( hFile );
}
__ULT_FUNC_EXIT(hr);
}
/////////////////////////////////////////////////////////////////////////////
HRESULT CMPCUpload::TriggerRescheduleJobs()
{
__ULT_FUNC_ENTRY( "CMPCUpload::TriggerRescheduleJobs" );
HRESULT hr;
//
// Signal the Transport Agent.
//
m_mpctaThread.Thread_Signal();
hr = S_OK;
__ULT_FUNC_EXIT(hr);
}
HRESULT CMPCUpload::RemoveNonQueueableJob( /*[in]*/ bool fSignal )
{
__ULT_FUNC_ENTRY( "CMPCUpload::RemoveNonQueueableJob" );
HRESULT hr;
SYSTEMTIME stTime;
DATE dTime;
Iter it;
MPC::SmartLock<_ThreadModel> lock( this );
//
// Search for jobs which need to be updated.
//
for(it = m_lstActiveJobs.begin(); it != m_lstActiveJobs.end();)
{
CMPCUploadJob* mpcujJob = *it;
VARIANT_BOOL fPersistToDisk;
(void)mpcujJob->get_PersistToDisk( &fPersistToDisk );
if(fPersistToDisk == VARIANT_FALSE)
{
bool fSuccess;
(void)mpcujJob->put_Status( UL_DELETED );
__MPC_EXIT_IF_METHOD_FAILS(hr, mpcujJob->CanRelease( fSuccess ));
if(fSuccess)
{
//
// Remove from the system.
//
ReleaseChild( mpcujJob );
m_fDirty = true;
it = m_lstActiveJobs.begin(); // Iterator is no longer valid, start from the beginning.
continue;
}
}
it++;
}
//
// Save if needed.
//
if(IsDirty())
{
__MPC_EXIT_IF_METHOD_FAILS(hr, UpdateToDisk());
}
//
// Signal the Transport Agent.
//
if(fSignal) m_mpctaThread.Thread_Signal();
hr = S_OK;
__ULT_FUNC_CLEANUP;
__ULT_FUNC_EXIT(hr);
}
HRESULT CMPCUpload::RescheduleJobs( /*[in]*/ bool fSignal, /*[out]*/ DWORD *pdwWait )
{
__ULT_FUNC_ENTRY( "CMPCUpload::RescheduleJobs" );
HRESULT hr;
MPC::SmartLock<_ThreadModel> lock( this );
CMPCUploadJob* mpcujFirstJob = NULL;
DATE dTime = MPC::GetLocalTime();
DWORD dwWait = INFINITE;
Iter it;
//
// Search for jobs which need to be updated.
//
for(it = m_lstActiveJobs.begin(); it != m_lstActiveJobs.end();)
{
CMPCUploadJob* mpcujJob = *it;
UL_STATUS usStatus; (void)mpcujJob->get_Status ( &usStatus );
DATE dCompleteTime; (void)mpcujJob->get_CompleteTime ( &dCompleteTime );
DATE dExpirationTime; (void)mpcujJob->get_ExpirationTime( &dExpirationTime );
DWORD dwRetryInterval; (void)mpcujJob->get_RetryInterval ( &dwRetryInterval );
//
// If the job has an expiration date and it has passed, remove it.
//
if(dExpirationTime && dTime >= dExpirationTime)
{
(void)mpcujJob->put_Status( usStatus = UL_DELETED );
}
//
// Check if the job is ready for transmission.
//
switch(usStatus)
{
case UL_ACTIVE :
case UL_TRANSMITTING:
case UL_ABORTED :
//
// Pick the higher priority job.
//
if(mpcujFirstJob == NULL || *mpcujFirstJob < *mpcujJob) mpcujFirstJob = mpcujJob;
break;
}
//
// If the job is marked as ABORTED and a certain amount of time is elapsed, retry to send.
//
if(usStatus == UL_ABORTED)
{
DATE dDiff = (dCompleteTime + (dwRetryInterval / l_SecondsInDay)) - dTime;
if(dDiff > 0)
{
if(dwWait > dDiff * l_SecondsInDay)
{
dwWait = dDiff * l_SecondsInDay;
}
}
else
{
(void)mpcujJob->put_Status( usStatus = UL_ACTIVE );
}
}
//
// If the job is marked as DELETED, remove it.
//
if(usStatus == UL_DELETED)
{
bool fSuccess;
__MPC_EXIT_IF_METHOD_FAILS(hr, mpcujJob->CanRelease( fSuccess ));
if(fSuccess)
{
//
// Remove from the system.
//
m_lstActiveJobs.remove( mpcujJob );
mpcujJob->Unlink ();
mpcujJob->Release();
m_fDirty = true;
it = m_lstActiveJobs.begin(); // Iterator is no longer valid, start from the beginning.
continue;
}
}
it++;
}
//
// If the best job is ready, set the wait delay to zero.
//
if(mpcujFirstJob)
{
UL_STATUS usStatus; (void)mpcujFirstJob->get_Status( &usStatus );
if(usStatus == UL_ACTIVE ||
usStatus == UL_TRANSMITTING )
{
dwWait = 0;
}
}
//
// Save if needed.
//
if(IsDirty())
{
__MPC_EXIT_IF_METHOD_FAILS(hr, UpdateToDisk());
}
//
// Signal the Transport Agent.
//
if(fSignal) m_mpctaThread.Thread_Signal();
hr = S_OK;
__ULT_FUNC_CLEANUP;
if(pdwWait) *pdwWait = dwWait;
__ULT_FUNC_EXIT(hr);
}
HRESULT CMPCUpload::GetFirstJob( /*[out]*/ CMPCUploadJob*& mpcujJob ,
/*[out]*/ bool& fFound )
{
__ULT_FUNC_ENTRY( "CMPCUpload::GetFirstJob" );
HRESULT hr;
UL_STATUS usStatus;
IterConst it;
MPC::SmartLock<_ThreadModel> lock( this );
mpcujJob = NULL;
fFound = false;
//
// Rebuild the queue.
//
for(it = m_lstActiveJobs.begin(); it != m_lstActiveJobs.end(); it++)
{
CMPCUploadJob* mpcujJob2 = *it;
(void)mpcujJob2->get_Status( &usStatus );
//
// Check if the job is ready for transmission.
//
switch(usStatus)
{
case UL_ACTIVE :
case UL_TRANSMITTING:
case UL_ABORTED :
//
// Pick the higher priority job.
//
if(mpcujJob == NULL || *mpcujJob < *mpcujJob2) mpcujJob = mpcujJob2;
break;
}
}
if(mpcujJob)
{
(void)mpcujJob->get_Status( &usStatus );
if(usStatus != UL_ABORTED)
{
mpcujJob->AddRef();
fFound = true;
}
else
{
mpcujJob = NULL;
}
}
hr = S_OK;
__ULT_FUNC_EXIT(hr);
}
HRESULT CMPCUpload::GetJobByName( /*[out]*/ CMPCUploadJob*& mpcujJob ,
/*[out]*/ bool& fFound ,
/*[in] */ BSTR bstrName )
{
__ULT_FUNC_ENTRY( "CMPCUpload::GetJobByName" );
HRESULT hr;
IterConst it;
MPC::wstring szName = SAFEBSTR( bstrName );
MPC::SmartLock<_ThreadModel> lock( this );
mpcujJob = NULL;
fFound = false;
//
// Rebuild the queue.
//
for(it = m_lstActiveJobs.begin(); it != m_lstActiveJobs.end(); it++)
{
CMPCUploadJob* mpcujJob2 = *it;
CComBSTR bstrName2;
MPC::wstring szName2;
(void)mpcujJob2->get_JobID( &bstrName2 );
szName2 = SAFEBSTR( bstrName2 );
if(szName == szName2)
{
mpcujJob2->AddRef();
mpcujJob = mpcujJob2;
fFound = true;
break;
}
}
hr = S_OK;
__ULT_FUNC_EXIT(hr);
}
/////////////////////////////////////////////////////////////////////////////
HRESULT CMPCUpload::CalculateQueueSize( /*[out]*/ DWORD& dwSize )
{
__ULT_FUNC_ENTRY( "CMPCUpload::CalculateQueueSize" );
HRESULT hr;
MPC::SmartLock<_ThreadModel> lock( this );
dwSize = 0;
{
MPC::wstring szQueue = g_Config.get_QueueLocation();
WIN32_FILE_ATTRIBUTE_DATA wfadInfo;
MPC::FileSystemObject fso( szQueue.c_str() );
MPC::FileSystemObject::List lst;
MPC::FileSystemObject::Iter it;
__MPC_EXIT_IF_METHOD_FAILS(hr, fso.EnumerateFiles( lst ));
for(it = lst.begin(); it != lst.end(); it++)
{
DWORD dwFileSize;
__MPC_EXIT_IF_METHOD_FAILS(hr, (*it)->get_FileSize( dwFileSize ));
dwSize += dwFileSize;
}
}
hr = S_OK;
__ULT_FUNC_CLEANUP;
__ULT_FUNC_EXIT(hr);
}
//////////////////////////////////////////////////////////////////////
// Persistence
//////////////////////////////////////////////////////////////////////
bool CMPCUpload::IsDirty()
{
__ULT_FUNC_ENTRY( "CMPCUpload::IsDirty" );
bool fRes = true; // Default result.
IterConst it;
MPC::SmartLock<_ThreadModel> lock( this );
if(m_fDirty == true) __ULT_FUNC_LEAVE;
for(it = m_lstActiveJobs.begin(); it != m_lstActiveJobs.end(); it++)
{
CMPCUploadJob* mpcujJob = *it;
if(mpcujJob->IsDirty() == true) __ULT_FUNC_LEAVE;
}
fRes = false;
__ULT_FUNC_CLEANUP;
__ULT_FUNC_EXIT(fRes);
}
HRESULT CMPCUpload::Load( /*[in]*/ MPC::Serializer& streamIn )
{
__ULT_FUNC_ENTRY( "CMPCUpload::Load" );
HRESULT hr;
DWORD dwVer;
CMPCUploadJob* mpcujJob = NULL;
MPC::SmartLock<_ThreadModel> lock( this );
CleanUp();
//
// Version doesn't match, so force a rewrite and exit.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> dwVer);
if(dwVer != l_dwVersion)
{
m_fDirty = true;
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
}
__MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> m_dwLastJobID);
m_lstActiveJobs.clear();
while(1)
{
HRESULT hr2;
__MPC_EXIT_IF_METHOD_FAILS(hr, CreateChild( mpcujJob ));
if(FAILED(hr2 = mpcujJob->Load( streamIn )))
{
if(hr2 != HRESULT_FROM_WIN32( ERROR_HANDLE_EOF ))
{
__MPC_SET_ERROR_AND_EXIT(hr, hr2);
}
break;
}
mpcujJob = NULL;
}
m_fDirty = false;
hr = S_OK;
__ULT_FUNC_CLEANUP;
ReleaseChild( mpcujJob );
__ULT_FUNC_EXIT(hr);
}
HRESULT CMPCUpload::Save( /*[in]*/ MPC::Serializer& streamOut )
{
__ULT_FUNC_ENTRY( "CMPCUpload::Save" );
HRESULT hr;
IterConst it;
MPC::SmartLock<_ThreadModel> lock( this );
__MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << l_dwVersion );
__MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << m_dwLastJobID);
for(it = m_lstActiveJobs.begin(); it != m_lstActiveJobs.end(); it++)
{
CMPCUploadJob* mpcujJob = *it;
__MPC_EXIT_IF_METHOD_FAILS(hr, mpcujJob->Save( streamOut ));
}
m_fDirty = false;
__ULT_FUNC_CLEANUP;
__ULT_FUNC_EXIT(hr);
}
//////////////////////////////////////////////////////////////////////
// Enumerator
//////////////////////////////////////////////////////////////////////
STDMETHODIMP CMPCUpload::get__NewEnum( /*[out]*/ IUnknown* *pVal )
{
__ULT_FUNC_ENTRY( "CMPCUpload::get__NewEnum" );
HRESULT hr;
Iter it;
CComPtr<CMPCUploadEnum> pEnum;
MPC::SmartLock<_ThreadModel> lock( this );
__MPC_PARAMCHECK_BEGIN(hr)
__MPC_PARAMCHECK_POINTER_AND_SET(pVal,NULL);
__MPC_PARAMCHECK_END();
//
// Create the Enumerator and fill it with jobs.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &pEnum ));
for(it = m_lstActiveJobs.begin(); it != m_lstActiveJobs.end(); it++)
{
CComBSTR bstrUser;
__MPC_EXIT_IF_METHOD_FAILS(hr, (*it)->get_Creator( &bstrUser ));
if(SUCCEEDED(MPC::CheckCallerAgainstPrincipal( /*fImpersonate*/true, bstrUser, MPC::IDENTITY_SYSTEM | MPC::IDENTITY_ADMIN | MPC::IDENTITY_ADMINS )))
{
CComPtr<IMPCUploadJob> job;
__MPC_EXIT_IF_METHOD_FAILS(hr, WrapChild( *it, &job ));
__MPC_EXIT_IF_METHOD_FAILS(hr, pEnum->AddItem( job ));
}
}
__MPC_EXIT_IF_METHOD_FAILS(hr, pEnum->QueryInterface( IID_IEnumVARIANT, (void**)pVal ));
hr = S_OK;
__ULT_FUNC_CLEANUP;
__ULT_FUNC_EXIT(hr);
}
STDMETHODIMP CMPCUpload::Item( /*[in]*/ long index, /*[out]*/ IMPCUploadJob* *pVal )
{
__ULT_FUNC_ENTRY( "CMPCUpload::Item" );
HRESULT hr;
IterConst it;
MPC::SmartLock<_ThreadModel> lock( this );
__MPC_PARAMCHECK_BEGIN(hr)
__MPC_PARAMCHECK_POINTER_AND_SET(pVal,NULL);
__MPC_PARAMCHECK_END();
//
// Look for the N-th job.
//
for(it = m_lstActiveJobs.begin(); it != m_lstActiveJobs.end(); it++)
{
if(index-- == 0)
{
(*pVal = *it)->AddRef();
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
}
}
hr = E_INVALIDARG;
__ULT_FUNC_CLEANUP;
__ULT_FUNC_EXIT(hr);
}
STDMETHODIMP CMPCUpload::get_Count( /*[out]*/ long *pVal )
{
__ULT_FUNC_ENTRY( "CMPCUpload::get_Count" );
if(pVal == NULL) __ULT_FUNC_EXIT(E_POINTER);
MPC::SmartLock<_ThreadModel> lock( this );
*pVal = m_lstActiveJobs.size();
__ULT_FUNC_EXIT(S_OK);
}
STDMETHODIMP CMPCUpload::CreateJob( /*[out]*/ IMPCUploadJob* *pVal )
{
__ULT_FUNC_ENTRY( "CMPCUpload::CreateJob" );
HRESULT hr;
CMPCUploadJob* mpcujJob = NULL;
DWORD dwSize;
MPC::SmartLock<_ThreadModel> lock( this );
__MPC_PARAMCHECK_BEGIN(hr)
__MPC_PARAMCHECK_POINTER_AND_SET(pVal,NULL);
__MPC_PARAMCHECK_END();
//
// Check quota limits.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, CalculateQueueSize( dwSize ));
if(dwSize > g_Config.get_QueueSize())
{
__MPC_SET_ERROR_AND_EXIT(hr, E_UPLOADLIBRARY_CLIENT_QUOTA_EXCEEDED);
}
//
// Create a new job and link it to the system.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, CreateChild( mpcujJob ));
//
// Assign a unique ID to the job.
//
while(1)
{
WCHAR rgBuf[64];
swprintf( rgBuf, L"INNER_%08x", m_dwLastJobID );
__MPC_EXIT_IF_METHOD_FAILS(hr, mpcujJob->SetSequence( m_dwLastJobID++ ));
if(SUCCEEDED(hr = mpcujJob->put_JobID( CComBSTR( rgBuf ) ))) break;
if(hr != HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS))
{
//
// Some other error, bailing out...
//
__MPC_FUNC_LEAVE;
}
}
//
// Find out the ID of the caller.
//
{
CComBSTR bstrUser;
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::GetCallerPrincipal( /*fImpersonate*/true, bstrUser ));
__MPC_EXIT_IF_METHOD_FAILS(hr, mpcujJob->put_Creator( bstrUser ));
}
//
// Get the proxy settings from the caller...
//
(void)mpcujJob->GetProxySettings();
//
// Cast it to an IMPCUploadJob.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, WrapChild( mpcujJob, pVal ));
mpcujJob = NULL;
m_fDirty = true;
//
// Reschedule jobs, so the status of the queue will be updated to disk.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, RescheduleJobs( true ));
hr = S_OK;
__ULT_FUNC_CLEANUP;
ReleaseChild( mpcujJob );
__ULT_FUNC_EXIT(hr);
}