/****************************************************************************** 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 //////////////////////////////////////////////////////////////////////////////// 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 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 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 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 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); }