瀏覽代碼

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

Source commit: 3db5f1e4d3a6e85e5c16559935f5273e1e905f6c
Martin Prikryl 3 年之前
父節點
當前提交
4b38960069
共有 5 個文件被更改,包括 94 次插入1 次删除
  1. 5 0
      source/core/Common.cpp
  2. 1 0
      source/core/Common.h
  3. 2 1
      source/core/FileOperationProgress.cpp
  4. 1 0
      source/core/Interface.h
  5. 85 0
      source/windows/GUITools.cpp

+ 5 - 0
source/core/Common.cpp

@@ -3022,6 +3022,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

@@ -142,6 +142,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);

+ 85 - 0
source/windows/GUITools.cpp

@@ -2297,7 +2297,92 @@ 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()
 {
   TPuttyCleanupThread::Finalize();
+
+  TSystemRequiredThread * Thread;
+  {
+    TGuard Guard(SystemRequiredThreadSection.get());
+    Thread = SystemRequiredThread;
+    SystemRequiredThread = NULL;
+  }
+  Thread->Terminate();
+  Thread->WaitFor();
+  delete Thread;
 }