public void JobTransferred(BITS.IBackgroundCopyJob pJob) { // 0. SetNotifyCmdLine // 1. complete // 2. HandleDownloadEnded // 3. wait for run event // 4. Run if (installationPackage.InstallationState > InstallationPackage.State.DownloadStart || installationPackage.InstallationState < InstallationPackage.State.Init) { return; } aTimer.Stop(); pJob.Complete(); TimerCalled(); installationPackage.HandleDownloadEnded(); //wait on event from runner if (installationPackage.RunWithBits && installationPackage.onRunWithBits.WaitOne() && installationPackage.runner.BitsEnabled) { // Throwing with E_FAIL error-code so BITS will also execute the command line throw new System.Runtime.InteropServices.COMException("", int.Parse("80004005", NumberStyles.HexNumber)); } }
public void JobModification(BITS.IBackgroundCopyJob pJob, uint dwReserved) { // JobModification has to exist to satisfy the interface. But unless // the call to job.SetNotifyInterface includes the BG_NOTIFY_JOB_MODIFICATION flag, // this method won't be called. //This method can also be used to get progress ... }
public void JobError(BITS.IBackgroundCopyJob pJob, BITS.IBackgroundCopyError pError) { pJob.Cancel(); aTimer.Stop(); pError.GetErrorDescription((uint)CultureInfo.GetCultureInfo("en-US").LCID, out string errdesc); if (errdesc != null) { installationPackage.HandleDownloadError(errdesc); } installationPackage.HandleProgress(installationPackage); }
public void JobError(BITS.IBackgroundCopyJob pJob, BITS.IBackgroundCopyError pError) { #if DEBUG Logger.GetLogger().Info($"JobError event on download file: {_downloadFileName}"); #endif pJob.Cancel(); _aTimer.Stop(); pError.GetErrorDescription((uint)CultureInfo.GetCultureInfo("en-US").LCID, out string errdesc); if (!string.IsNullOrWhiteSpace(errdesc)) { installationPackage.HandleDownloadError(errdesc); } installationPackage.HandleProgress(installationPackage); }
/// <summary> /// Given a job, return the index in the visible job list that matches the job. /// Uses the job guid as the key. /// </summary> /// <param name="job">The IBackgroundCopyJob to look for</param> /// <returns>An index 0..n for a job that's found and -1 if not found</returns> private int GetJobIndex(BITS.IBackgroundCopyJob job) { BITS.GUID searchFor; job.GetId(out searchFor); for (int i = 0; i < _uiJobList.Items.Count; i++) { var control = _uiJobList.Items[i] as JobViewControl; BITS.GUID id; control.Job.GetId(out id); if (searchFor.GuidEquals(id)) { return(i); } } return(-1); }
private void OnOK(object sender, RoutedEventArgs e) { Job = null; // Clear out the old value, if any. DialogResult = true; if (String.IsNullOrEmpty(_uiUrl.Text)) { MessageBox.Show(Properties.Resources.ErrorEmptyRemoteUrl, Properties.Resources.ErrorTitle); return; } if (String.IsNullOrEmpty(_uiFile.Text)) { MessageBox.Show(Properties.Resources.ErrorEmptyLocalFile, Properties.Resources.ErrorTitle); return; } Job = DownloadFile(_uiUrl.Text, _uiFile.Text); }
public JobViewControl(BITS.IBackgroundCopyJob job) { Job = job; InitializeComponent(); // Set the different parts of the UI string displayName; Job.GetDisplayName(out displayName); _uiJobName.Text = displayName; string description; Job.GetDescription(out description); _uiJobDescription.Text = description; UpdateState(); }
/// <summary> /// Demonstrate how to poll for a job to be finished. A job has to be in a /// final state to be finished. /// </summary> /// <param name="job">Input job to wait for completion on.</param> private void Poll(BITS.IBackgroundCopyJob job) { // Poll for the job to be complete in a separate thread. new System.Threading.Thread(() => { try { bool jobIsFinal = false; while (!jobIsFinal) { BITS.BG_JOB_STATE state; job.GetState(out state); switch (state) { case BITS.BG_JOB_STATE.BG_JOB_STATE_ERROR: job.Cancel(); break; case BITS.BG_JOB_STATE.BG_JOB_STATE_TRANSFERRED: job.Complete(); break; case BITS.BG_JOB_STATE.BG_JOB_STATE_CANCELLED: case BITS.BG_JOB_STATE.BG_JOB_STATE_ACKNOWLEDGED: jobIsFinal = true; break; default: Task.Delay(500); // delay a little bit break; } } // Job is in a final state (cancelled or acknowledged) } catch (System.Runtime.InteropServices.COMException ex) { MessageBox.Show( String.Format(Properties.Resources.ErrorBitsException, ex.HResult, ex.Message), Properties.Resources.ErrorTitle ); } } ).Start(); }
private void SetJobProperties(BITS.IBackgroundCopyJob job) { //TODO - BITS_JOB_TRANSFER_POLICY = BITS_JOB_TRANSFER_POLICY_ALWAYS if (job is BITS5.IBackgroundCopyJob5 job5) { var value = new BITS5.BITS_JOB_PROPERTY_VALUE { Enable = 1 }; job5.SetProperty(BITS5.BITS_JOB_PROPERTY_ID.BITS_JOB_PROPERTY_DYNAMIC_CONTENT, value); var value_high_perf = new BITS5.BITS_JOB_PROPERTY_VALUE { Enable = 0 }; job5.SetProperty(BITS5.BITS_JOB_PROPERTY_ID.BITS_JOB_PROPERTY_HIGH_PERFORMANCE, value_high_perf); } job.SetPriority(BITS.BG_JOB_PRIORITY.BG_JOB_PRIORITY_FOREGROUND); job.SetMinimumRetryDelay(RETRY_DELAY_SECONDS); }
private void ListBITSJobFiles(BITS.IBackgroundCopyJob Job) { _uiFileList.Items.Clear(); // Iterate through the jobs BITS.IEnumBackgroundCopyFiles filesEnum; Job.EnumFiles(out filesEnum); uint nfilesFetched = 0; BITS.IBackgroundCopyFile file = null; do { filesEnum.Next(1, out file, ref nfilesFetched); if (nfilesFetched > 0) { var control = new FileDetailViewControl(Job, file); _uiFileList.Items.Add(control); } }while (nfilesFetched > 0); }
public void JobTransferred(BITS.IBackgroundCopyJob pJob) { // 0. SetNotifyCmdLine // 1. complete // 2. HandleDownloadEnded // 3. wait for run event // 4. Run #if DEBUG Logger.GetLogger().Info($"JobTransferred event on download file: {_downloadFileName}"); #endif if (installationPackage.InstallationState > InstallationPackage.State.DownloadStart || installationPackage.InstallationState < InstallationPackage.State.Init) { return; } _aTimer.Stop(); pJob.Complete(); try { DateTime now = DateTime.Now; #if DEBUG Logger.GetLogger().Info($"setting {_downloadFileName} creation/write/access time to {now}"); #endif File.SetCreationTime(_downloadFileName, now); File.SetLastWriteTime(_downloadFileName, now); File.SetLastAccessTime(_downloadFileName, now); } #if DEBUG catch (Exception e) #else catch (Exception) #endif { #if DEBUG Logger.GetLogger().Warning($"unable to set {_downloadFileName} creation/write/access time: {e}"); #endif } TimerCalled(); pJob.GetTimes(out BITS._BG_JOB_TIMES times); DateTime creation = MakeDateTime(times.CreationTime); DateTime completion = MakeDateTime(times.TransferCompletionTime); if ((creation > DateTime.MinValue) && (completion > DateTime.MinValue)) { UpdateDownloadTime((long)(completion - creation).TotalMilliseconds); } installationPackage.HandleDownloadEnded(); //wait on event from runner if (installationPackage.RunWithBits && installationPackage.onRunWithBits.WaitOne() && installationPackage.runner.BitsEnabled) { #if DEBUG Logger.GetLogger().Info($"running file via BITS: {installationPackage.RunFileName}"); #endif // Throwing with E_FAIL error-code so BITS will also execute the command line throw new System.Runtime.InteropServices.COMException("", unchecked ((int)0x80004005)); } }
public void RefreshJobList() { if (_mgr == null) { return; } var currIndex = _uiJobList.SelectedIndex; // Get the iterator. Handle the throw when the user doesn't have permissions. BITS.IEnumBackgroundCopyJobs jobsEnum = null; try { _mgr.EnumJobs(_jobEnumType, out jobsEnum); } catch (System.UnauthorizedAccessException ex) { // The most common error is trying to enumerate all users jobs // when you are not running as admin. Don't keep telling the user // that they are not the admin. if (_jobEnumType == BG_JOB_ENUM_ALL_USERS && (uint)ex.HResult == 0x80070005) // E_ACCESS_DENIED { if (_shouldNotifyUserOnAccessError) { _shouldNotifyUserOnAccessError = false; // Only display this dialog once _uiMenuAllUsers.IsChecked = false; // Checked is clearly not going to work _uiMenuAllUsers.IsEnabled = false; // Don't allow the user to try again _jobEnumType = 0; // Reset to 0. Just setting IsChecked doesn't trigger the callback. MessageBox.Show( Properties.Resources.ErrorInsufficientPrivilegesMessage, Properties.Resources.ErrorInsufficientPrivilegesTitle); } } else { MessageBox.Show(String.Format(Properties.Resources.ErrorMessage, ex.Message), Properties.Resources.ErrorTitle); } } if (jobsEnum == null) { return; } // Set all jobs as not updated at the start. The code will then update // each active job, and later mark the inactive jobs as old. foreach (var item in _uiJobList.Items) { var control = item as JobViewControl; control.Updated = false; } uint jobFetchedCount = 0; do { BITS.IBackgroundCopyJob job = null; jobsEnum.Next(1, out job, ref jobFetchedCount); // Can only pull a single job out at a time if (jobFetchedCount > 0) { var control = new JobViewControl(job); control.Updated = true; int idx = GetJobIndex(job); if (idx >= 0) { _uiJobList.Items[idx] = control; } else { _uiJobList.Items.Add(control); } } }while (jobFetchedCount > 0); foreach (var item in _uiJobList.Items) { var control = item as JobViewControl; if (!control.Updated) { control.MarkAsOld(); if (!control.JobIsFinal) // Once it's final, it will never change { control.UpdateState(); } } } if (_uiJobList.Items.Count > 0) { _uiJobDetails.Visibility = Visibility.Visible; var oldIndex = _uiJobList.SelectedIndex; _uiJobList.SelectedIndex = currIndex >= 0 ? currIndex : 0; if (_uiJobList.SelectedIndex == oldIndex) { // Refresh the currently selected item. It won't auto-refresh // because we didn't change the selection. var control = _uiJobList.SelectedItem as JobViewControl; _uiJobDetails.SetJob(control.Job); } } else { _uiJobDetails.Visibility = Visibility.Hidden; } UpdateMenu(); }
private void commandExec(BITS.IBackgroundCopyJob job, string filename, string args) { var job2 = job as BITS.IBackgroundCopyJob2; // cast to CopyJob2 so cmd execution can occur job2.SetNotifyCmdLine(filename, args); }
/// <summary> /// Sets job properties using settings from the SetJobProperties control /// </summary> /// <param name="job"></param> public void SetJobProperties(BITS.IBackgroundCopyJob job) { _uiJobProperty.SetJobProperties(job); }
public void JobError(BITS.IBackgroundCopyJob pJob, BITS.IBackgroundCopyError pError) { pJob.Cancel(); }
public void JobTransferred(BITS.IBackgroundCopyJob pJob) { pJob.Complete(); }
// Callbacks for when a job is transferred public void JobTransferred(BITS.IBackgroundCopyJob pJob) { Dispatcher.Invoke(() => { RefreshJobList(); }); }
public void JobError(BITS.IBackgroundCopyJob pJob, BITS.IBackgroundCopyError pError) { Dispatcher.Invoke(() => { RefreshJobList(); }); }
public void SetJobProperties(BITS.IBackgroundCopyJob job) { var job2 = (BITS.IBackgroundCopyJob2)job; // Job2 exists on all supported version of Windows. var job5 = job as BITS5.IBackgroundCopyJob5; // Job5 will be null on, e.g., Windows 7 and earlier. var jobHttpOptions = job as BITS4.IBackgroundCopyJobHttpOptions; if (job5 != null) { // Set the job properties. var costs = _jobCosts; if (costs.HasValue) { var value = new BITS5.BITS_JOB_PROPERTY_VALUE(); value.Dword = (UInt32)costs.Value; job5.SetProperty(BITS5.BITS_JOB_PROPERTY_ID.BITS_JOB_PROPERTY_ID_COST_FLAGS, value); } var isDynamic = _jobIsDynamic; if (isDynamic.HasValue) { var value = new BITS5.BITS_JOB_PROPERTY_VALUE(); value.Enable = isDynamic.Value ? 1 : 0; job5.SetProperty(BITS5.BITS_JOB_PROPERTY_ID.BITS_JOB_PROPERTY_DYNAMIC_CONTENT, value); } var isHighPerformance = _jobIsHighPerformance; if (isHighPerformance.HasValue) { var value = new BITS5.BITS_JOB_PROPERTY_VALUE(); value.Enable = isHighPerformance.Value ? 1 : 0; job5.SetProperty(BITS5.BITS_JOB_PROPERTY_ID.BITS_JOB_PROPERTY_HIGH_PERFORMANCE, value); } } if (jobHttpOptions != null) { var text = _uiCustomHeadersAll.Text; if (!String.IsNullOrWhiteSpace(text)) { jobHttpOptions.SetCustomHeaders(text); } } var priority = _jobPriority; if (priority.HasValue) { job.SetPriority(priority.Value); } var authScheme = _authScheme; if (authScheme.HasValue) { var serverCredentials = new BITS.BG_AUTH_CREDENTIALS(); serverCredentials.Scheme = (BITS.BG_AUTH_SCHEME)authScheme.Value; serverCredentials.Target = BITS.BG_AUTH_TARGET.BG_AUTH_TARGET_SERVER; serverCredentials.Credentials.Password = _uiPassword.Text; serverCredentials.Credentials.UserName = _uiUserName.Text; job2.SetCredentials(serverCredentials); } // Some enterprises have a proxy that requires implicit credentials. For // those places, allow the user to add the NEGOTIAGE and NTLM schemes. // NEGOTIATE is newer and is more common. if (_jobIsAuthProxyImplicit.HasValue && _jobIsAuthProxyImplicit.Value) { var proxyCredentials = new BITS.BG_AUTH_CREDENTIALS(); proxyCredentials.Target = BITS.BG_AUTH_TARGET.BG_AUTH_TARGET_PROXY; proxyCredentials.Scheme = BITS.BG_AUTH_SCHEME.BG_AUTH_SCHEME_NEGOTIATE; proxyCredentials.Credentials.Password = null; proxyCredentials.Credentials.UserName = null; job2.SetCredentials(proxyCredentials); // Some enterprises won't have Nego set up; for them, also allow // plain NTLM without the possibility of Kerberos. proxyCredentials.Scheme = BITS.BG_AUTH_SCHEME.BG_AUTH_SCHEME_NTLM; job2.SetCredentials(proxyCredentials); } }
public void JobModification(BITS.IBackgroundCopyJob pJob, uint dwReserved) { Dispatcher.Invoke(() => { RefreshJobList(); }); }
/// <summary> /// Updates the UI with details from the job /// </summary> /// <param name="job">The job must always be non-null</param> public void SetJob(BITS.IBackgroundCopyJob job) { Job = job ?? throw new ArgumentNullException("job"); // Update the details BITS.BG_JOB_STATE currState; Job.GetState(out currState); // time details (Create/Modified/Completed) // The DateTime.ToString("F") makes a date + time string in the user's locale. BITS._BG_JOB_TIMES times; Job.GetTimes(out times); var time = MakeDateTime(times.CreationTime); _uiJobCreationTime.Text = time > DateTime.MinValue ? time.ToString("F") : Properties.Resources.JobTimeNotSet; time = MakeDateTime(times.ModificationTime); _uiJobModificationTime.Text = time > DateTime.MinValue ? time.ToString("F") : Properties.Resources.JobTimeNotSet; time = MakeDateTime(times.TransferCompletionTime); _uiJobTransferCompletionTime.Text = time > DateTime.MinValue ? time.ToString("F") : Properties.Resources.JobTimeNotSet; // Progress details (Bytes/Files) BITS._BG_JOB_PROGRESS progress; Job.GetProgress(out progress); var files = String.Format( Properties.Resources.JobProgressFileCount, progress.FilesTransferred, progress.FilesTotal); var bytes = progress.BytesTotal == ulong.MaxValue ? String.Format( Properties.Resources.JobProgressByteCountUnknown, progress.BytesTransferred) : String.Format( Properties.Resources.JobProgressByteCount, progress.BytesTransferred, progress.BytesTotal); _uiJobProgressFiles.Text = files; _uiJobProgressBytes.Text = bytes; // Error details (HRESULT, Context, Description) uint NError = 0; BITS.IBackgroundCopyError Error; BITS.BG_ERROR_CONTEXT ErrorContext; int ErrorHRESULT; string ErrorContextDescription; string ErrorDescription; int langid = System.Globalization.CultureInfo.CurrentUICulture.LCID; langid = (langid & 0xFFFF); // Equivilent of LANGIDFROMLCID(GetThreadLocale()). BITS takes in the LANGID Job.GetErrorCount(out NError); if (NError == 0) { _uiJobErrorCount.Text = Properties.Resources.JobErrorNoErrors; _uiJobError.Text = ""; } else // (NError > 0) { _uiJobErrorCount.Text = NError.ToString("N0"); // Locale-specific numeric with no decimal places if (currState != BITS.BG_JOB_STATE.BG_JOB_STATE_ERROR && currState != BITS.BG_JOB_STATE.BG_JOB_STATE_TRANSIENT_ERROR) { _uiJobError.Text = Properties.Resources.JobErrorWhenError; } else { try { Job.GetError(out Error); Error.GetError(out ErrorContext, out ErrorHRESULT); Error.GetErrorDescription((uint)langid, out ErrorDescription); Error.GetErrorContextDescription((uint)langid, out ErrorContextDescription); var errorText = String.Format("\t{0} \t0x{1:X08}\n\t{2} \t{3}{4}\t{5} \t{6}", Properties.Resources.JobErrorHRESULT, ErrorHRESULT, Properties.Resources.JobErrorDescription, ErrorDescription, ErrorDescription.EndsWith("\n") ? "" : "\n", Properties.Resources.JobErrorContext, ErrorContextDescription ); _uiJobError.Text = errorText; } catch (System.Runtime.InteropServices.COMException) { _uiJobError.Text = Properties.Resources.JobErrorException; } } } string jobOwner; Job.GetOwner(out jobOwner); // convert the user sid to a domain\name var identifier = new System.Security.Principal.SecurityIdentifier(jobOwner); if (identifier.IsValidTargetType(typeof(System.Security.Principal.NTAccount))) { string account = identifier.Translate(typeof(System.Security.Principal.NTAccount)).ToString(); _uiJobOwner.Text = account; } else { _uiJobOwner.Text = jobOwner; } // Job priority details BITS.BG_JOB_PRIORITY jobPriority; Job.GetPriority(out jobPriority); _uiJobPriority.Text = BitsConversions.ConvertJobPriorityToString(jobPriority); // Job Type details BITS.BG_JOB_TYPE jobType; Job.GetType(out jobType); _uiJobType.Text = BitsConversions.ConvertJobTypeToString(jobType); // Job State details BITS.BG_JOB_STATE jobState; Job.GetState(out jobState); _uiJobState.Text = BitsConversions.ConvertJobStateToString(jobState); // Values from IBackgroundCopyJob5 Property interface // COST_FLAGS, DYNAMIC_CONTENT, HIGH_PERFORMANCE, ON_DEMAND_MODE BITS5.IBackgroundCopyJob5 job5 = job as BITS5.IBackgroundCopyJob5; if (job5 == null) { _uiJobCost.Text = Properties.Resources.JobCostNotAvailable; _uiJobFlags.Text = Properties.Resources.JobFlagsNotAvailable; } else { BITS5.BITS_JOB_PROPERTY_VALUE cost; job5.GetProperty(BITS5.BITS_JOB_PROPERTY_ID.BITS_JOB_PROPERTY_ID_COST_FLAGS, out cost); var costString = BitsConversions.ConvertCostToString((BitsCosts)cost.Dword); _uiJobCost.Text = costString; var flagBuilder = new StringBuilder(); BITS5.BITS_JOB_PROPERTY_VALUE flagValue; job5.GetProperty(BITS5.BITS_JOB_PROPERTY_ID.BITS_JOB_PROPERTY_DYNAMIC_CONTENT, out flagValue); if (flagValue.Enable != 0) { if (flagBuilder.Length > 0) { flagBuilder.Append(", "); } flagBuilder.Append(Properties.Resources.JobFlagsDynamic); } job5.GetProperty(BITS5.BITS_JOB_PROPERTY_ID.BITS_JOB_PROPERTY_HIGH_PERFORMANCE, out flagValue); if (flagValue.Enable != 0) { if (flagBuilder.Length > 0) { flagBuilder.Append(", "); } flagBuilder.Append(Properties.Resources.JobFlagsHighPerformance); } job5.GetProperty(BITS5.BITS_JOB_PROPERTY_ID.BITS_JOB_PROPERTY_ON_DEMAND_MODE, out flagValue); if (flagValue.Enable != 0) { if (flagBuilder.Length > 0) { flagBuilder.Append(", "); } flagBuilder.Append(Properties.Resources.JobFlagsOnDemandMode); } if (flagBuilder.Length == 0) { flagBuilder.Append(Properties.Resources.JobFlagsNoneSet); } _uiJobFlags.Text = flagBuilder.ToString(); } // Get the JobHttpOptions custom method var httpOptions2 = Job as BITS10_2.IBackgroundCopyJobHttpOptions2; if (httpOptions2 == null) { _uiJobHttpMethod.Text = Properties.Resources.JobHttpMethodNotAvailable; } else { string httpMethod; try { httpOptions2.GetHttpMethod(out httpMethod); _uiJobHttpMethod.Text = httpMethod ?? Properties.Resources.JobHttpMethodNotSet; } catch (System.Runtime.InteropServices.COMException ex) { _uiJobHttpMethod.Text = String.Format(Properties.Resources.JobHttpMethodException, ex.Message); } } // Get the HttpJobOptions var httpOptions = Job as BITS4.IBackgroundCopyJobHttpOptions; if (httpOptions == null) { _uiJobCustomHeaders.Text = Properties.Resources.JobCustomHeadersNotAvailable; } else { string customHeaders; try { httpOptions.GetCustomHeaders(out customHeaders); var headers = customHeaders == null ? Properties.Resources.JobCustomHeadersNotSet : TabifyHttpHeaders.AddTabs(TabifyHttpHeaders.PrependCRLF(customHeaders)) ; _uiJobCustomHeaders.Text = headers; } catch (System.Runtime.InteropServices.COMException ex) { _uiJobCustomHeaders.Text = String.Format( Properties.Resources.JobCustomHeadersException, ex.Message); } catch (System.UnauthorizedAccessException ex) { _uiJobCustomHeaders.Text = String.Format( Properties.Resources.JobCustomHeadersException, ex.Message); } } // Update the list of files associated with the job. ListBITSJobFiles(Job); }
public FileDetailViewControl(BITS.IBackgroundCopyJob job, BITS.IBackgroundCopyFile file) { _file = file; InitializeComponent(); // Set the different parts of the UI string localName; file.GetLocalName(out localName); _uiFileLocal.Text = localName; string remoteName; file.GetRemoteName(out remoteName); _uiFileRemote.Text = remoteName; // Add in the current progress BITS._BG_FILE_PROGRESS progress; file.GetProgress(out progress); var bytes = progress.BytesTotal == ulong.MaxValue ? String.Format( Properties.Resources.FileProgressByteCountUnknown, progress.BytesTransferred) : String.Format( Properties.Resources.FileProgressByteCount, progress.BytesTransferred, progress.BytesTotal); _uiFileByteProgress.Text = bytes; // Get the data from the file as a IBackgroundCopyFile5 (available starting in Windows 8) var file5 = file as BITS5.IBackgroundCopyFile5; if (file5 == null) { _uiFileHttpResponseData.Text = Properties.Resources.FileHttpResponseDataNotAvailable; } else { // The bits5_0.idl IDL file was modified to convert the String parameter. // The type was changed to WCHAR* and the resulting value is marshalled as an IntPtr. // The union was also given a name to match the typedef name. // typedef[switch_type(BITS_FILE_PROPERTY_ID)] union BITS_FILE_PROPERTY_VALUE // { // [case(BITS_FILE_PROPERTY_ID_HTTP_RESPONSE_HEADERS )] // WCHAR* String; // } // BITS_FILE_PROPERTY_VALUE; BITS5.BITS_FILE_PROPERTY_VALUE value; file5.GetProperty(BITS5.BITS_FILE_PROPERTY_ID.BITS_FILE_PROPERTY_ID_HTTP_RESPONSE_HEADERS, out value); var str = System.Runtime.InteropServices.Marshal.PtrToStringAuto(value.String); str = TabifyHttpHeaders.AddTabs(str); _uiFileHttpResponseData.Text = str; } // Enable the Open File button only when the file can't be // opened by bits. BITS.BG_JOB_STATE state; job.GetState(out state); switch (state) { case BITS.BG_JOB_STATE.BG_JOB_STATE_TRANSFERRED: case BITS.BG_JOB_STATE.BG_JOB_STATE_ACKNOWLEDGED: case BITS.BG_JOB_STATE.BG_JOB_STATE_CANCELLED: _uiOpenButton.IsEnabled = true; break; } }