Пример #1
0
        public void JobModification(IBackgroundCopyJob pJob, uint dwReserved)
        {
            BitsJob job;

            if (null != this.onJobModified)
            {
                Guid guid;
                pJob.GetId(out guid);
                if (manager.Jobs.ContainsKey(guid))
                {
                    job = manager.Jobs[guid];
                }
                else
                {
                    // Update Joblist to check whether the job still exists. If not, just return
                    manager.EnumJobs(manager.currentOwner);
                    if (manager.Jobs.ContainsKey(guid))
                    {
                        job = manager.Jobs[guid];
                    }
                    else
                    {
                        return;
                    }
                }
                this.onJobModified(this, new NotificationEventArgs(job));
                //forward event
                if (job.notificationTarget != null)
                {
                    job.notificationTarget.JobModification(pJob, dwReserved);
                }
            }
        }
Пример #2
0
        /// <summary>
        /// Prepares a BITS job adding the files and creating the required folders.
        /// </summary>
        /// <param name="backgroundCopyJob">The BITS job information.</param>
        /// <param name="task">The DownloadTask instace.</param>
        private static void PrepareJob(IBackgroundCopyJob backgroundCopyJob, DownloadTask task)
        {
            Guid jobID;

            backgroundCopyJob.GetId(out jobID);
            task.JobId = jobID;

            DownloadFile sourceFile = task.DownloadItem.File;
            string       src        = sourceFile.Source;

            //  to defend against config errors, check to see if the path given is UNC;
            //  if so, throw immediately there's a misconfiguration.  Paths to BITS must be HTTP or HTTPS
            if (FileHelper.IsUncPath(src))
            {
                Exception ex = new DownloaderException("Download location must be HTTP or HTTPS URL");
                Logger.Error(ex);
                throw ex;
            }

            //TODO: how about duplicate filenames?
            string dest = Path.Combine(task.DownloadFilesBase, sourceFile.LocalName);

            if (!Directory.Exists(Path.GetDirectoryName(dest)))
            {
                Directory.CreateDirectory(Path.GetDirectoryName(dest));
            }

            //  add this file to the job
            backgroundCopyJob.AddFile(src, dest);
        }
Пример #3
0
        /// <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;
        }
Пример #4
0
        /// <summary>Called when an error occurs.</summary>
        /// <param name="copyJob">Contains job-related information, such as the number of bytes and files transferred before the error occurred. It also contains the methods to resume and cancel the job. Do not release pJob; BITS releases the interface when the JobError method returns.</param>
        /// <param name="error">Contains error information, such as the file being processed at the time the fatal error occurred and a description of the error. Do not release pError; BITS releases the interface when the JobError method returns.</param>
        public void JobError(IBackgroundCopyJob copyJob, IBackgroundCopyError error)
        {
            if (this.manager == null)
            {
                return;
            }

            BitsJob job;

            if (null == this.errorOccurred)
            {
                return;
            }

            Guid guid;

            copyJob.GetId(out guid);
            if (this.manager.Jobs.ContainsKey(guid))
            {
                job = this.manager.Jobs[guid];
            }
            else
            {
                // Update Job list to check whether the job still exists. If not, just return
                this.manager.EnumJobs(this.manager.CurrentOwner);
                if (this.manager.Jobs.ContainsKey(guid))
                {
                    job = this.manager.Jobs[guid];
                }
                else
                {
                    return;
                }
            }

            this.errorOccurred(this, new ErrorNotificationEventArgs(job, new BitsError(job, error)));

            // forward event
            if (job.NotificationTarget == null)
            {
            }
            else
            {
                try
                {
                    job.NotificationTarget.JobError(copyJob, error);
                }
                catch (COMException)
                {
                }
            }
        }
Пример #5
0
        /// <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;
                }
            }
        }
Пример #6
0
        /// <summary>
        /// Locate the DownloadTask associated with the given background job.
        /// </summary>
        /// <param name="pJob">The job reference.</param>
        /// <returns>The DownloadTask for that job.</returns>
        private static DownloadTask FindTask(IBackgroundCopyJob pJob)
        {
            Guid jobID;

            pJob.GetId(out jobID);

            foreach (var task in BackgroundDownloadManager.GetTasks())
            {
                if (task.JobId == jobID)
                {
                    return(task);
                }
            }

            return(null);
        }
Пример #7
0
        public void JobModification(IBackgroundCopyJob pJob, uint dwReserved)
        {
            BitsJob job;

            if (null != this.onJobModified)
            {
                Guid guid;
                pJob.GetId(out guid);
                if (manager.Jobs.ContainsKey(guid))
                {
                    job = manager.Jobs[guid];
                }
                else
                {
                    job = new BitsJob(manager, pJob);
                }
                this.onJobModified(this, new NotificationEventArgs(job));
            }
        }
Пример #8
0
        public void JobError(IBackgroundCopyJob pJob, IBackgroundCopyError pError)
        {
            BitsJob job;

            if (null != this.onJobErrored)
            {
                Guid guid;
                pJob.GetId(out guid);
                if (manager.Jobs.ContainsKey(guid))
                {
                    job = manager.Jobs[guid];
                }
                else
                {
                    job = new BitsJob(manager, pJob);
                }
                this.onJobErrored(this, new ErrorNotificationEventArgs(job, new BitsError(job, pError)));
            }
        }
        /// <summary>
        /// Gets all the jobs currently being managed with the system.
        /// </summary>
        public IEnumerable <IDownloadJob> GetAll()
        {
            var jobs = new List <DownloadJob> ();
            IBackgroundCopyManager  bitsManager = null;
            IEnumBackgroundCopyJobs enumJobs    = null;

            try {
                bitsManager = (IBackgroundCopyManager) new BackgroundCopyManager();
                bitsManager.EnumJobs(0, out enumJobs);

                uint fetched;
                IBackgroundCopyJob bitsJob = null;
                try {
                    enumJobs.Next(1, out bitsJob, out fetched);
                    while (fetched == 1)
                    {
                        Guid id;
                        bitsJob.GetId(out id);
                        jobs.Add(new DownloadJob(id, bitsJob));

                        enumJobs.Next(1, out bitsJob, out fetched);
                    }
                } finally {
                    if (bitsJob != null)
                    {
                        Marshal.ReleaseComObject(bitsJob);
                    }
                }

                return(jobs.ToArray());
            } finally {
                if (enumJobs != null)
                {
                    Marshal.ReleaseComObject(enumJobs);
                }
                if (bitsManager != null)
                {
                    Marshal.ReleaseComObject(bitsManager);
                }
            }
        }
Пример #10
0
 public void JobModification(IBackgroundCopyJob pJob, uint dwReserved)
 {
     BitsJob job;
     if (null != this.onJobModified)
     {
         Guid guid;
         pJob.GetId(out guid);
         if (manager.Jobs.ContainsKey(guid))
         {
             job = manager.Jobs[guid];
         }
         else
         {
             // Update Joblist to check whether the job still exists. If not, just return
             manager.EnumJobs(manager.currentOwner);
             if (manager.Jobs.ContainsKey(guid))
             {
                 job = manager.Jobs[guid];
             }
             else
                 return;
         }
         this.onJobModified(this, new NotificationEventArgs(job));
         //forward event
         if (job.notificationTarget != null)
             job.notificationTarget.JobModification(pJob, dwReserved);
     }
 }
Пример #11
0
        /// <summary>
        /// used by externally visible overload.
        /// </summary>
        /// <param name="isDisposing">whether or not to clean up managed + unmanaged/large (true) or just unmanaged(false)</param>
        private void Dispose(bool isDisposing)
        {
            const uint BG_JOB_ENUM_CURRENT_USER = 0;
            // const uint BG_JOB_ENUM_ALL_USERS = 0x0001; leads to ACCESS DENIED errors

            IBackgroundCopyManager  mgr  = null;
            IEnumBackgroundCopyJobs jobs = null;
            IBackgroundCopyJob      job  = null;

            if (isDisposing)
            {
                try
                {
                    mgr = (IBackgroundCopyManager)(new BackgroundCopyManager());

                    mgr.EnumJobs(BG_JOB_ENUM_CURRENT_USER, out jobs);

                    uint numJobs;
                    jobs.GetCount(out numJobs);

                    //  lock the jobs collection for duration of this operation
                    lock (bitsDownloaderJobs.SyncRoot)
                    {
                        for (int i = 0; i < numJobs; i++)
                        {
                            //  use jobs interface to walk through getting each job
                            uint fetched;
                            jobs.Next(1, out job, out fetched);

                            //  get jobid guid
                            Guid jobID;
                            job.GetId(out jobID);

                            //  check if the job is in OUR collection; if so cancel it.  we obviously don't want to get
                            //  jobs from other Updater threads/processes, or other BITS jobs on the machine!
                            if (bitsDownloaderJobs.Contains(jobID))
                            {
                                //  take ownership just in case, and cancel() it
                                job.TakeOwnership();
                                job.Cancel();
                                // remove from our collection
                                bitsDownloaderJobs.Remove(jobID);
                            }
                        }
                    }
                }
                finally
                {
                    if (null != mgr)
                    {
                        Marshal.ReleaseComObject(mgr);
                        mgr = null;
                    }
                    if (null != jobs)
                    {
                        Marshal.ReleaseComObject(jobs);
                        jobs = null;
                    }
                    if (null != job)
                    {
                        Marshal.ReleaseComObject(job);
                        job = null;
                    }
                }
            }
        }
Пример #12
0
        /// <summary>
        /// Waits for the download to complete, for the synchronous usage of the downloader.
        /// </summary>
        /// <param name="backgroundCopyJob">The job instance reference.</param>
        /// <param name="maxWaitTime">The maximum wait time.</param>
        /// <param name="task">The updater task instance.</param>
        private void WaitForDownload(DownloadTask task, IBackgroundCopyJob backgroundCopyJob, TimeSpan maxWaitTime)
        {
            bool isCompleted  = false;
            bool isSuccessful = false;

            try
            {
                Guid jobID;
                backgroundCopyJob.GetId(out jobID);

                //  set endtime to current tickcount + allowable # milliseconds to wait for job
                double endTime = Environment.TickCount + maxWaitTime.TotalMilliseconds;

                while (!isCompleted)
                {
                    BG_JOB_STATE state;
                    backgroundCopyJob.GetState(out state);
                    switch (state)
                    {
                    case BG_JOB_STATE.BG_JOB_STATE_SUSPENDED:
                    {
                        OnDownloadStarted(new TaskEventArgs(task));
                        backgroundCopyJob.Resume();
                        break;
                    }

                    case BG_JOB_STATE.BG_JOB_STATE_ERROR:
                    {
                        //  use utility to:
                        //  a)  get error info
                        //  b)  report it
                        //  c)  cancel and remove copy job
                        OnJobError(task, backgroundCopyJob, null, null);

                        //  complete loop, but DON'T say it's successful
                        isCompleted = true;
                        break;
                    }

                    case BG_JOB_STATE.BG_JOB_STATE_TRANSIENT_ERROR:
                    {
                        //  NOTE:  during debugging + test, transient errors resulted in complete job failure about 90%
                        //  of the time.  Therefore we treat transients just like full errors, and CANCEL the job
                        //  use utility to manage error etc.
                        OnJobError(task, backgroundCopyJob, null, null);

                        //  stop the loop, set completed to true but not successful
                        isCompleted = true;
                        break;
                    }

                    case BG_JOB_STATE.BG_JOB_STATE_TRANSFERRING:
                    {
                        OnJobModification(task, backgroundCopyJob);
                        break;
                    }

                    case BG_JOB_STATE.BG_JOB_STATE_TRANSFERRED:
                    {
                        OnJobTransferred(task, backgroundCopyJob);

                        isCompleted  = true;
                        isSuccessful = true;
                        break;
                    }

                    default:
                        break;
                    }

                    if (isCompleted)
                    {
                        break;
                    }

                    if (endTime < Environment.TickCount)
                    {
                        var ex = new DownloaderException("Download attempt timed out");
                        OnJobError(task, backgroundCopyJob, null, ex);
                        break;
                    }

                    //  Avoid 100% CPU utilisation with too tight a loop, let download happen.
                    Thread.Sleep(TimeToWaitDuringSynchronousDownload);
                }

                if (!isSuccessful)
                {
                    //  create message + error, package it, publish
                    var ex =
                        new DownloaderException(String.Format("Download attempt for {0} failed",
                                                              task.DownloadItem.ItemId));
                    OnJobError(task, backgroundCopyJob, null, ex);
                }
            }
            catch (ThreadInterruptedException tie)
            {
                //  if interrupted, clean up job
                OnJobError(task, backgroundCopyJob, null, tie);
            }
        }
Пример #13
0
        /// <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;
                }
            }
        }