void IBackgroundCopyCallback.JobError(IBackgroundCopyJob bitsJob, IBackgroundCopyError error)
        {
            try {
                // if the error hasn't been reported, try to get it
                if (error == null)
                {
                    bitsJob.GetError(out error);
                }
            } catch (COMException) { }

            // If we've got the native error, extract values and populate the
            // status message.
            if (error != null)
            {
                StatusMessage = FormatError(error);
            }

            BG_JOB_STATE state;

            bitsJob.GetState(out state);
            if (state != BG_JOB_STATE.BG_JOB_STATE_ACKNOWLEDGED &&
                state != BG_JOB_STATE.BG_JOB_STATE_CANCELLED)
            {
                bitsJob.Cancel();
            }

            Status = DownloadStatus.Error;
        }
Exemple #2
0
        /// <summary>
        /// Verifies if the task has a download job assigned, meaning this is a retry.
        /// If a transferred job is detected, the job is completed and the event
        /// OnDownloadCompleted is raised.
        /// </summary>
        /// <param name="copyManager">The BITS background copy manager to use</param>
        /// <param name="task">The DownloadTask to get the data from</param>
        /// <param name="copyJob">If an in progress BITS job is found for this task, this job is returned on this parameter</param>
        /// <returns>A Boolean value indicating whether the job is completed or not.
        /// A True value means that the job has been completed by BITS while a False value
        /// means that the job doesn't exists or can be resumed.
        /// </returns>
        private bool CheckForResumeAndProceed(IBackgroundCopyManager copyManager, DownloadTask task,
                                              out IBackgroundCopyJob copyJob)
        {
            copyJob = null;
            if (task.JobId != null && task.DownloadErrorResumeCount < BackgroundDownloadManager.MaxDownloadErrorResumes)
            {
                Guid jobId = task.JobId.Value;

                try
                {
                    copyManager.GetJob(ref jobId, out copyJob);
                    if (copyJob != null)
                    {
                        BG_JOB_STATE jobState;
                        copyJob.GetState(out jobState);
                        if (jobState == BG_JOB_STATE.BG_JOB_STATE_TRANSFERRED)
                        {
                            OnJobTransferred(task, copyJob);
                            return(true);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Logger.Error(
                        new DownloaderException(
                            String.Format(
                                "The BITSDownloader cannot connect to the job '{0}' for the task '{1}' so a new BITS job will be created.",
                                jobId, task.TaskId), ex));
                }
            }
            return(false);
        }
Exemple #3
0
        internal static BackgroundCopyJobState GetState(IBackgroundCopyJob ijob)
        {
            BackgroundCopyJobState o;

            ijob.GetState(out o);
            return(o);
        }
        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);
                }
            }
        }
Exemple #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="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;
        }
        void IBackgroundCopyCallback.JobModification(IBackgroundCopyJob bitsJob, uint reserved)
        {
            _BG_JOB_PROGRESS progress;

            bitsJob.GetProgress(out progress);
            BytesTotal       = progress.BytesTotal;
            BytesTransferred = progress.BytesTransferred;

            BG_JOB_STATE state;

            bitsJob.GetState(out state);
            Status = (DownloadStatus)(int)state;
        }
Exemple #7
0
        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);
        }
Exemple #8
0
        /// <summary>
        /// 检查/启动/结束传输作业进程,参数文件节点为空的取当前文件节点
        /// </summary>
        /// <param name="nodeFile">要管理的传输文件节点</param>
        static private void HandleBits(Object o)
        {
            IBackgroundCopyManager bcm = null;
            IBackgroundCopyJob     job = null;
            XmlNode nodeFile           = null;

            nodeFile = BitsFileList.GetCurrentFile();
            if (null == nodeFile)
            {
                return;
            }
            ((XmlElement)nodeFile).SetAttribute("state", "doing");
            try
            {
                // Create BITS object
                bcm = (IBackgroundCopyManager) new BackgroundCopyManager();
                Guid jobID = Guid.Empty;
                if (null != nodeFile.Attributes["jobguid"] && !string.IsNullOrEmpty(nodeFile.Attributes["jobguid"].Value))
                { // Do we already have a job in place?
                    jobID = new Guid(nodeFile.Attributes["jobguid"].Value);
                    BG_JOB_STATE state;
                    try
                    {
                        bcm.GetJob(ref jobID, out job); // Get the BITS job object
                        job.GetState(out state);        // check its state
                        switch (state)
                        {
                        case BG_JOB_STATE.BG_JOB_STATE_ERROR:     // If it is an error, re-poll
                            job.Complete();
                            nodeFile.Attributes.RemoveNamedItem("jobguid");
                            Marshal.ReleaseComObject(job);
                            job = null;
                            break;

                        case BG_JOB_STATE.BG_JOB_STATE_CANCELLED:
                        case BG_JOB_STATE.BG_JOB_STATE_TRANSFERRED:     // If we got the job
                            job.Complete();                             // then complete it
                            nodeFile.ParentNode.RemoveChild(nodeFile);
                            Marshal.ReleaseComObject(job);
                            Marshal.ReleaseComObject(bcm);
                            return;

                        default:
                            Marshal.ReleaseComObject(bcm);
                            return;
                        }
                    }
                    catch (Exception e)
                    {
                        NameValueCollection errInfo = new NameValueCollection();
                        errInfo["文件类别"]   = nodeFile.Attributes["doctype"].Value;
                        errInfo["远程文件"]   = nodeFile.Attributes["srcurl"].Value;
                        errInfo["作业Guid"] = nodeFile.Attributes["jobguid"].Value;
                        ExceptionManager.Publish(e, errInfo);
                        if (null != (e as UnauthorizedAccessException))
                        {
                            if (job != null)
                            {
                                Marshal.ReleaseComObject(job);
                            }
                            if (bcm != null)
                            {
                                Marshal.ReleaseComObject(bcm);
                            }
                            return;
                        }
                        COMException exCOM = e as COMException;
                        if (null != exCOM && exCOM.ErrorCode == unchecked ((Int32)0x80200001))
                        {
                            nodeFile.Attributes.RemoveNamedItem("jobguid");
                        }
                        else
                        {
                            return;
                        }
                    }
                }

                // Create a bits job to download the next expected update
                if (null != nodeFile && (null == nodeFile.Attributes["jobguid"] || string.IsNullOrEmpty(nodeFile.Attributes["jobguid"].Value)))
                {
                    bcm.CreateJob("下载远程文件",
                                  BG_JOB_TYPE.BG_JOB_TYPE_DOWNLOAD, out jobID, out job);
                    string doctype = nodeFile.Attributes["doctype"].Value;
                    string srcurl  = nodeFile.Attributes["srcurl"].Value;
                    string dest    = nodeFile.Attributes["localname"].Value;

                    job.SetDescription("下载文件位置: " + doctype);
                    job.AddFile(srcurl, dest);
                    job.Resume(); // start the job in action
                    ((XmlElement)nodeFile).SetAttribute("jobguid", jobID.ToString());
                }
                if (bcm != null)
                {
                    Marshal.ReleaseComObject(bcm);
                }
                return;
            }
            catch { }
        }
Exemple #9
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);
            }
        }
Exemple #10
0
        /// <summary>
        /// Synchronous downloading method using BITS
        /// </summary>
        /// <param name="sourceFile">Source file to download</param>
        /// <param name="destFile">Target file on the local system</param>
        /// <param name="maxTimeWait">Maximum time to wait for a download</param>
        void IDownloader.Download(string sourceFile, string destFile, TimeSpan maxTimeWait)
        {
            IBackgroundCopyManager backGroundCopyManager = null;
            IBackgroundCopyJob     backGroundCopyJob     = null;
            Guid         jobID                = Guid.Empty;
            bool         isCompleted          = false;
            bool         isSuccessful         = false;
            string       cumulativeErrMessage = "";
            BG_JOB_STATE state;

            //  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/HTTPS
            ThrowIfSourceIsUNC(sourceFile);

            try
            {
                //  use utility function to create manager, job, get back jobid etc.; uses 'out' semantics
                CreateCopyJob(
                    out backGroundCopyManager,
                    out backGroundCopyJob,
                    ref jobID,
                    "RES_BITSJobName",
                    "RES_BITSDescription");

                // Add the file to the Job List
                backGroundCopyJob.AddFile(sourceFile, destFile);

                // Start the Back Ground Copy Job.
                backGroundCopyJob.Resume();

                //  set endtime to current tickcount + allowable # milliseconds to wait for job
                int endTime = Environment.TickCount + (int)maxTimeWait.TotalMilliseconds;

                #region __While Loop Waits On Single Download__

                while (!isCompleted)
                {
                    backGroundCopyJob.GetState(out state);
                    switch (state)
                    {
                    case BG_JOB_STATE.BG_JOB_STATE_ERROR:
                    {
                        //  use utility to:
                        //  a)  get error info
                        //  b)  report it
                        //  c)  cancel and remove copy job
                        HandleDownloadErrorCancelJob(backGroundCopyJob, ref cumulativeErrMessage);

                        //  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.
                        HandleDownloadErrorCancelJob(backGroundCopyJob, ref cumulativeErrMessage);

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

                    case BG_JOB_STATE.BG_JOB_STATE_TRANSFERRED:
                    {
                        //  notify BITS we're happy, remove from queue and transfer ownership to us:
                        backGroundCopyJob.Complete();
                        //  remove job from our collection, we won't need to Cancel() in our Dispose()
                        RemoveCopyJobEntry(jobID);
                        isCompleted  = true;
                        isSuccessful = true;
                        break;
                    }

                    default:
                        break;
                    }

                    if (endTime < Environment.TickCount)
                    {
                        HandleDownloadErrorCancelJob(backGroundCopyJob, ref cumulativeErrMessage);
                        break;
                    }

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

                #endregion

                if (!isSuccessful)
                {
                    //  create message + error, package it, publish
                    string error = ApplicationUpdateManager.TraceWrite(
                        "[BITSDownloader.Download]",
                        "RES_MESSAGE_ManifestFileNotDownloaded", sourceFile, cumulativeErrMessage);
                    Exception ex = new Exception(error + Environment.NewLine + cumulativeErrMessage);

                    throw ex;
                }
            }
            catch (ThreadInterruptedException tie)
            {
                //  if interrupted, clean up job
                HandleDownloadErrorCancelJob(backGroundCopyJob, ref cumulativeErrMessage);
                ApplicationUpdateManager.TraceWrite(tie, "[BITSDownloader.Download]", "RES_TIEInBITS", sourceFile);
                throw tie;
            }
            catch (Exception e)
            {
                //  if exception, clean up job
                HandleDownloadErrorCancelJob(backGroundCopyJob, ref cumulativeErrMessage);
                //  then log error
                string error = ApplicationUpdateManager.TraceWrite(
                    e,
                    "[BITSDownloader.Download]",
                    "RES_MESSAGE_ManifestFileNotDownloaded", sourceFile, cumulativeErrMessage);
                Exception ex = new Exception(error, e);
                ExceptionManager.Publish(ex);
                //  throw; allow consuming class to figure out what to do
                throw ex;
            }
            finally
            {
                if (null != backGroundCopyJob)
                {
                    Marshal.ReleaseComObject(backGroundCopyJob);
                }
                if (null != backGroundCopyManager)
                {
                    Marshal.ReleaseComObject(backGroundCopyManager);
                }
            }
        }
Exemple #11
0
        /// <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);
                }
            }
        }