Преглед изворни кода

In UWP, files can be downloaded directly to an external drop location even without a loaded drag&drop shell extension.

Part of "Make WinSCP available in Windows Store (UWP/AppX package)"
https://winscp.net/tracker/1639
(UWP-only subset of dev branch commit dc85563)

Counters DownloadsDragDropQueue + DownloadsDragDropFakeFile

(cherry picked from commit dc855630a2a68ba029e6ef7845471a49049dfe42)

# Conflicts:
#	source/resource/TextsWin.h
#	source/resource/TextsWin1.rc
#	translations/translate.web.ini

Source commit: 5c7069bac3e08f2f19c227d38eaffe989e73f4f8
Martin Prikryl пре 7 година
родитељ
комит
be8d3acbc1

+ 4 - 1
source/Moje.cbproj

@@ -96,7 +96,10 @@
 			<BuildOrder>3</BuildOrder>
 		</DelphiCompile>
 		<DelphiCompile Include="packages\my\CompThread.pas">
-			<BuildOrder>4</BuildOrder>
+			<BuildOrder>22</BuildOrder>
+		</DelphiCompile>
+		<DelphiCompile Include="packages\my\DirectoryMonitor.pas">
+			<BuildOrder>23</BuildOrder>
 		</DelphiCompile>
 		<ResFiles Include="packages\my\DiscMon.dcr">
 			<BuildOrder>6</BuildOrder>

+ 1 - 1
source/dragext/DragExt.cpp

@@ -208,7 +208,7 @@ DllMain(HINSTANCE HInstance, DWORD Reason, LPVOID /*Reserved*/)
 
     if (GRefThisDll == 0)
     {
-      GLogMutex = CreateMutex(NULL, false, L"WinSCPDragExtLogMutex");
+      GLogMutex = CreateMutex(NULL, false, DRAG_EXT_RUNNING_MUTEX);
 
       for (int Root = 0; Root <= 1; Root++)
       {

+ 1 - 0
source/dragext/DragExt.h

@@ -4,6 +4,7 @@
 //---------------------------------------------------------------------------
 #define DRAG_EXT_MAPPING L"WinSCPDragExtMapping"
 #define DRAG_EXT_MUTEX L"WinSCPDragExtMutex"
+#define DRAG_EXT_RUNNING_MUTEX L"WinSCPDragExtLogMutex"
 #define DRAG_EXT_DUMMY_DIR_PREFIX L"scp"
 #define DRAG_EXT_DUMMY_DIR_PREFIX_LEN 3
 //---------------------------------------------------------------------------

+ 69 - 9
source/forms/CustomScpExplorer.cpp

@@ -35,6 +35,7 @@
 #include <Consts.hpp>
 #include <DateUtils.hpp>
 #include <TB2Common.hpp>
+#include <DirectoryMonitor.hpp>
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
 #pragma link "CustomDirView"
@@ -6583,7 +6584,7 @@ void __fastcall TCustomScpExplorerForm::RemoteFileControlDDCreateDragFileList(
 
   if (WinConfiguration->DDExtEnabled)
   {
-    if (!WinConfiguration->DDExtInstalled)
+    if (!IsUWP() && !WinConfiguration->DDExtInstalled)
     {
       Configuration->Usage->Inc(L"DownloadsDragDropExternalExtNotInstalled");
       throw ExtException(NULL, LoadStr(DRAGEXT_TARGET_NOT_INSTALLED2), HELP_DRAGEXT_TARGET_NOT_INSTALLED);
@@ -6592,19 +6593,61 @@ void __fastcall TCustomScpExplorerForm::RemoteFileControlDDCreateDragFileList(
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TCustomScpExplorerForm::DDFakeCreated(TObject * /*Sender*/, const UnicodeString FileName)
+{
+  if (DebugAlwaysTrue(!FDragExtFakeDirectory.IsEmpty()) &&
+      SameText(ExtractFileName(FileName), ExtractFileName(FDragExtFakeDirectory)))
+  {
+    FFakeFileDropTarget = FileName;
+  }
+}
+//---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::DDExtInitDrag(TFileList * FileList,
   bool & Created)
 {
+  FFakeFileDropTarget = UnicodeString();
   FDragExtFakeDirectory =
     ExcludeTrailingBackslash(WinConfiguration->TemporaryDir());
   if (!ForceDirectories(ApiPath(FDragExtFakeDirectory)))
   {
     throw Exception(FMTLOAD(CREATE_TEMP_DIR_ERROR, (FDragExtFakeDirectory)));
   }
+  if (IsUWP())
+  {
+    FileSetAttr(ApiPath(FDragExtFakeDirectory), faHidden);
+  }
   FileList->AddItem(NULL, FDragExtFakeDirectory);
 
   Created = true;
 
+  if (IsUWP() && !WinConfiguration->IsDDExtRunning())
+  {
+    FDragFakeMonitors = new TObjectList();
+    for (char Drive = FirstDrive; Drive <= LastDrive; Drive++)
+    {
+      std::unique_ptr<TDirectoryMonitor> Monitor(new TDirectoryMonitor(this));
+      DriveInfo->ReadDriveStatus(Drive, dsSize | dsImageIndex);
+      TDriveInfoRec * DriveInfoRec = DriveInfo->Data[Drive];
+      if (DriveInfoRec->Valid &&
+          (DriveInfoRec->DriveType != DRIVE_CDROM))
+      {
+        try
+        {
+          Monitor->Path = UnicodeString(Drive) + L":\\";
+          Monitor->WatchSubtree = true;
+          Monitor->WatchFilters = FILE_NOTIFY_CHANGE_DIR_NAME;
+          Monitor->OnCreated = DDFakeCreated;
+          Monitor->Active = true;
+          FDragFakeMonitors->Add(Monitor.release());
+        }
+        catch (Exception & E)
+        {
+          // Ignore errors watching not-ready drives
+        }
+      }
+    }
+  }
+
   FDDExtMapFile = CreateFileMappingA((HANDLE)0xFFFFFFFF, NULL, PAGE_READWRITE,
     0, sizeof(TDragExtCommStruct), AnsiString(DRAG_EXT_MAPPING).c_str());
 
@@ -6669,6 +6712,11 @@ void __fastcall TCustomScpExplorerForm::RemoteFileControlDDEnd(TObject * Sender)
   // Drops of local files (uploads) are handled in QueueDDProcessDropped.
   SAFE_DESTROY(FDDFileList);
 
+  if (IsUWP() && !FFakeFileDropTarget.IsEmpty())
+  {
+    RemoveDir(ApiPath(FFakeFileDropTarget));
+  }
+
   if ((FDDExtMapFile != NULL) || (FDDTargetControl == QueueView3))
   {
     try
@@ -6712,9 +6760,9 @@ void __fastcall TCustomScpExplorerForm::RemoteFileControlDDEnd(TObject * Sender)
         }
 
         TTransferOperationParam Param;
-        bool Internal;
+        UnicodeString CounterName;
         bool ForceQueue;
-        if (!DDGetTarget(Param.TargetDirectory, ForceQueue, Internal))
+        if (!DDGetTarget(Param.TargetDirectory, ForceQueue, CounterName))
         {
           // we get drInvalid both if d&d was intercepted by ddext,
           // and when users drops on no-drop location.
@@ -6731,7 +6779,7 @@ void __fastcall TCustomScpExplorerForm::RemoteFileControlDDEnd(TObject * Sender)
         }
         else
         {
-          // download using ddext
+          // download using fake file
           Param.Temp = false;
           Param.DragDrop = true;
           if (ForceQueue)
@@ -6746,8 +6794,7 @@ void __fastcall TCustomScpExplorerForm::RemoteFileControlDDEnd(TObject * Sender)
           if (RemoteFileControlFileOperation(Sender, Operation,
                 (WinConfiguration->DDTransferConfirmation == asOff), &Param))
           {
-            Configuration->Usage->Inc(
-              Internal ? L"DownloadsDragDropInternal" : L"DownloadsDragDropExternalExt");
+            Configuration->Usage->Inc(CounterName);
           }
         }
       }
@@ -6756,8 +6803,14 @@ void __fastcall TCustomScpExplorerForm::RemoteFileControlDDEnd(TObject * Sender)
     {
       CloseHandle(FDDExtMapFile);
       FDDExtMapFile = NULL;
+      if (IsUWP())
+      {
+        delete FDragFakeMonitors;
+        FDragFakeMonitors = NULL;
+      }
       RemoveDir(ApiPath(FDragExtFakeDirectory));
       FDragExtFakeDirectory = L"";
+      FFakeFileDropTarget = UnicodeString();
     }
   }
 
@@ -6789,16 +6842,23 @@ void __fastcall TCustomScpExplorerForm::RemoteFileControlDDGiveFeedback(
 }
 //---------------------------------------------------------------------------
 bool __fastcall TCustomScpExplorerForm::DDGetTarget(
-  UnicodeString & Directory, bool & ForceQueue, bool & Internal)
+  UnicodeString & Directory, bool & ForceQueue, UnicodeString & CounterName)
 {
   bool Result;
   if (FDDTargetControl == QueueView3)
   {
     Directory = DefaultDownloadTargetDirectory();
     Result = true;
-    Internal = true;
+    CounterName = L"DownloadsDragDropQueue";
     ForceQueue = true;
   }
+  else if (IsUWP() && !FFakeFileDropTarget.IsEmpty())
+  {
+    Directory = ExcludeTrailingBackslash(ExtractFilePath(FFakeFileDropTarget));
+    Result = true;
+    ForceQueue = false;
+    CounterName = L"DownloadsDragDropFakeFile";
+  }
   else
   {
     ForceQueue = false;
@@ -6820,7 +6880,7 @@ bool __fastcall TCustomScpExplorerForm::DDGetTarget(
           if (Result)
           {
             Directory = ExtractFilePath(CommStruct->DropDest);
-            Internal = false;
+            CounterName = L"DownloadsDragDropExternalExt";
           }
           UnmapViewOfFile(CommStruct);
         }

+ 4 - 1
source/forms/CustomScpExplorer.h

@@ -202,6 +202,7 @@ private:
   TStringList * FErrorList;
   HANDLE FDDExtMutex;
   UnicodeString FDragExtFakeDirectory;
+  TObjectList * FDragFakeMonitors;
   TStrings * FDelayedDeletionList;
   TTimer * FDelayedDeletionTimer;
   TStrings * FDDFileList;
@@ -327,6 +328,7 @@ protected:
   TPoint FLastContextPopupScreenPoint;
   bool FRemoteDirViewWasFocused;
   bool FDoNotIdleCurrentTerminal;
+  UnicodeString FFakeFileDropTarget;
 
   virtual bool __fastcall CopyParamDialog(TTransferDirection Direction,
     TTransferType Type, bool Temp, TStrings * FileList,
@@ -419,8 +421,9 @@ protected:
   bool __fastcall ExecuteFileOperation(TFileOperation Operation, TOperationSide Side,
     TStrings * FileList, bool NoConfirmation, void * Param);
   virtual bool __fastcall DDGetTarget(UnicodeString & Directory,
-    bool & ForceQueue, bool & Internal);
+    bool & ForceQueue, UnicodeString & CounterName);
   virtual void __fastcall DDExtInitDrag(TFileList * FileList, bool & Created);
+  void __fastcall DDFakeCreated(TObject * Sender, const UnicodeString FileName);
   virtual void __fastcall SideEnter(TOperationSide Side);
   virtual TOperationSide __fastcall GetSide(TOperationSide Side);
   TStrings * __fastcall PanelExport(TOperationSide Side, TPanelExport Export);

+ 2 - 2
source/forms/Preferences.cpp

@@ -1214,8 +1214,8 @@ void __fastcall TPreferencesDialog::UpdateControls()
     }
     SetLabelHintPopup(CopyParamLabel, InfoStr);
 
-    EnableControl(DDExtEnabledButton, WinConfiguration->DDExtInstalled);
-    EnableControl(DDExtEnabledLabel, WinConfiguration->DDExtInstalled);
+    EnableControl(DDExtEnabledButton, IsUWP() || WinConfiguration->DDExtInstalled);
+    EnableControl(DDExtEnabledLabel, DDExtEnabledButton->Enabled);
     EnableControl(DDExtDisabledPanel, DDExtDisabledButton->Checked);
     EnableControl(DDTemporaryDirectoryEdit, DDCustomTemporaryDirectoryButton->Enabled &&
       DDCustomTemporaryDirectoryButton->Checked);

+ 2 - 2
source/forms/Preferences.dfm

@@ -1343,7 +1343,7 @@ object PreferencesDialog: TPreferencesDialog
             Width = 364
             Height = 17
             Anchors = [akLeft, akTop, akRight]
-            Caption = 'Use &shell extension'
+            Caption = 'Determine drop target by dragging a &fake file'
             TabOrder = 1
             OnClick = ControlChange
           end
@@ -1353,7 +1353,7 @@ object PreferencesDialog: TPreferencesDialog
             Width = 356
             Height = 17
             Anchors = [akLeft, akTop, akRight]
-            Caption = 'Use &temporary folder'
+            Caption = 'Download files via &temporary folder'
             TabOrder = 2
             OnClick = ControlChange
           end

+ 3 - 3
source/forms/ScpCommander.cpp

@@ -1449,7 +1449,7 @@ void __fastcall TScpCommanderForm::LocalFileControlDDDragOver(TObject * /*Sender
 }
 //---------------------------------------------------------------------------
 bool __fastcall TScpCommanderForm::DDGetTarget(
-  UnicodeString & Directory, bool & ForceQueue, bool & Internal)
+  UnicodeString & Directory, bool & ForceQueue, UnicodeString & CounterName)
 {
   bool Result;
   if (!FDDExtTarget.IsEmpty())
@@ -1457,12 +1457,12 @@ bool __fastcall TScpCommanderForm::DDGetTarget(
     Directory = FDDExtTarget;
     FDDExtTarget = L"";
     Result = true;
-    Internal = true;
+    CounterName = L"DownloadsDragDropInternal";
     ForceQueue = false;
   }
   else
   {
-    Result = TCustomScpExplorerForm::DDGetTarget(Directory, ForceQueue, Internal);
+    Result = TCustomScpExplorerForm::DDGetTarget(Directory, ForceQueue, CounterName);
   }
   return Result;
 }

+ 1 - 1
source/forms/ScpCommander.h

@@ -536,7 +536,7 @@ protected:
     TOperationSide Side);
   bool __fastcall InternalDDDownload(UnicodeString & TargetDirectory);
   virtual bool __fastcall DDGetTarget(
-    UnicodeString & Directory, bool & ForceQueue, bool & Internal);
+    UnicodeString & Directory, bool & ForceQueue, UnicodeString & CounterName);
   virtual void __fastcall DDExtInitDrag(TFileList * FileList, bool & Created);
   virtual void __fastcall SideEnter(TOperationSide Side);
   void __fastcall SaveCommandLine();

+ 39 - 1
source/windows/WinConfiguration.cpp

@@ -493,6 +493,7 @@ void __fastcall TWinConfiguration::Default()
   FDDWarnLackOfTempSpace = true;
   FDDWarnLackOfTempSpaceRatio = 1.1;
   FDDExtEnabled = DDExtInstalled;
+  FDDFakeFile = true;
   FDDExtTimeout = MSecsPerSec;
   FDeleteToRecycleBin = true;
   FSelectDirectories = false;
@@ -915,6 +916,7 @@ THierarchicalStorage * TWinConfiguration::CreateScpStorage(bool & SessionList)
     KEY(Bool,     UseSharedBookmarks); \
     KEY(Integer,  LocaleSafe); \
     KEY(Bool,     DDExtEnabled); \
+    KEY(Bool,     DDFakeFile); \
     KEY(Integer,  DDExtTimeout); \
     KEY(Bool,     DefaultDirIsHome); \
     KEY(Bool,     TemporaryDirectoryAppendSession); \
@@ -1605,6 +1607,23 @@ bool __fastcall TWinConfiguration::GetDDExtInstalled()
   return (FDDExtInstalled > 0);
 }
 //---------------------------------------------------------------------------
+bool __fastcall TWinConfiguration::IsDDExtRunning()
+{
+  bool Result;
+  if (!DDExtInstalled)
+  {
+    Result = false;
+  }
+  else
+  {
+    HANDLE H = OpenMutex(SYNCHRONIZE, False, DRAG_EXT_RUNNING_MUTEX);
+    Result = (H != NULL);
+    CloseHandle(H);
+  }
+
+  return Result;
+}
+//---------------------------------------------------------------------------
 RawByteString __fastcall TWinConfiguration::StronglyRecryptPassword(RawByteString Password, UnicodeString Key)
 {
   RawByteString Dummy;
@@ -1799,9 +1818,28 @@ void __fastcall TWinConfiguration::SetDDTemporaryDirectory(UnicodeString value)
   SET_CONFIG_PROPERTY(DDTemporaryDirectory);
 }
 //---------------------------------------------------------------------------
+bool __fastcall TWinConfiguration::GetDDExtEnabled()
+{
+  if (IsUWP())
+  {
+    return FDDFakeFile;
+  }
+  else
+  {
+    return FDDExtEnabled;
+  }
+}
+//---------------------------------------------------------------------------
 void __fastcall TWinConfiguration::SetDDExtEnabled(bool value)
 {
-  SET_CONFIG_PROPERTY(DDExtEnabled);
+  if (IsUWP())
+  {
+    SET_CONFIG_PROPERTY(DDFakeFile);
+  }
+  else
+  {
+    SET_CONFIG_PROPERTY(DDExtEnabled);
+  }
 }
 //---------------------------------------------------------------------------
 void __fastcall TWinConfiguration::SetDDExtTimeout(int value)

+ 6 - 1
source/windows/WinConfiguration.h

@@ -355,6 +355,7 @@ private:
   UnicodeString FDDTemporaryDirectory;
   bool FDDWarnLackOfTempSpace;
   bool FDDExtEnabled;
+  bool FDDFakeFile;
   int FDDExtInstalled;
   int FDDExtTimeout;
   bool FConfirmClosingSession;
@@ -464,6 +465,7 @@ private:
   void __fastcall SetDDTemporaryDirectory(UnicodeString value);
   void __fastcall SetDDWarnLackOfTempSpace(bool value);
   void __fastcall SetDDExtEnabled(bool value);
+  bool __fastcall GetDDExtEnabled();
   void __fastcall SetDDExtTimeout(int value);
   void __fastcall SetConfirmClosingSession(bool value);
   void __fastcall SetDDWarnLackOfTempSpaceRatio(double value);
@@ -577,6 +579,8 @@ protected:
   void __fastcall ReleaseExtensionTranslations();
   void __fastcall LoadExtensionTranslations();
 
+  __property bool DDFakeFile = { read=FDDFakeFile, write=FDDFakeFile };
+
 public:
   __fastcall TWinConfiguration();
   virtual __fastcall ~TWinConfiguration();
@@ -612,6 +616,7 @@ public:
   UnicodeString __fastcall ExtensionStringTranslation(const UnicodeString & ExtensionId, const UnicodeString & S);
   UnicodeString __fastcall UniqueExtensionName(const UnicodeString & ExtensionName, int Counter);
   UnicodeString __fastcall GetProvisionaryExtensionId(const UnicodeString & FileName);
+  bool __fastcall IsDDExtRunning();
 
   static void __fastcall RestoreFont(const TFontConfiguration & Configuration, TFont * Font);
   static void __fastcall StoreFont(TFont * Font, TFontConfiguration & Configuration);
@@ -646,7 +651,7 @@ public:
   __property bool UseSharedBookmarks = { read = FUseSharedBookmarks, write = SetUseSharedBookmarks};
   __property UnicodeString DDTemporaryDirectory  = { read=FDDTemporaryDirectory, write=SetDDTemporaryDirectory };
   __property bool DDWarnLackOfTempSpace  = { read=FDDWarnLackOfTempSpace, write=SetDDWarnLackOfTempSpace };
-  __property bool DDExtEnabled = { read=FDDExtEnabled, write=SetDDExtEnabled };
+  __property bool DDExtEnabled = { read=GetDDExtEnabled, write=SetDDExtEnabled };
   __property bool DDExtInstalled = { read=GetDDExtInstalled };
   __property int DDExtTimeout = { read=FDDExtTimeout, write=SetDDExtTimeout };
   __property bool ConfirmClosingSession  = { read=FConfirmClosingSession, write=SetConfirmClosingSession };