Browse Source

Bug 1532: Allow canceling file transfer in .NET assembly

https://winscp.net/tracker/1532

Source commit: 8a404c04df8fef7a168b94d17e9e982b533a4b7b
Martin Prikryl 8 years ago
parent
commit
6805e5a631

+ 1 - 0
dotnet/FileTransferProgressEventArgs.cs

@@ -17,6 +17,7 @@ namespace WinSCP
         public double OverallProgress { get; internal set; }
         public double FileProgress { get; internal set; }
         public int CPS { get; internal set; }
+        public bool Cancel { get; set; }
 
         internal FileTransferProgressEventArgs()
         {

+ 5 - 0
dotnet/Session.cs

@@ -1900,6 +1900,11 @@ namespace WinSCP
             if ((_progressHandling >= 0) && WantsProgress)
             {
                 _fileTransferProgress(this, args);
+
+                if (args.Cancel)
+                {
+                    _process.Cancel();
+                }
             }
         }
 

+ 2 - 1
dotnet/internal/ConsoleCommStruct.cs

@@ -77,6 +77,7 @@ namespace WinSCP
         public uint OverallProgress;
         public uint FileProgress;
         public uint CPS;
+        public bool Cancel; // since version 8
     }
 
     [StructLayout(LayoutKind.Sequential)]
@@ -91,7 +92,7 @@ namespace WinSCP
 
     internal class ConsoleCommStruct : IDisposable
     {
-        public const int CurrentVersion = 0x0007;
+        public const int CurrentVersion = 0x0008;
 
         public ConsoleCommStruct(Session session, SafeFileHandle fileMapping)
         {

+ 41 - 25
dotnet/internal/ExeSessionProcess.cs

@@ -448,38 +448,47 @@ namespace WinSCP
                     "File Name [{0}] - Directory [{1}] - Overall Progress [{2}] - File Progress [{3}] - CPS [{4}]",
                     e.FileName, e.Directory, e.OverallProgress, e.FileProgress, e.CPS);
 
-                FileTransferProgressEventArgs args = new FileTransferProgressEventArgs();
-
-                switch (e.Operation)
+                if (!_cancel)
                 {
-                    case ConsoleProgressEventStruct.ProgressOperation.Copy:
-                        args.Operation = ProgressOperation.Transfer;
-                        break;
+                    FileTransferProgressEventArgs args = new FileTransferProgressEventArgs();
 
-                    default:
-                        throw _logger.WriteException(new ArgumentOutOfRangeException("Unknown progress operation", (Exception)null));
-                }
+                    switch (e.Operation)
+                    {
+                        case ConsoleProgressEventStruct.ProgressOperation.Copy:
+                            args.Operation = ProgressOperation.Transfer;
+                            break;
 
-                switch (e.Side)
-                {
-                    case ConsoleProgressEventStruct.ProgressSide.Local:
-                        args.Side = ProgressSide.Local;
-                        break;
+                        default:
+                            throw _logger.WriteException(new ArgumentOutOfRangeException("Unknown progress operation", (Exception)null));
+                    }
 
-                    case ConsoleProgressEventStruct.ProgressSide.Remote:
-                        args.Side = ProgressSide.Remote;
-                        break;
+                    switch (e.Side)
+                    {
+                        case ConsoleProgressEventStruct.ProgressSide.Local:
+                            args.Side = ProgressSide.Local;
+                            break;
 
-                    default:
-                        throw _logger.WriteException(new ArgumentOutOfRangeException("Unknown progress side", (Exception)null));
+                        case ConsoleProgressEventStruct.ProgressSide.Remote:
+                            args.Side = ProgressSide.Remote;
+                            break;
+
+                        default:
+                            throw _logger.WriteException(new ArgumentOutOfRangeException("Unknown progress side", (Exception)null));
+                    }
+
+                    args.FileName = e.FileName;
+                    args.Directory = e.Directory;
+                    args.OverallProgress = ((double)e.OverallProgress) / 100;
+                    args.FileProgress = ((double)e.FileProgress) / 100;
+                    args.CPS = (int)e.CPS;
+                    args.Cancel = false;
+                    _session.ProcessProgress(args);
                 }
 
-                args.FileName = e.FileName;
-                args.Directory = e.Directory;
-                args.OverallProgress = ((double)e.OverallProgress) / 100;
-                args.FileProgress = ((double)e.FileProgress) / 100;
-                args.CPS = (int)e.CPS;
-                _session.ProcessProgress(args);
+                if (_cancel)
+                {
+                    e.Cancel = true;
+                }
             }
         }
 
@@ -685,6 +694,7 @@ namespace WinSCP
         {
             using (_logger.CreateCallstack())
             {
+                _cancel = false;
                 AddInput(command, log);
             }
         }
@@ -939,6 +949,11 @@ namespace WinSCP
             _logger.WriteLine("{0} - exists [{1}]", executablePath, File.Exists(executablePath));
         }
 
+        public void Cancel()
+        {
+            _cancel = true;
+        }
+
         private const int MaxAttempts = 10;
         private const string ConsoleMapping = "WinSCPConsoleMapping";
         private const string ConsoleEventRequest = "WinSCPConsoleEventRequest";
@@ -964,5 +979,6 @@ namespace WinSCP
         private readonly List<string> _log = new List<string>();
         private AutoResetEvent _inputEvent = new AutoResetEvent(false);
         private Job _job;
+        private bool _cancel;
     }
 }

+ 3 - 2
source/console/Console.h

@@ -12,8 +12,8 @@ struct TConsoleCommStruct
 {
   enum TVersion
   {
-    CurrentVersion =          0x0007,
-    CurrentVersionConfirmed = 0x0107
+    CurrentVersion =          0x0008,
+    CurrentVersionConfirmed = 0x0108
   };
 
   struct TInitEvent
@@ -64,6 +64,7 @@ struct TConsoleCommStruct
     unsigned int OverallProgress;
     unsigned int FileProgress;
     unsigned int CPS;
+    bool Cancel; // since version 8
   };
 
   size_t Size;

+ 6 - 0
source/core/Script.cpp

@@ -2244,7 +2244,13 @@ void __fastcall TManagementScript::TerminalOperationProgress(
         Progress.OverallProgress = ProgressData.OverallProgress();
         Progress.FileProgress = ProgressData.TransferProgress();
         Progress.CPS = ProgressData.CPS();
+        Progress.Cancel = false;
         OnProgress(this, Progress);
+
+        if (Progress.Cancel)
+        {
+          ProgressData.SetCancel(csCancel);
+        }
       }
 
       if (!DoPrint && ((FLastProgressTime != Time) || ProgressData.IsTransferDone()))

+ 2 - 1
source/core/Script.h

@@ -23,13 +23,14 @@ public:
   unsigned int OverallProgress;
   unsigned int FileProgress;
   unsigned int CPS;
+  bool Cancel;
 };
 //---------------------------------------------------------------------------
 typedef void __fastcall (__closure *TScriptPrintEvent)(TScript * Script, const UnicodeString Str, bool Error);
 typedef void __fastcall (__closure *TScriptSynchronizeStartStop)(TScript * Script,
   const UnicodeString LocalDirectory, const UnicodeString RemoteDirectory,
   const TCopyParamType & CopyParam, int SynchronizeParams);
-typedef void __fastcall (__closure *TScriptProgressEvent)(TScript * Script, const TScriptProgress & Progress);
+typedef void __fastcall (__closure *TScriptProgressEvent)(TScript * Script, TScriptProgress & Progress);
 //---------------------------------------------------------------------------
 class TScriptProcParams : public TOptions
 {

+ 23 - 14
source/windows/ConsoleRunner.cpp

@@ -55,7 +55,7 @@ public:
   virtual void __fastcall WaitBeforeExit() = 0;
   virtual bool __fastcall CommandLineOnly() = 0;
   virtual bool __fastcall WantsProgress() = 0;
-  virtual void __fastcall Progress(const TScriptProgress & Progress) = 0;
+  virtual void __fastcall Progress(TScriptProgress & Progress) = 0;
   virtual UnicodeString __fastcall FinalLogMessage() = 0;
 };
 //---------------------------------------------------------------------------
@@ -76,7 +76,7 @@ public:
   virtual void __fastcall WaitBeforeExit();
   virtual bool __fastcall CommandLineOnly();
   virtual bool __fastcall WantsProgress();
-  virtual void __fastcall Progress(const TScriptProgress & Progress);
+  virtual void __fastcall Progress(TScriptProgress & Progress);
   virtual UnicodeString __fastcall FinalLogMessage();
 
 protected:
@@ -519,7 +519,7 @@ bool __fastcall TOwnConsole::WantsProgress()
   return false;
 }
 //---------------------------------------------------------------------------
-void __fastcall TOwnConsole::Progress(const TScriptProgress & /*Progress*/)
+void __fastcall TOwnConsole::Progress(TScriptProgress & /*Progress*/)
 {
   DebugFail();
 }
@@ -547,7 +547,7 @@ public:
   virtual void __fastcall WaitBeforeExit();
   virtual bool __fastcall CommandLineOnly();
   virtual bool __fastcall WantsProgress();
-  virtual void __fastcall Progress(const TScriptProgress & Progress);
+  virtual void __fastcall Progress(TScriptProgress & Progress);
   virtual UnicodeString __fastcall FinalLogMessage();
 
 private:
@@ -875,16 +875,17 @@ bool __fastcall TExternalConsole::WantsProgress()
   return FWantsProgress;
 }
 //---------------------------------------------------------------------------
-void __fastcall TExternalConsole::Progress(const TScriptProgress & Progress)
+void __fastcall TExternalConsole::Progress(TScriptProgress & Progress)
 {
   TConsoleCommStruct * CommStruct = GetCommStruct();
+
+  typedef TConsoleCommStruct::TProgressEvent TProgressEvent;
+  TProgressEvent & ProgressEvent = CommStruct->ProgressEvent;
+
   try
   {
     CommStruct->Event = TConsoleCommStruct::PROGRESS;
 
-    typedef TConsoleCommStruct::TProgressEvent TProgressEvent;
-    TProgressEvent & ProgressEvent = CommStruct->ProgressEvent;
-
     switch (Progress.Operation)
     {
       case foCopy:
@@ -919,6 +920,7 @@ void __fastcall TExternalConsole::Progress(const TScriptProgress & Progress)
     ProgressEvent.OverallProgress = Progress.OverallProgress;
     ProgressEvent.FileProgress = Progress.FileProgress;
     ProgressEvent.CPS = Progress.CPS;
+    ProgressEvent.Cancel = Progress.Cancel;
   }
   __finally
   {
@@ -926,8 +928,15 @@ void __fastcall TExternalConsole::Progress(const TScriptProgress & Progress)
   }
   SendEvent(INFINITE);
 
-  // nothing to read from response, just wait for it
-  FreeCommStruct(GetCommStruct());
+  CommStruct = GetCommStruct();
+  try
+  {
+    Progress.Cancel = ProgressEvent.Cancel;
+  }
+  __finally
+  {
+    FreeCommStruct(CommStruct);
+  }
 }
 //---------------------------------------------------------------------------
 class TNullConsole : public TConsole
@@ -948,7 +957,7 @@ public:
   virtual bool __fastcall CommandLineOnly();
 
   virtual bool __fastcall WantsProgress();
-  virtual void __fastcall Progress(const TScriptProgress & Progress);
+  virtual void __fastcall Progress(TScriptProgress & Progress);
   virtual UnicodeString __fastcall FinalLogMessage();
 };
 //---------------------------------------------------------------------------
@@ -1027,7 +1036,7 @@ bool __fastcall TNullConsole::WantsProgress()
   return false;
 }
 //---------------------------------------------------------------------------
-void __fastcall TNullConsole::Progress(const TScriptProgress & /*Progress*/)
+void __fastcall TNullConsole::Progress(TScriptProgress & /*Progress*/)
 {
   DebugFail();
 }
@@ -1105,7 +1114,7 @@ private:
   void __fastcall TimerTimer(TObject * Sender);
   UnicodeString ExpandCommand(UnicodeString Command, TStrings * ScriptParameters);
   void __fastcall Failed(bool & AnyError);
-  void __fastcall ScriptProgress(TScript * Script, const TScriptProgress & Progress);
+  void __fastcall ScriptProgress(TScript * Script, TScriptProgress & Progress);
   void __fastcall ConfigurationChange(TObject * Sender);
 };
 //---------------------------------------------------------------------------
@@ -1700,7 +1709,7 @@ void __fastcall TConsoleRunner::ScriptSynchronizeStartStop(TScript * /*Script*/,
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall TConsoleRunner::ScriptProgress(TScript * /*Script*/, const TScriptProgress & Progress)
+void __fastcall TConsoleRunner::ScriptProgress(TScript * /*Script*/, TScriptProgress & Progress)
 {
   FConsole->Progress(Progress);
 }