internal DownloadJob(Guid id, IBackgroundCopyJob bitsJob) { this.id = id; string name; bitsJob.GetDisplayName(out name); DisplayName = name; string description; bitsJob.GetDescription(out description); Description = description; BG_JOB_PRIORITY priority; bitsJob.GetPriority(out priority); Priority = (DownloadPriority)(int)priority; bitsJob.GetMinimumRetryDelay(out minimumRetryDelay); bitsJob.GetNoProgressTimeout(out noProgressTimeout); BG_JOB_STATE state; bitsJob.GetState(out state); Status = (DownloadStatus)(int)state; _BG_JOB_PROGRESS progress; bitsJob.GetProgress(out progress); BytesTotal = progress.BytesTotal; BytesTransferred = progress.BytesTransferred; bitsJob.SetNotifyInterface(this); IEnumBackgroundCopyFiles enumFiles = null; try { bitsJob.EnumFiles(out enumFiles); uint fetched; IBackgroundCopyFile file; enumFiles.Next(1, out file, out fetched); if (fetched == 1) { string remoteUrl; file.GetRemoteName(out remoteUrl); RemoteUrl = remoteUrl; string localName; file.GetLocalName(out localName); LocalFile = localName; } } finally { if (enumFiles != null) { Marshal.ReleaseComObject(enumFiles); } } }
/// <summary> /// Centralizes all chores related to stopping and cancelling a copy job, and getting back /// from BITS the errors incurred during the job. /// </summary> /// <param name="task">reference to the job associated task</param> /// <param name="pJob">reference to the copy job object (not job id)</param> /// <param name="pError">reference to the COM error reported by bits (might be null)</param> /// <param name="ex">reference to an exception cosidered as an error (might be null)</param> private void OnJobError(DownloadTask task, IBackgroundCopyJob pJob, IBackgroundCopyError pError, Exception ex) { Exception finalException = ex; if (pJob != null) { // get information about this job string jobDesc; pJob.GetDescription(out jobDesc); string jobName; pJob.GetDisplayName(out jobName); Guid jobID; pJob.GetId(out jobID); try { // if the error hasn't been reported, try to get it if (pError == null) { pJob.GetError(out pError); } } catch (COMException e) { Logger.Error(e); if (e.ErrorCode != ExceptionCodeNotAnError) { throw; } } // If we've got the native error, wrap into a nicer exception if (pError != null) { var BitsEx = new BitsDownloadErrorException(pError, (uint)CultureIdForGettingComErrorMessages); cumulativeErrorMessage += BitsEx.Message + Environment.NewLine; finalException = BitsEx; } BG_JOB_STATE state; pJob.GetState(out state); if (state != BG_JOB_STATE.BG_JOB_STATE_ACKNOWLEDGED && state != BG_JOB_STATE.BG_JOB_STATE_CANCELLED) { pJob.Cancel(); } RemoveCopyJobEntry(jobID); } OnDownloadError(new DownloadTaskErrorEventArgs(task, finalException)); Logger.Error(finalException); //throw finalException; }
/// <summary> /// Centralizes all chores related to stopping and cancelling a copy job, and getting back /// from BITS the errors incurred during the job. /// </summary> /// <param name="copyJob">reference to the copy job object (not job id)</param> /// <param name="errMessage">a cumulative error message passed by reference so /// that additions can be made</param> private void HandleDownloadErrorCancelJob( IBackgroundCopyJob copyJob, ref string errMessage) { string singleError = ""; string jobDesc = ""; string jobName = ""; Guid jobID = Guid.Empty; IBackgroundCopyError copyError = null; try { // check if job is null; don't try to clean up null references! if (null != copyJob) { // get information about this job for reporting the error copyJob.GetDescription(out jobDesc); copyJob.GetDisplayName(out jobName); copyJob.GetId(out jobID); // find out what the error was copyJob.GetError(out copyError); // use the culture id specified in RESX to tell COM which culture to return err message in: copyError.GetErrorDescription((uint)CULTURE_ID_FOR_COM, out singleError); // add error to our "stack" of errors: errMessage += singleError + Environment.NewLine; // notify BITS that we consider this job a loss, forget about it: copyJob.Cancel(); // remove job from collection RemoveCopyJobEntry(jobID); // log error, but don't throw here; let dnldmgr take care of error // NOTE that errMessage is used cumulatively for full track of problem errMessage = ApplicationUpdateManager.TraceWrite("[BITSDownloader]", "RES_EXCEPTION_BITSBackgroundCopyError", jobID, jobName, jobDesc, errMessage); ExceptionManager.Publish(new Exception(errMessage)); } } finally { if (null != copyError) { Marshal.ReleaseComObject(copyError); copyError = null; } } }
private void RefreshJobProperties( ) { _job.GetDisplayName(out _displayName); _job.GetDescription(out _description); _BG_JOB_PROGRESS jobProgress; _job.GetProgress(out jobProgress); _bytesTotal = jobProgress.BytesTotal; _bytesTransferred = jobProgress.BytesTransferred; BG_JOB_STATE jobState; _job.GetState(out jobState); this.JobStateDescription = Enum.GetName(jobState.GetType(), jobState); }
/// <summary> /// returns a job status enum for a particular job identified by its GUID /// </summary> /// <param name="jobId">a guid for the job requested</param> /// <returns>a JobStatus describing the state of the job</returns> JobStatus IDownloader.GetJobStatus(Guid jobId) { IBackgroundCopyManager backGroundCopyManager = null; IBackgroundCopyJob backGroundCopyJob = null; BG_JOB_STATE state; string errMessage = ""; string jobName = ""; string jobDesc = ""; string error = ""; try { backGroundCopyManager = (IBackgroundCopyManager) new BackgroundCopyManager(); backGroundCopyManager.GetJob(ref jobId, out backGroundCopyJob); // get job name backGroundCopyJob.GetDisplayName(out jobName); // get job desc backGroundCopyJob.GetDescription(out jobDesc); // get job state enum value backGroundCopyJob.GetState(out state); switch (state) { case BG_JOB_STATE.BG_JOB_STATE_ERROR: { // use utility method to handle error: HandleDownloadErrorCancelJob(backGroundCopyJob, ref errMessage); // return status as error return(JobStatus.Error); } case BG_JOB_STATE.BG_JOB_STATE_TRANSIENT_ERROR: { // NOTE: if transient, just treat as full error. During testing about 90% of transients // resulted in full failure. Cleanup. // use utility method to handle error: HandleDownloadErrorCancelJob(backGroundCopyJob, ref errMessage); // return status as error return(JobStatus.Error); } case BG_JOB_STATE.BG_JOB_STATE_TRANSFERRED: { // tell BITS to transfer to us and stop thinking about the job backGroundCopyJob.Complete(); // remove job from collection to be Dispose()ed RemoveCopyJobEntry(jobId); return(JobStatus.Ready); } case BG_JOB_STATE.BG_JOB_STATE_CANCELLED: { // use utility method to handle error: HandleDownloadErrorCancelJob(backGroundCopyJob, ref errMessage); // return status as cancelled return(JobStatus.Cancelled); } default: return(JobStatus.Downloading); } } catch (ThreadInterruptedException tie) { // if interrupted, clean up job HandleDownloadErrorCancelJob(backGroundCopyJob, ref errMessage); ApplicationUpdateManager.TraceWrite(tie, "[BITSDownloader.Download]", "RES_TIEInBITS", "N/A"); throw tie; } catch (Exception e) { // use utility method to handle error: HandleDownloadErrorCancelJob(backGroundCopyJob, ref errMessage); // bad to catch all exceptions, but OK because we adorn it with necessary additional info then pass it up as innerException error = ApplicationUpdateManager.TraceWrite(e, "[BITSDownloader.GetJobStatus]", "RES_EXCEPTION_BITSOtherError", jobId, jobName, jobDesc); // publish Exception newE = new Exception(error, e); ExceptionManager.Publish(newE); // rethrow; throw newE; } finally { if (backGroundCopyManager != null) { Marshal.ReleaseComObject(backGroundCopyManager); } if (backGroundCopyJob != null) { Marshal.ReleaseComObject(backGroundCopyJob); } } }
/// <summary> /// Centralizes all chores related to stopping and cancelling a copy job, and getting back /// from BITS the errors incurred during the job. /// </summary> /// <param name="copyJob">reference to the copy job object (not job id)</param> /// <param name="errMessage">a cumulative error message passed by reference so /// that additions can be made</param> private void HandleDownloadErrorCancelJob( IBackgroundCopyJob copyJob, ref string errMessage) { string singleError = ""; string jobDesc = ""; string jobName = ""; Guid jobID = Guid.Empty; IBackgroundCopyError copyError = null; try { // check if job is null; don't try to clean up null references! if( null != copyJob ) { // get information about this job for reporting the error copyJob.GetDescription( out jobDesc ); copyJob.GetDisplayName( out jobName ); copyJob.GetId( out jobID ); // find out what the error was copyJob.GetError( out copyError ); // use the culture id specified in RESX to tell COM which culture to return err message in: copyError.GetErrorDescription( (uint)CULTURE_ID_FOR_COM, out singleError ); // add error to our "stack" of errors: errMessage += singleError + Environment.NewLine; // notify BITS that we consider this job a loss, forget about it: copyJob.Cancel(); // remove job from collection RemoveCopyJobEntry( jobID ); // log error, but don't throw here; let dnldmgr take care of error // NOTE that errMessage is used cumulatively for full track of problem errMessage = ApplicationUpdateManager.TraceWrite( "[BITSDownloader]", "RES_EXCEPTION_BITSBackgroundCopyError", jobID, jobName, jobDesc, errMessage ); ExceptionManager.Publish( new Exception( errMessage ) ); } } finally { if( null != copyError ) { Marshal.ReleaseComObject( copyError ); copyError = null; } } }