Browse Source

Bug 2083: Workaround for an apparent bug in Windows 11 that prevents WinSCP from stopping Windows going to the sleep mode during transfers

https://winscp.net/tracker/2083
(cherry picked from commit 4b38960069c9e6637bdf519b0a9e452681224c43)

# Conflicts:
#	source/windows/GUITools.cpp

Source commit: fcc260c91f8d3671c66cef13a8843514c39e9773
Martin Prikryl 3 years ago
parent
commit
1592dee8de

+ 2 - 0
source/WinSCP.cpp

@@ -13,6 +13,7 @@ USEFORM("forms\ScpExplorer.cpp", ScpExplorerForm);
 #include <VCLCommon.h>
 #include <Setup.h>
 #include <PuttyTools.h>
+#include <GUITools.h>
 //---------------------------------------------------------------------------
 WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
 {
@@ -53,6 +54,7 @@ WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
     }
     __finally
     {
+      GUIFinalize();
       FinalizeSystemSettings();
       FinalizeWinHelp();
       CoreFinalize();

+ 5 - 0
source/core/Common.cpp

@@ -3021,6 +3021,11 @@ bool __fastcall IsWin10Build(unsigned int BuildNumber)
      (OSVersionInfo.dwBuildNumber >= BuildNumber));
 }
 //---------------------------------------------------------------------------
+bool IsWin11()
+{
+  return IsWin10Build(22000);
+}
+//---------------------------------------------------------------------------
 bool __fastcall IsWine()
 {
   HMODULE NtDll = GetModuleHandle(L"ntdll.dll");

+ 1 - 0
source/core/Common.h

@@ -141,6 +141,7 @@ bool __fastcall IsWin7();
 bool __fastcall IsWin8();
 bool __fastcall IsWin10();
 bool __fastcall IsWin10Build(unsigned int BuildNumber);
+bool IsWin11();
 bool __fastcall IsWine();
 bool __fastcall IsUWP();
 UnicodeString GetPackageName();

+ 2 - 1
source/core/FileOperationProgress.cpp

@@ -5,6 +5,7 @@
 #include "Common.h"
 #include "FileOperationProgress.h"
 #include "CoreMain.h"
+#include "Interface.h"
 //---------------------------------------------------------------------------
 #define TRANSFER_BUF_SIZE 32768
 //---------------------------------------------------------------------------
@@ -310,7 +311,7 @@ void __fastcall TFileOperationProgressType::Progress()
 //---------------------------------------------------------------------------
 void __fastcall TFileOperationProgressType::DoProgress()
 {
-  SetThreadExecutionState(ES_SYSTEM_REQUIRED);
+  SystemRequired();
   FOnProgress(*this);
 }
 //---------------------------------------------------------------------------

+ 1 - 0
source/core/Interface.h

@@ -49,6 +49,7 @@ void __fastcall BusyEnd(void * Token);
 const unsigned int GUIUpdateInterval = 100;
 void __fastcall SetNoGUI();
 bool __fastcall ProcessGUI(bool Force = false);
+void SystemRequired();
 UnicodeString __fastcall AppNameString();
 UnicodeString __fastcall SshVersionString();
 void __fastcall CopyToClipboard(UnicodeString Text);

+ 87 - 0
source/windows/GUITools.cpp

@@ -2144,3 +2144,90 @@ bool CanShowTimeEstimate(TDateTime StartTime)
 {
   return (SecondsBetween(StartTime, Now()) >= 3);
 }
+class TSystemRequiredThread : public TSignalThread
+{
+public:
+  TSystemRequiredThread();
+  void Required();
+protected:
+  virtual bool __fastcall WaitForEvent();
+  virtual void __fastcall ProcessEvent();
+private:
+  bool FRequired;
+  TDateTime FLastRequired;
+};
+//---------------------------------------------------------------------------
+std::unique_ptr<TCriticalSection> SystemRequiredThreadSection(TraceInitPtr(new TCriticalSection()));
+TSystemRequiredThread * SystemRequiredThread = NULL;
+//---------------------------------------------------------------------------
+TSystemRequiredThread::TSystemRequiredThread() :
+  TSignalThread(true), FRequired(false)
+{
+}
+//---------------------------------------------------------------------------
+void TSystemRequiredThread::Required()
+{
+  // guarded in SystemRequired()
+  FLastRequired = Now();
+  TriggerEvent();
+}
+//---------------------------------------------------------------------------
+bool __fastcall TSystemRequiredThread::WaitForEvent()
+{
+  const int ExpireInterval = 5000;
+  bool Result = (TSignalThread::WaitForEvent(ExpireInterval) > 0);
+  if (!Result && !FTerminated)
+  {
+    TGuard Guard(SystemRequiredThreadSection.get());
+    if (!FTerminated && FRequired &&
+        (MilliSecondsBetween(Now(), FLastRequired) > ExpireInterval))
+    {
+      SetThreadExecutionState(ES_CONTINUOUS);
+      FLastRequired = TDateTime();
+      FRequired = false;
+    }
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
+void __fastcall TSystemRequiredThread::ProcessEvent()
+{
+  TGuard Guard(SystemRequiredThreadSection.get());
+  if (!FRequired &&
+      (FLastRequired != TDateTime()))
+  {
+    SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_CONTINUOUS);
+    FRequired = true;
+  }
+}
+//---------------------------------------------------------------------------
+void SystemRequired()
+{
+  if (IsWin11())
+  {
+    TGuard Guard(SystemRequiredThreadSection.get());
+    if (SystemRequiredThread == NULL)
+    {
+      SystemRequiredThread = new TSystemRequiredThread();
+      SystemRequiredThread->Start();
+    }
+    SystemRequiredThread->Required();
+  }
+  else
+  {
+    SetThreadExecutionState(ES_SYSTEM_REQUIRED);
+  }
+}
+//---------------------------------------------------------------------------
+void GUIFinalize()
+{
+  TSystemRequiredThread * Thread;
+  {
+    TGuard Guard(SystemRequiredThreadSection.get());
+    Thread = SystemRequiredThread;
+    SystemRequiredThread = NULL;
+  }
+  Thread->Terminate();
+  Thread->WaitFor();
+  delete Thread;
+}

+ 1 - 0
source/windows/GUITools.h

@@ -10,6 +10,7 @@ class TSessionData;
 //---------------------------------------------------------------------------
 typedef void __fastcall (__closure* TProcessMessagesEvent)();
 //---------------------------------------------------------------------------
+void GUIFinalize();
 bool __fastcall FindFile(UnicodeString & Path);
 bool __fastcall FindTool(const UnicodeString & Name, UnicodeString & Path);
 void __fastcall ExecuteTool(const UnicodeString & Name);