Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

handling cancellation during ApplyImage #34

Open
PCAssistSoftware opened this issue Dec 3, 2018 · 8 comments
Open

handling cancellation during ApplyImage #34

PCAssistSoftware opened this issue Dec 3, 2018 · 8 comments

Comments

@PCAssistSoftware
Copy link

hi

When creating an image I can handle cancel button and abort the process

But for ApplyImage I cannot get it to work, and even if I click Stop Debugging in Visual Studio it freezes up the system until I reboot or disconnect drive I am writing too

@jeffkl
Copy link
Owner

jeffkl commented Dec 3, 2018

You'll need your progress callback to return WimMessageResult.Abort like this unit test. Depending on your application, you'll need to implement IDisposable which should get called when your process is killed.

@PCAssistSoftware
Copy link
Author

Hi Jeff
I have spent hours today using that exact unit test as an example and I just can't get it to work - had no problems with handling it for capture, it seems apply is different?

@PCAssistSoftware
Copy link
Author

Okay, using example you posted here = https://github.com/jeffkl/ManagedWimgApi/wiki/Message-Callbacks

I did the same as I did for capture and added

case WimMessageType.QueryAbort
      Return WimMessageResult.Abort

but unlike for "capture" - it seems QueryAbort never gets called for "apply"

@PCAssistSoftware
Copy link
Author

so instead I tried it under case WinMessageType.Process just as a test and at least here it does then Return WimMessageResult.Abort

I then catch the "OperationCanceledException" which now fires - but even using your example it doesn't stop the "applying" of the image, it just locks up the whole interface and Visual Studio gives following error if I click stop debugging

System.ComponentModel.Win32Exception: 'The process cannot access the file because it is being used by another process'

System.ComponentModel.Win32Exception
HResult=0x80004005
Message=The process cannot access the file because it is being used by another process
Source=Microsoft.Wim
StackTrace:
at Microsoft.Wim.WimHandle.ReleaseHandle()
at System.Runtime.InteropServices.SafeHandle.InternalFinalize()
at System.Runtime.InteropServices.SafeHandle.Finalize()

nothing will then bring system back to life unless I unplug drive I am writing too, or wait for it to finish the "apply"

@jeffkl
Copy link
Owner

jeffkl commented Dec 4, 2018

I wrote a simple console application with cancellation and it appears to work with my simple test image. Debugging in Visual Studio worked if I stopped it as well.

using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Wim;

namespace ConsoleApplication
{
    internal  static class Program
    {
        private static readonly CancellationTokenSource CancellationTokenSource = new CancellationTokenSource();

        public static int Main(string[] args)
        {
            Console.CancelKeyPress += (sender, eventArgs) =>
            {
                Console.WriteLine("Cancelling...");
                CancellationTokenSource.Cancel();
                eventArgs.Cancel = true;
            };

            string wimPath = "test.wim";
            string applyPath = Directory.CreateDirectory("wimapply").FullName;

            using (WimHandle wimHandle = WimgApi.CreateFile(wimPath, WimFileAccess.Read, WimCreationDisposition.OpenExisting, WimCreateFileOptions.None, WimCompressionType.None))
            {
                WimgApi.SetTemporaryPath(wimHandle, Path.GetTempPath());

                WimMessageResult MessageCallback(WimMessageType messageType, object message, object userData)
                {
                    if (CancellationTokenSource.IsCancellationRequested)
                    {
                        Console.WriteLine("Aborting...");
                        return WimMessageResult.Abort;
                    }

                    Console.WriteLine("Sleeping...");
                    try
                    {
                        Task.Delay(1000, CancellationTokenSource.Token).Wait();
                    }
                    catch (TaskCanceledException)
                    {
                    }

                    return WimMessageResult.Done;
                }

                WimgApi.RegisterMessageCallback(wimHandle, MessageCallback);

                try
                {
                    using (WimHandle imageHandle = WimgApi.LoadImage(wimHandle, 1))
                    {
                        WimHandle imageHandleCopy = imageHandle;

                        try
                        {
                            Console.WriteLine("Applying...");
                            WimgApi.ApplyImage(imageHandleCopy, applyPath, WimApplyImageOptions.DisableDirectoryAcl | WimApplyImageOptions.DisableFileAcl | WimApplyImageOptions.Index);
                            Console.WriteLine("Applied");
                        }
                        catch (OperationCanceledException)
                        {
                            Console.WriteLine("Cancelled");
                            return 1;
                        }
                    }
                }
                finally
                {
                    WimgApi.UnregisterMessageCallback(wimHandle, MessageCallback);
                }

                return 0;
            }
        }
    }
}

Result

D:\ManagedWimgApi\src\ConsoleApplication\bin\Debug> ConsoleApplication.exe
Applying...
Sleeping...
Sleeping...
Cancelling...
Aborting...
Cancelled

If a particular file is very large I don't think the message callback would be called until later.

@PCAssistSoftware
Copy link
Author

Hi Jeff

Thank you very much for the example which helped me prove that my interpretation of how to do it was correct

It turns out the problem is not the cancellation aspect, it is to do with destinations

In your example the destination is a folder on an internal hard drive I assume

Whereas during testing I was writing to a drive connected via USB

If I run your code it works fine as is, but if I change destination to be a external USB drive then I get same problem as reported

@PCAssistSoftware
Copy link
Author

Can confirm from much more testing that problem is when writing (applying) to external USB devices, as even when you cancel API it still locks the drive causing app to hang in debugger or also explorer to hang as well - will find way of prompting or ejecting USB device to prevent this in future - problem doesn't occur when writing to internal drives

@jeffkl
Copy link
Owner

jeffkl commented Dec 18, 2018

I'll try to find some time to test it out and see if there's anything I can get to work in regards to cancellation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants