mirror of https://github.com/dahall/Vanara.git
183 lines
6.5 KiB
C#
183 lines
6.5 KiB
C#
using System;
|
|
using System.Runtime.InteropServices;
|
|
using System.Security.Principal;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Vanara.PInvoke;
|
|
using static Vanara.PInvoke.BITS;
|
|
|
|
namespace Vanara.IO
|
|
{
|
|
/// <summary>
|
|
/// Use the BackgroundCopyManager to create transfer jobs, retrieve an enumerator object that contains the jobs in the queue, and to retrieve individual jobs
|
|
/// from the queue.
|
|
/// </summary>
|
|
public static partial class BackgroundCopyManager
|
|
{
|
|
private static Version ver;
|
|
|
|
/// <summary>Initializes a new instance of the <see cref="BackgroundCopyManager"/> class.</summary>
|
|
static BackgroundCopyManager()
|
|
{
|
|
IMgr = new IBackgroundCopyManager();
|
|
Jobs = new BackgroundCopyJobCollection();
|
|
}
|
|
|
|
/// <summary>Gets the list of currently queued jobs for all users.</summary>
|
|
public static BackgroundCopyJobCollection Jobs { get; private set; }
|
|
|
|
/// <summary>Retrieves the running version of BITS.</summary>
|
|
public static Version Version
|
|
{
|
|
get
|
|
{
|
|
try { return ver ?? (ver = GetVer()); }
|
|
catch { return new Version(); }
|
|
|
|
Version GetVer()
|
|
{
|
|
var fi = System.Diagnostics.FileVersionInfo.GetVersionInfo(Environment.ExpandEnvironmentVariables(@"%WinDir%\Sysnative\qmgr.dll"));
|
|
switch ($"{fi.FileMajorPart}.{fi.FileMinorPart}")
|
|
{
|
|
case "7.8": return new Version(10, 1);
|
|
case "7.7": return new Version(5, 0);
|
|
case "7.5": return new Version(4, 0);
|
|
case "7.0": return new Version(3, 0);
|
|
case "6.7": return new Version(2, 5);
|
|
case "6.6": return new Version(2, 0);
|
|
case "6.5": return new Version(1, 5);
|
|
case "6.2": return new Version(1, 2);
|
|
default: return new Version(1, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>Copies an existing file to a new file using BITS. Overwriting a file of the same name is not allowed.</summary>
|
|
/// <param name="sourceFileName">The file to copy.</param>
|
|
/// <param name="destFileName">The name of the destination file.</param>
|
|
public static void Copy(string sourceFileName, string destFileName)
|
|
{
|
|
CopyTemplate(sourceFileName, destFileName, () => false, System.Threading.Thread.Sleep, null, f => f.Add(sourceFileName, destFileName));
|
|
}
|
|
|
|
/// <summary>Copies an existing file to a new file using BITS. Overwriting a file of the same name is not allowed.</summary>
|
|
/// <param name="sourceFileName">The file to copy.</param>
|
|
/// <param name="destFileName">The name of the destination file.</param>
|
|
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
|
|
/// <param name="progress">An optional delegate that can be used to track the progress of the operation asynchronously.</param>
|
|
/// <returns>A task that represents the asynchronous copy operation.</returns>
|
|
public static async Task CopyAsync(string sourceFileName, string destFileName, CancellationToken cancellationToken, IProgress<Tuple<BackgroundCopyJobState, byte>> progress)
|
|
{
|
|
#if NET40
|
|
await TaskEx.Run(() => CopyTemplate(sourceFileName, destFileName, () => cancellationToken.IsCancellationRequested,
|
|
Thread.Sleep, (s, p) => progress?.Report(new Tuple<BackgroundCopyJobState, byte>(s,p)), f => f.Add(sourceFileName, destFileName)), cancellationToken);
|
|
#else
|
|
await Task.Run(() => CopyTemplate(sourceFileName, destFileName, () => cancellationToken.IsCancellationRequested,
|
|
Thread.Sleep, (s, p) => progress?.Report(new Tuple<BackgroundCopyJobState, byte>(s, p)), f => f.Add(sourceFileName, destFileName)), cancellationToken);
|
|
#endif
|
|
cancellationToken.ThrowIfCancellationRequested();
|
|
}
|
|
|
|
private static IBackgroundCopyManager IMgr { get; set; }
|
|
|
|
internal static IBackgroundCopyJob CreateJob(string displayName, BG_JOB_TYPE jobType = BG_JOB_TYPE.BG_JOB_TYPE_DOWNLOAD)
|
|
{
|
|
try
|
|
{
|
|
IMgr.CreateJob(displayName, jobType, out var newJobID, out var newJob);
|
|
return newJob;
|
|
}
|
|
catch (COMException cex)
|
|
{
|
|
HandleCOMException(cex);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
internal static IEnumBackgroundCopyJobs EnumJobs(BG_JOB_ENUM type = BG_JOB_ENUM.BG_JOB_ENUM_ALL_USERS) => IMgr.EnumJobs(type);
|
|
|
|
internal static string GetErrorMessage(HRESULT hResult)
|
|
{
|
|
try
|
|
{
|
|
return IMgr.GetErrorDescription(hResult, (uint)((short)System.Globalization.CultureInfo.CurrentCulture.LCID));
|
|
}
|
|
catch (COMException)
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
internal static IBackgroundCopyJob GetJob(Guid jobId)
|
|
{
|
|
try
|
|
{
|
|
return IMgr.GetJob(jobId);
|
|
}
|
|
catch (COMException cex)
|
|
{
|
|
if ((uint)cex.ErrorCode != 0x80200001)
|
|
throw new BackgroundCopyException(cex);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
internal static void HandleCOMException(COMException cex) => throw new BackgroundCopyException(cex);
|
|
|
|
/// <summary>Checks if the current user has administrator rights.</summary>
|
|
internal static bool IsCurrentUserAdministrator()
|
|
{
|
|
var wp = new WindowsPrincipal(WindowsIdentity.GetCurrent());
|
|
return wp.IsInRole(WindowsBuiltInRole.Administrator);
|
|
}
|
|
|
|
private static void CopyTemplate(string sourceFileName, string destFileName, Func<bool> shouldCancel, Action<int> delay, Action<BackgroundCopyJobState, byte> report, Action<BackgroundCopyFileCollection> add)
|
|
{
|
|
var type = (Uri.TryCreate(destFileName, UriKind.Absolute, out var uri) && !uri.IsFile) ? BackgroundCopyJobType.Upload : BackgroundCopyJobType.Download;
|
|
using (var job = Jobs.Add("Temp" + Guid.NewGuid().ToString(), "", type))
|
|
{
|
|
job.DisableNotifications = true;
|
|
add(job.Files);
|
|
BackgroundCopyJobState state = BackgroundCopyJobState.Connecting;
|
|
job.Resume();
|
|
do
|
|
{
|
|
switch (state = job.State)
|
|
{
|
|
case BackgroundCopyJobState.Queued:
|
|
case BackgroundCopyJobState.Connecting:
|
|
case BackgroundCopyJobState.Transferring:
|
|
case BackgroundCopyJobState.Suspended:
|
|
ReportProgress();
|
|
break;
|
|
case BackgroundCopyJobState.Error:
|
|
case BackgroundCopyJobState.TransientError:
|
|
throw job.LastError;
|
|
case BackgroundCopyJobState.Transferred:
|
|
ReportProgress();
|
|
job.Complete();
|
|
return;
|
|
case BackgroundCopyJobState.Acknowledged:
|
|
case BackgroundCopyJobState.Cancelled:
|
|
return;
|
|
default:
|
|
throw new InvalidOperationException("Unknown job state");
|
|
}
|
|
if (shouldCancel())
|
|
{
|
|
job.Cancel();
|
|
break;
|
|
}
|
|
delay(1000);
|
|
|
|
void ReportProgress()
|
|
{
|
|
report?.Invoke(state, job.Progress.PercentComplete);
|
|
}
|
|
|
|
} while (state != BackgroundCopyJobState.Transferred && state != BackgroundCopyJobState.Error && state != BackgroundCopyJobState.TransientError);
|
|
}
|
|
}
|
|
}
|
|
} |