فهرست منبع

Bug 1625: Prevent stall on startup when updating jumplist takes too long

https://winscp.net/tracker/1625

Source commit: b8823cb84ce81d1684a5edcd57aa41a9f64cdb22
Martin Prikryl 7 سال پیش
والد
کامیت
d9a9475a7b
2فایلهای تغییر یافته به همراه45 افزوده شده و 9 حذف شده
  1. 42 1
      source/packages/my/OperationWithTimeout.pas
  2. 3 8
      source/windows/Setup.cpp

+ 42 - 1
source/packages/my/OperationWithTimeout.pas

@@ -3,7 +3,7 @@ unit OperationWithTimeout;
 interface
 
 uses
-  Winapi.Windows, Winapi.ShlObj, Winapi.ShellAPI, ActiveX;
+  Winapi.Windows, Winapi.ShlObj, Winapi.ShellAPI, ActiveX, Winapi.ObjectArray;
 
 function ShellFolderGetAttributesOfWithTimeout(
   ShellFolder: IShellFolder; cidl: UINT; var apidl: PItemIDList; var rgfInOut: UINT; Timeout: Integer): HResult;
@@ -16,6 +16,9 @@ function ShellFolderParseDisplayNameWithTimeout(
   ShellFolder: IShellFolder; hwndOwner: HWND; pbcReserved: Pointer; lpszDisplayName: POLESTR;
   out pchEaten: ULONG; out ppidl: PItemIDList; var dwAttributes: ULONG; Timeout: Integer): HResult;
 
+function DestinationListBeginList(
+  DestinationList: ICustomDestinationList; var pcMaxSlots: UINT; const riid: TIID; out ppv: Pointer; Timeout: Integer): HRESULT;
+
 implementation
 
 uses
@@ -55,6 +58,12 @@ type
     ppidl: PItemIDList;
     dwAttributes: ULONG;
 
+    // DestinationListBeginList uses ResultHResult
+    DestinationList: ICustomDestinationList;
+    pcMaxSlots: UINT;
+    riid: TIID;
+    ppv: Pointer;
+
     constructor Create(AOperationEvent: TOperationEvent);
   end;
 
@@ -322,6 +331,38 @@ begin
   end;
 end;
 
+procedure DestinationListBeginListOperation(Operation: TOperation);
+begin
+  Operation.ResultHResult := Operation.DestinationList.BeginList(Operation.pcMaxSlots, Operation.riid, Operation.ppv);
+end;
+
+function DestinationListBeginList(
+  DestinationList: ICustomDestinationList; var pcMaxSlots: UINT; const riid: TIID; out ppv: Pointer; Timeout: Integer): HRESULT;
+var
+  Operation: TOperation;
+begin
+  NeedThread;
+  Operation := TOperation.Create(DestinationListBeginListOperation);
+  Operation.DestinationList := DestinationList;
+  Operation.pcMaxSlots := pcMaxSlots;
+  Operation.riid := riid;
+  Operation.ppv := ppv;
+  Thread.Queue(Operation);
+  if WaitForOperation(Timeout) then
+  begin
+    pcMaxSlots := Operation.pcMaxSlots;
+    ppv := Operation.ppv;
+    Result := Operation.ResultHResult;
+    Thread.Remove(Operation);
+  end
+    else
+  begin
+    ppv := nil;
+    Result := E_FAIL;
+  end;
+end;
+
+
 initialization
 
 finalization

+ 3 - 8
source/windows/Setup.cpp

@@ -30,6 +30,7 @@
 #include <VCLCommon.h>
 #include <WebBrowserEx.hpp>
 #include <DateUtils.hpp>
+#include <OperationWithTimeout.hpp>
 //---------------------------------------------------------------------------
 #define KEY _T("SYSTEM\\CurrentControlSet\\Control\\") \
             _T("Session Manager\\Environment")
@@ -1803,7 +1804,7 @@ static bool __fastcall AddJumpListCategory(TStrings * Names,
 void __fastcall UpdateJumpList(TStrings * SessionNames, TStrings * WorkspaceNames)
 {
   ICustomDestinationList * DestinationList = NULL;
-  IObjectArray * RemovedArray = NULL;
+  IObjectArray * RemovedArray;
   TStringList * Removed = NULL;
   int OldErrMode = SetErrorMode(SEM_FAILCRITICALERRORS);
 
@@ -1814,9 +1815,7 @@ void __fastcall UpdateJumpList(TStrings * SessionNames, TStrings * WorkspaceName
     {
 
       unsigned int MinSlots;
-      unsigned int * PMinSlots = &MinSlots;
-      void ** PRemovedArray = (void**)&RemovedArray;
-      HRESULT Result = DestinationList->BeginList(PMinSlots, IID_IObjectArray, PRemovedArray);
+      HRESULT Result = DestinationListBeginList(DestinationList, MinSlots, IID_IObjectArray, reinterpret_cast<void *>(RemovedArray), 50000);
       if (SUCCEEDED(Result) && DebugAlwaysTrue(RemovedArray != NULL))
       {
         Removed = new TStringList();
@@ -1856,10 +1855,6 @@ void __fastcall UpdateJumpList(TStrings * SessionNames, TStrings * WorkspaceName
   __finally
   {
     SetErrorMode(OldErrMode);
-    if (RemovedArray != NULL)
-    {
-      RemovedArray->Release();
-    }
     if (DestinationList != NULL)
     {
       DestinationList->Release();