diff --git a/Files.Launcher/DragDropForm.cs b/Files.Launcher/DragDropForm.cs
deleted file mode 100644
index a931e3df6da0..000000000000
--- a/Files.Launcher/DragDropForm.cs
+++ /dev/null
@@ -1,161 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Windows.Forms;
-
-namespace FilesFullTrust
-{
-    internal class DragDropForm : Form
-    {
-        private string dropPath;
-
-        public List<string> DropTargets { get; private set; } = new List<string>();
-
-        public DragDropForm(string dropPath, string dropText, System.Threading.CancellationToken token)
-        {
-            var appTheme = GetAppTheme();
-
-            this.FormBorderStyle = FormBorderStyle.None;
-            this.ShowInTaskbar = false;
-            this.MaximizeBox = false;
-            this.MinimizeBox = false;
-            this.Text = "Files";
-            this.BackColor = appTheme switch
-            {
-                Windows.UI.Xaml.ElementTheme.Light => System.Drawing.Color.White,
-                _ => System.Drawing.Color.Black
-            };
-            this.Opacity = 0.5;
-            this.TopMost = true;
-            this.DragOver += DragDropForm_DragOver;
-            this.DragDrop += DragDropForm_DragDrop;
-            this.DragLeave += DragDropForm_DragLeave;
-            this.AllowDrop = true;
-
-            var label = new Label();
-            label.AutoSize = false;
-            label.Font = new System.Drawing.Font("Segoe UI", 24);
-            label.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
-            label.ForeColor = appTheme switch
-            {
-                Windows.UI.Xaml.ElementTheme.Light => System.Drawing.Color.Black,
-                _ => System.Drawing.Color.White
-            };
-            label.Dock = DockStyle.Fill;
-            label.Text = dropText;
-            this.Controls.Add(label);
-            this.dropPath = dropPath;
-
-            // Create window over Files window
-            this.StartPosition = FormStartPosition.Manual;
-            var Handle = Vanara.PInvoke.User32.WindowFromPoint(Cursor.Position);
-            Vanara.PInvoke.User32.GetWindowRect(Handle, out var lpRect);
-            this.Size = new System.Drawing.Size(lpRect.Width, lpRect.Height);
-            this.Location = new System.Drawing.Point(lpRect.Location.X, lpRect.Location.Y);
-
-            token.Register(() =>
-            {
-                if (this.IsHandleCreated)
-                {
-                    // If another window is created, close this one
-                    this.Invoke(new InvokeDelegate(() => this.Close()));
-                }
-            });
-            this.HandleCreated += DragDropForm_HandleCreated;
-        }
-
-        private Windows.UI.Xaml.ElementTheme GetAppTheme()
-        {
-            var appTheme = Windows.UI.Xaml.ElementTheme.Default;
-            var savedTheme = Windows.Storage.ApplicationData.Current.LocalSettings.Values["theme"]?.ToString();
-            if (!string.IsNullOrEmpty(savedTheme))
-            {
-                Enum.TryParse(savedTheme, out appTheme);
-            }
-            if (appTheme == Windows.UI.Xaml.ElementTheme.Default)
-            {
-                var settings = new Windows.UI.ViewManagement.UISettings();
-                appTheme = settings.GetColorValue(Windows.UI.ViewManagement.UIColorType.Background).ToString() switch
-                {
-                    "#FFFFFFFF" => Windows.UI.Xaml.ElementTheme.Light,
-                    "#FF000000" => Windows.UI.Xaml.ElementTheme.Dark,
-                    _ => Windows.UI.Xaml.ElementTheme.Default // Unknown theme
-                };
-            }
-            return appTheme;
-        }
-
-        public delegate void InvokeDelegate();
-
-        private void DragDropForm_HandleCreated(object sender, EventArgs e)
-        {
-            var timer = new Timer();
-            timer.Interval = 1000;
-            timer.Tick += (s, e) =>
-            {
-                if (!this.DesktopBounds.Contains(Cursor.Position))
-                {
-                    // After some time check whether the mouse is still inside the drop window
-                    this.Close();
-                    (s as Timer).Dispose();
-                }
-            };
-            timer.Start();
-        }
-
-        private void DragDropForm_DragLeave(object sender, EventArgs e)
-        {
-            this.Close();
-        }
-
-        private void DragDropForm_DragDrop(object sender, DragEventArgs e)
-        {
-            if (e.Data.GetDataPresent("FileDrop"))
-            {
-                var str = e.Data.GetData("FileDrop") as string[];
-                DropTargets.AddRange(str);
-                foreach (var file in DropTargets)
-                {
-                    try
-                    {
-                        // Move files to destination
-                        // Works for 7zip, Winrar which unpack the items in the temp folder
-                        var destName = Path.GetFileName(file.TrimEnd(Path.DirectorySeparatorChar));
-                        Directory.Move(file, Path.Combine(dropPath, destName));
-                    }
-                    catch (Exception ex)
-                    {
-                        Program.Logger.Warn(ex, "Failed to drop items");
-                    }
-                }
-            }
-            this.Close();
-        }
-
-        private void DragDropForm_DragOver(object sender, DragEventArgs e)
-        {
-            // Should handle "Shell ID List" as well
-            if (e.Data.GetDataPresent("FileDrop"))
-            {
-                e.Effect = DragDropEffects.All;
-            }
-            else
-            {
-                e.Effect = DragDropEffects.None;
-            }
-        }
-
-        protected override CreateParams CreateParams
-        {
-            get
-            {
-                // Turn on WS_EX_TOOLWINDOW style bit
-                // Window won't show in alt-tab
-                CreateParams cp = base.CreateParams;
-                cp.ExStyle |= 0x80;
-                return cp;
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/Files.Launcher/Files.Launcher.csproj b/Files.Launcher/Files.Launcher.csproj
index a922dbcaed62..fcc14d48272f 100644
--- a/Files.Launcher/Files.Launcher.csproj
+++ b/Files.Launcher/Files.Launcher.csproj
@@ -126,15 +126,13 @@
   </ItemGroup>
   <ItemGroup>
     <Compile Include="DeviceWatcher.cs" />
-    <Compile Include="DragDropForm.cs">
-      <SubType>Form</SubType>
-    </Compile>
     <Compile Include="LogWriter.cs" />
     <Compile Include="FilePermissions.cs" />
     <Compile Include="NetworkDrivesAPI.cs" />
     <Compile Include="Program.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="QuickLook.cs" />
+    <Compile Include="RemoteDataObject.cs" />
     <Compile Include="Win32API.cs" />
     <Compile Include="Win32API_ContextMenu.cs" />
   </ItemGroup>
diff --git a/Files.Launcher/Program.cs b/Files.Launcher/Program.cs
index d88910140a42..0c203cdf35d6 100644
--- a/Files.Launcher/Program.cs
+++ b/Files.Launcher/Program.cs
@@ -87,9 +87,6 @@ private static void Main(string[] args)
                 librariesWatcher.Renamed += (object _, RenamedEventArgs e) => OnLibraryChanged(e.ChangeType, e.OldFullPath, e.FullPath);
                 librariesWatcher.EnableRaisingEvents = true;
 
-                // Create cancellation token for drop window
-                cancellation = new CancellationTokenSource();
-
                 // Connect to app service and wait until the connection gets closed
                 appServiceExit = new ManualResetEvent(false);
                 InitializeAppServiceConnection();
@@ -116,8 +113,6 @@ private static void Main(string[] args)
                 handleTable?.Dispose();
                 deviceWatcher?.Dispose();
                 librariesWatcher?.Dispose();
-                cancellation?.Cancel();
-                cancellation?.Dispose();
                 appServiceExit?.Dispose();
             }
         }
@@ -157,7 +152,6 @@ private static async void RecycleBinWatcher_Changed(object sender, FileSystemEve
 
         private static NamedPipeServerStream connection;
         private static ManualResetEvent appServiceExit;
-        private static CancellationTokenSource cancellation;
         private static Win32API.DisposableDictionary handleTable;
         private static IList<FileSystemWatcher> binWatchers;
         private static DeviceWatcher deviceWatcher;
@@ -872,17 +866,46 @@ await Win32API.StartSTATask(() =>
                     break;
 
                 case "DragDrop":
-                    cancellation.Cancel();
-                    cancellation.Dispose();
-                    cancellation = new CancellationTokenSource();
                     var dropPath = (string)message["droppath"];
-                    var dropText = (string)message["droptext"];
-                    var drops = Win32API.StartSTATask<List<string>>(() =>
+                    var result2 = await Win32API.StartSTATask(() =>
                     {
-                        var form = new DragDropForm(dropPath, dropText, cancellation.Token);
-                        System.Windows.Forms.Application.Run(form);
-                        return form.DropTargets;
+                        var rdo = new RemoteDataObject(System.Windows.Forms.Clipboard.GetDataObject());
+
+                        foreach (RemoteDataObject.DataPackage package in rdo.GetRemoteData())
+                        {
+                            try
+                            {
+                                if (package.ItemType == RemoteDataObject.StorageType.File)
+                                {
+                                    string directoryPath = Path.GetDirectoryName(dropPath);
+                                    if (!Directory.Exists(directoryPath))
+                                    {
+                                        Directory.CreateDirectory(directoryPath);
+                                    }
+
+                                    string uniqueName = Win32API.GenerateUniquePath(Path.Combine(dropPath, package.Name));
+                                    using (FileStream stream = new FileStream(uniqueName, FileMode.CreateNew))
+                                    {
+                                        package.ContentStream.CopyTo(stream);
+                                    }
+                                }
+                                else
+                                {
+                                    string directoryPath = Path.Combine(dropPath, package.Name);
+                                    if (!Directory.Exists(directoryPath))
+                                    {
+                                        Directory.CreateDirectory(directoryPath);
+                                    }
+                                }
+                            }
+                            finally
+                            {
+                                package.Dispose();
+                            }
+                        }
+                        return true;
                     });
+                    await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", result2 } }, message.Get("RequestID", (string)null));
                     break;
 
                 case "DeleteItem":
diff --git a/Files.Launcher/RemoteDataObject.cs b/Files.Launcher/RemoteDataObject.cs
new file mode 100644
index 000000000000..c916e2c26d86
--- /dev/null
+++ b/Files.Launcher/RemoteDataObject.cs
@@ -0,0 +1,298 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.ComTypes;
+using System.Windows.Forms;
+using Vanara.PInvoke;
+using STATSTG = System.Runtime.InteropServices.ComTypes.STATSTG;
+
+namespace FilesFullTrust
+{
+    // Class taken from Rx-Explorer (https://github.com/zhuxb711/RX-Explorer)
+    public class RemoteDataObject
+    {
+        /// <summary>
+        /// Holds the <see cref="System.Windows.IDataObject"/> that this class is wrapping
+        /// </summary>
+        private System.Windows.Forms.IDataObject underlyingDataObject;
+
+        /// <summary>
+        /// Holds the <see cref="System.Runtime.InteropServices.ComTypes.IDataObject"/> interface to the <see cref="System.Windows.IDataObject"/> that this class is wrapping.
+        /// </summary>
+        private System.Runtime.InteropServices.ComTypes.IDataObject comUnderlyingDataObject;
+
+        /// <summary>
+        /// Holds the internal ole <see cref="System.Windows.IDataObject"/> to the <see cref="System.Windows.IDataObject"/> that this class is wrapping.
+        /// </summary>
+        private System.Windows.Forms.IDataObject oleUnderlyingDataObject;
+
+        /// <summary>
+        /// Holds the <see cref="MethodInfo"/> of the "GetDataFromHGLOBAL" method of the internal ole <see cref="System.Windows.IDataObject"/>.
+        /// </summary>
+        private MethodInfo getDataFromHGLOBALMethod;
+
+        /// <summary>
+        /// Initializes a new instance of the class.
+        /// </summary>
+        /// <param name="underlyingDataObject">The underlying data object to wrap.</param>
+        public RemoteDataObject(System.Windows.Forms.IDataObject underlyingDataObject)
+        {
+            //get the underlying dataobject and its ComType IDataObject interface to it
+            this.underlyingDataObject = underlyingDataObject;
+            comUnderlyingDataObject = (System.Runtime.InteropServices.ComTypes.IDataObject)this.underlyingDataObject;
+
+            //get the internal ole dataobject and its GetDataFromHGLOBAL so it can be called later
+            FieldInfo innerDataField = this.underlyingDataObject.GetType().GetField("innerData", BindingFlags.NonPublic | BindingFlags.Instance);
+            oleUnderlyingDataObject = (System.Windows.Forms.IDataObject)innerDataField.GetValue(this.underlyingDataObject);
+            getDataFromHGLOBALMethod = oleUnderlyingDataObject.GetType().GetMethod("GetDataFromHGLOBAL", BindingFlags.NonPublic | BindingFlags.Instance);
+        }
+
+        public IEnumerable<DataPackage> GetRemoteData()
+        {
+            string FormatName = string.Empty;
+
+            if (GetDataPresent(Shell32.ShellClipboardFormat.CFSTR_FILEDESCRIPTORW))
+            {
+                FormatName = Shell32.ShellClipboardFormat.CFSTR_FILEDESCRIPTORW;
+            }
+            else if (GetDataPresent(Shell32.ShellClipboardFormat.CFSTR_FILEDESCRIPTORA))
+            {
+                FormatName = Shell32.ShellClipboardFormat.CFSTR_FILEDESCRIPTORA;
+            }
+
+            if (string.IsNullOrEmpty(FormatName))
+            {
+                yield break;
+            }
+            else
+            {
+                if (underlyingDataObject.GetData(FormatName, true) is MemoryStream FileGroupDescriptorStream)
+                {
+                    try
+                    {
+                        byte[] FileGroupDescriptorBytes = FileGroupDescriptorStream.ToArray();
+
+                        IntPtr FileGroupDescriptorAPointer = Marshal.AllocHGlobal(FileGroupDescriptorBytes.Length);
+
+                        try
+                        {
+                            Marshal.Copy(FileGroupDescriptorBytes, 0, FileGroupDescriptorAPointer, FileGroupDescriptorBytes.Length);
+
+                            int ItemCount = Marshal.ReadInt32(FileGroupDescriptorAPointer);
+
+                            IntPtr FileDescriptorPointer = (IntPtr)(FileGroupDescriptorAPointer.ToInt64() + Marshal.SizeOf(ItemCount));
+
+                            for (int FileDescriptorIndex = 0; FileDescriptorIndex < ItemCount; FileDescriptorIndex++)
+                            {
+                                Shell32.FILEDESCRIPTOR FileDescriptor = Marshal.PtrToStructure<Shell32.FILEDESCRIPTOR>(FileDescriptorPointer);
+
+                                if (FileDescriptor.dwFileAttributes.HasFlag(FileFlagsAndAttributes.FILE_ATTRIBUTE_DIRECTORY))
+                                {
+                                    yield return new DataPackage(FileDescriptor.cFileName, StorageType.Directroy, null);
+                                }
+                                else
+                                {
+                                    yield return new DataPackage(FileDescriptor.cFileName, StorageType.File, GetContentData(Shell32.ShellClipboardFormat.CFSTR_FILECONTENTS, FileDescriptorIndex));
+                                }
+
+                                FileDescriptorPointer = (IntPtr)(FileDescriptorPointer.ToInt64() + Marshal.SizeOf(FileDescriptor));
+                            }
+                        }
+                        finally
+                        {
+                            Marshal.FreeHGlobal(FileGroupDescriptorAPointer);
+                        }
+                    }
+                    finally
+                    {
+                        FileGroupDescriptorStream.Dispose();
+                    }
+                }
+                else
+                {
+                    yield break;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Retrieves the data associated with the specified data format at the specified index.
+        /// </summary>
+        /// <param name="Format">The format of the data to retrieve. See <see cref="T:System.Windows.DataFormats"></see> for predefined formats.</param>
+        /// <param name="Index">The index of the data to retrieve.</param>
+        /// <returns>
+        /// A <see cref="MemoryStream"/> containing the raw data for the specified data format at the specified index.
+        /// </returns>
+        private MemoryStream GetContentData(string Format, int Index)
+        {
+            //create a FORMATETC struct to request the data with
+            FORMATETC Formatetc = new FORMATETC
+            {
+                cfFormat = (short)DataFormats.GetFormat(Format).Id,
+                dwAspect = DVASPECT.DVASPECT_CONTENT,
+                lindex = Index,
+                ptd = new IntPtr(0),
+                tymed = TYMED.TYMED_ISTREAM | TYMED.TYMED_ISTORAGE | TYMED.TYMED_HGLOBAL
+            };
+
+            //using the Com IDataObject interface get the data using the defined FORMATETC
+            comUnderlyingDataObject.GetData(ref Formatetc, out STGMEDIUM Medium);
+
+            //retrieve the data depending on the returned store type
+            switch (Medium.tymed)
+            {
+                case TYMED.TYMED_ISTORAGE:
+                    {
+                        //to handle a IStorage it needs to be written into a second unmanaged
+                        //memory mapped storage and then the data can be read from memory into
+                        //a managed byte and returned as a MemoryStream
+
+                        try
+                        {
+                            //marshal the returned pointer to a IStorage object
+                            Ole32.IStorage IStorageObject = (Ole32.IStorage)Marshal.GetObjectForIUnknown(Medium.unionmember);
+
+                            try
+                            {
+                                //create a ILockBytes (unmanaged byte array) and then create a IStorage using the byte array as a backing store
+                                Ole32.CreateILockBytesOnHGlobal(IntPtr.Zero, true, out Ole32.ILockBytes LockBytes);
+                                Ole32.StgCreateDocfileOnILockBytes(LockBytes, STGM.STGM_READWRITE | STGM.STGM_SHARE_EXCLUSIVE | STGM.STGM_CREATE, ppstgOpen: out Ole32.IStorage IStorageObjectCopy);
+
+                                try
+                                {
+                                    //copy the returned IStorage into the new IStorage
+                                    IStorageObject.CopyTo(snbExclude: IntPtr.Zero, pstgDest: IStorageObjectCopy);
+                                    LockBytes.Flush();
+                                    IStorageObjectCopy.Commit(Ole32.STGC.STGC_DEFAULT);
+
+                                    //get the STATSTG of the LockBytes to determine how many bytes were written to it
+                                    LockBytes.Stat(out STATSTG LockBytesStat, Ole32.STATFLAG.STATFLAG_NONAME);
+
+                                    int CbSize = Convert.ToInt32(LockBytesStat.cbSize);
+
+                                    IntPtr LockBytesContentPtr = Marshal.AllocHGlobal(CbSize);
+
+                                    try
+                                    {
+                                        LockBytes.ReadAt(0, LockBytesContentPtr, Convert.ToUInt32(LockBytesStat.cbSize), out _);
+
+                                        byte[] LockBytesContent = new byte[CbSize];
+
+                                        Marshal.Copy(LockBytesContentPtr, LockBytesContent, 0, LockBytesContent.Length);
+
+                                        return new MemoryStream(LockBytesContent);
+                                    }
+                                    finally
+                                    {
+                                        Marshal.FreeHGlobal(LockBytesContentPtr);
+                                    }
+                                }
+                                finally
+                                {
+                                    Marshal.ReleaseComObject(IStorageObjectCopy);
+                                    Marshal.ReleaseComObject(LockBytes);
+                                }
+                            }
+                            finally
+                            {
+                                Marshal.ReleaseComObject(IStorageObject);
+                            }
+                        }
+                        finally
+                        {
+                            Marshal.Release(Medium.unionmember);
+                        }
+                    }
+                case TYMED.TYMED_ISTREAM:
+                    {
+                        //to handle a IStream it needs to be read into a managed byte and
+                        //returned as a MemoryStream
+
+                        IStream IStreamObject = (IStream)Marshal.GetObjectForIUnknown(Medium.unionmember);
+
+                        try
+                        {
+                            //get the STATSTG of the IStream to determine how many bytes are in it
+                            IStreamObject.Stat(out STATSTG iStreamStat, 0);
+
+                            byte[] IStreamContent = new byte[(Convert.ToInt32(iStreamStat.cbSize))];
+
+                            IStreamObject.Read(IStreamContent, IStreamContent.Length, IntPtr.Zero);
+
+                            return new MemoryStream(IStreamContent);
+                        }
+                        finally
+                        {
+                            Marshal.Release(Medium.unionmember);
+                            Marshal.ReleaseComObject(IStreamObject);
+                        }
+                    }
+                case TYMED.TYMED_HGLOBAL:
+                    {
+                        //to handle a HGlobal the exisitng "GetDataFromHGLOBAL" method is invoked via
+                        //reflection
+
+                        try
+                        {
+                            return (MemoryStream)getDataFromHGLOBALMethod.Invoke(oleUnderlyingDataObject, new object[] { DataFormats.GetFormat(Formatetc.cfFormat).Name, Medium.unionmember });
+                        }
+                        finally
+                        {
+                            Marshal.Release(Medium.unionmember);
+                        }
+                    }
+                default:
+                    {
+                        return null;
+                    }
+            }
+        }
+
+        /// <summary>
+        /// Determines whether data stored in this instance is associated with, or can be converted to, the specified format.
+        /// </summary>
+        /// <param name="format">The format for which to check. See <see cref="T:System.Windows.DataFormats"></see> for predefined formats.</param>
+        /// <returns>
+        /// true if data stored in this instance is associated with, or can be converted to, the specified format; otherwise false.
+        /// </returns>
+        public bool GetDataPresent(string format)
+        {
+            return underlyingDataObject.GetDataPresent(format);
+        }
+
+        public sealed class DataPackage : IDisposable
+        {
+            public StorageType ItemType { get; }
+
+            public MemoryStream ContentStream { get; }
+
+            public string Name { get; }
+
+            public DataPackage(string Name, StorageType ItemType, MemoryStream ContentStream)
+            {
+                this.Name = Name;
+                this.ItemType = ItemType;
+                this.ContentStream = ContentStream;
+            }
+
+            public void Dispose()
+            {
+                GC.SuppressFinalize(this);
+                ContentStream?.Dispose();
+            }
+
+            ~DataPackage()
+            {
+                Dispose();
+            }
+        }
+
+        public enum StorageType
+        {
+            File = 0,
+            Directroy = 1
+        }
+    }
+}
diff --git a/Files.Launcher/Win32API.cs b/Files.Launcher/Win32API.cs
index 8d088e3c285a..edca4ebdf5dd 100644
--- a/Files.Launcher/Win32API.cs
+++ b/Files.Launcher/Win32API.cs
@@ -27,6 +27,7 @@ public static Task<T> StartSTATask<T>(Func<T> func)
             var tcs = new TaskCompletionSource<T>();
             Thread thread = new Thread(() =>
             {
+                Ole32.OleInitialize();
                 try
                 {
                     tcs.SetResult(func());
@@ -37,7 +38,15 @@ public static Task<T> StartSTATask<T>(Func<T> func)
                     Program.Logger.Info(ex, ex.Message);
                     //tcs.SetException(e);
                 }
-            });
+                finally
+                {
+                    Ole32.OleUninitialize();
+                }
+            })
+            {
+                IsBackground = true,
+                Priority = ThreadPriority.Normal
+            };
             thread.SetApartmentState(ApartmentState.STA);
             thread.Start();
             return tcs.Task;
diff --git a/Files.Launcher/Win32API_ContextMenu.cs b/Files.Launcher/Win32API_ContextMenu.cs
index 0ada15218878..69f2523018fb 100644
--- a/Files.Launcher/Win32API_ContextMenu.cs
+++ b/Files.Launcher/Win32API_ContextMenu.cs
@@ -8,6 +8,7 @@
 using System.IO;
 using System.Linq;
 using System.Runtime.InteropServices;
+using System.Text.RegularExpressions;
 using System.Threading;
 using System.Threading.Tasks;
 using Vanara.InteropServices;
@@ -440,6 +441,49 @@ public void Dispose()
             }
         }
 
+        public static string GenerateUniquePath(string path)
+        {
+            string uniquePath = path;
+
+            if (File.Exists(path))
+            {
+                string nameWithoutExt = Path.GetFileNameWithoutExtension(path);
+                string extension = Path.GetExtension(path);
+                string directory = Path.GetDirectoryName(path);
+
+                for (ushort count = 1; File.Exists(uniquePath); count++)
+                {
+                    if (Regex.IsMatch(nameWithoutExt, @".*\(\d+\)"))
+                    {
+                        uniquePath = Path.Combine(directory, $"{nameWithoutExt.Substring(0, nameWithoutExt.LastIndexOf("(", StringComparison.InvariantCultureIgnoreCase))}({count}){extension}");
+                    }
+                    else
+                    {
+                        uniquePath = Path.Combine(directory, $"{nameWithoutExt} ({count}){extension}");
+                    }
+                }
+            }
+            else if (Directory.Exists(path))
+            {
+                string directory = Path.GetDirectoryName(path);
+                string Name = Path.GetFileName(path);
+
+                for (ushort Count = 1; Directory.Exists(uniquePath); Count++)
+                {
+                    if (Regex.IsMatch(Name, @".*\(\d+\)"))
+                    {
+                        uniquePath = Path.Combine(directory, $"{Name.Substring(0, Name.LastIndexOf("(", StringComparison.InvariantCultureIgnoreCase))}({Count})");
+                    }
+                    else
+                    {
+                        uniquePath = Path.Combine(directory, $"{Name} ({Count})");
+                    }
+                }
+            }
+
+            return uniquePath;
+        }
+
         // There is usually no need to define Win32 COM interfaces/P-Invoke methods here.
         // The Vanara library contains the definitions for all members of Shell32.dll, User32.dll and more
         // The ones below are due to bugs in the current version of the library and can be removed once fixed
diff --git a/Files/BaseLayout.cs b/Files/BaseLayout.cs
index 811279ef8f2c..a2185b541bef 100644
--- a/Files/BaseLayout.cs
+++ b/Files/BaseLayout.cs
@@ -22,6 +22,7 @@
 using System.Threading.Tasks;
 using Windows.ApplicationModel.Core;
 using Windows.ApplicationModel.DataTransfer;
+using Windows.ApplicationModel.DataTransfer.DragDrop;
 using Windows.Storage;
 using Windows.System;
 using Windows.UI.Core;
@@ -528,47 +529,6 @@ protected virtual void Page_CharacterReceived(CoreWindow sender, CharacterReceiv
             }
         }
 
-        private async void Item_DragStarting(object sender, DragStartingEventArgs e)
-        {
-            List<IStorageItem> selectedStorageItems = new List<IStorageItem>();
-
-            if (sender is DataGridRow dataGridRow)
-            {
-                if (dataGridRow.DataContext is ListedItem item)
-                {
-                    ParentShellPageInstance.SlimContentPage.SelectedItems.Add(item);
-                }
-            }
-
-            foreach (ListedItem item in ParentShellPageInstance.SlimContentPage.SelectedItems)
-            {
-                if (item is ShortcutItem)
-                {
-                    // Can't drag shortcut items
-                    continue;
-                }
-                else if (item.PrimaryItemAttribute == StorageItemTypes.File)
-                {
-                    await ParentShellPageInstance.FilesystemViewModel.GetFileFromPathAsync(item.ItemPath)
-                        .OnSuccess(t => selectedStorageItems.Add(t));
-                }
-                else if (item.PrimaryItemAttribute == StorageItemTypes.Folder)
-                {
-                    await ParentShellPageInstance.FilesystemViewModel.GetFolderFromPathAsync(item.ItemPath)
-                        .OnSuccess(t => selectedStorageItems.Add(t));
-                }
-            }
-
-            if (selectedStorageItems.Count == 0)
-            {
-                e.Cancel = true;
-                return;
-            }
-
-            e.Data.SetStorageItems(selectedStorageItems, false);
-            e.DragUI.SetContentFromDataPackage();
-        }
-
         protected async void FileList_DragItemsStarting(object sender, DragItemsStartingEventArgs e)
         {
             List<IStorageItem> selectedStorageItems = new List<IStorageItem>();
@@ -620,16 +580,6 @@ private void Item_DragLeave(object sender, DragEventArgs e)
         protected async void Item_DragOver(object sender, DragEventArgs e)
         {
             ListedItem item = GetItemFromElement(sender);
-
-            if (item is null && sender is GridViewItem gvi)
-            {
-                item = gvi.Content as ListedItem;
-            }
-            else if (item is null && sender is ListViewItem lvi)
-            {
-                item = lvi.Content as ListedItem;
-            }
-
             if (item is null)
             {
                 return;
@@ -661,11 +611,10 @@ protected async void Item_DragOver(object sender, DragEventArgs e)
                 {
                     draggedItems = await e.DataView.GetStorageItemsAsync();
                 }
-                catch (Exception ex) when ((uint)ex.HResult == 0x80040064)
+                catch (Exception ex) when ((uint)ex.HResult == 0x80040064 || (uint)ex.HResult == 0x8004006A)
                 {
-                    e.AcceptedOperation = DataPackageOperation.None;
-                    deferral.Complete();
-                    return;
+                    // Handled by FTP
+                    draggedItems = new List<IStorageItem>();
                 }
                 catch (Exception ex)
                 {
@@ -676,26 +625,44 @@ protected async void Item_DragOver(object sender, DragEventArgs e)
                 }
 
                 e.Handled = true;
-                e.DragUIOverride.IsCaptionVisible = true;
-
                 if (InstanceViewModel.IsPageTypeSearchResults || draggedItems.Any(draggedItem => draggedItem.Path == item.ItemPath))
                 {
                     e.AcceptedOperation = DataPackageOperation.None;
                 }
-                else if (item.IsExecutable)
+                else if (!draggedItems.Any())
                 {
-                    e.DragUIOverride.Caption = $"{"OpenItemsWithCaptionText".GetLocalized()} {item.ItemName}";
-                    e.AcceptedOperation = DataPackageOperation.Link;
-                } // Items from the same drive as this folder are dragged into this folder, so we move the items instead of copy
-                else if (draggedItems.AreItemsInSameDrive(item.ItemPath))
-                {
-                    e.DragUIOverride.Caption = string.Format("MoveToFolderCaptionText".GetLocalized(), item.ItemName);
-                    e.AcceptedOperation = DataPackageOperation.Move;
+                    e.DragUIOverride.IsCaptionVisible = true;
+                    e.DragUIOverride.Caption = string.Format("CopyToFolderCaptionText".GetLocalized(), item.ItemName);
+                    e.AcceptedOperation = DataPackageOperation.Copy;
                 }
                 else
                 {
-                    e.DragUIOverride.Caption = string.Format("CopyToFolderCaptionText".GetLocalized(), item.ItemName);
-                    e.AcceptedOperation = DataPackageOperation.Copy;
+                    e.DragUIOverride.IsCaptionVisible = true;
+                    if (item.IsExecutable)
+                    {
+                        e.DragUIOverride.Caption = $"{"OpenItemsWithCaptionText".GetLocalized()} {item.ItemName}";
+                        e.AcceptedOperation = DataPackageOperation.Link;
+                    } // Items from the same drive as this folder are dragged into this folder, so we move the items instead of copy
+                    else if (e.Modifiers.HasFlag(DragDropModifiers.Control))
+                    {
+                        e.DragUIOverride.Caption = string.Format("CopyToFolderCaptionText".GetLocalized(), item.ItemName);
+                        e.AcceptedOperation = DataPackageOperation.Copy;
+                    }
+                    else if (e.Modifiers.HasFlag(DragDropModifiers.Shift))
+                    {
+                        e.DragUIOverride.Caption = string.Format("MoveToFolderCaptionText".GetLocalized(), item.ItemName);
+                        e.AcceptedOperation = DataPackageOperation.Move;
+                    }
+                    else if (draggedItems.AreItemsInSameDrive(item.ItemPath))
+                    {
+                        e.DragUIOverride.Caption = string.Format("MoveToFolderCaptionText".GetLocalized(), item.ItemName);
+                        e.AcceptedOperation = DataPackageOperation.Move;
+                    }
+                    else
+                    {
+                        e.DragUIOverride.Caption = string.Format("CopyToFolderCaptionText".GetLocalized(), item.ItemName);
+                        e.AcceptedOperation = DataPackageOperation.Copy;
+                    }
                 }
             }
 
@@ -709,10 +676,10 @@ protected async void Item_Drop(object sender, DragEventArgs e)
             e.Handled = true;
             dragOverItem = null; // Reset dragged over item
 
-            ListedItem rowItem = GetItemFromElement(sender);
-            if (rowItem != null)
+            ListedItem item = GetItemFromElement(sender);
+            if (item != null)
             {
-                await ParentShellPageInstance.FilesystemHelpers.PerformOperationTypeAsync(e.AcceptedOperation, e.DataView, (rowItem as ShortcutItem)?.TargetPath ?? rowItem.ItemPath, false, true, rowItem.IsExecutable);
+                await ParentShellPageInstance.FilesystemHelpers.PerformOperationTypeAsync(e.AcceptedOperation, e.DataView, (item as ShortcutItem)?.TargetPath ?? item.ItemPath, false, true, item.IsExecutable);
             }
             deferral.Complete();
         }
@@ -723,11 +690,10 @@ protected void InitializeDrag(UIElement element)
             if (item != null)
             {
                 element.AllowDrop = false;
-                element.DragStarting -= Item_DragStarting;
                 element.DragOver -= Item_DragOver;
                 element.DragLeave -= Item_DragLeave;
                 element.Drop -= Item_Drop;
-                if (item.PrimaryItemAttribute == StorageItemTypes.Folder || (item.IsShortcutItem && (Path.GetExtension((item as ShortcutItem).TargetPath)?.Contains("exe") ?? false)))
+                if (item.PrimaryItemAttribute == StorageItemTypes.Folder || item.IsExecutable)
                 {
                     element.AllowDrop = true;
                     element.DragOver += Item_DragOver;
@@ -740,7 +706,6 @@ protected void InitializeDrag(UIElement element)
         protected void UninitializeDrag(UIElement element)
         {
             element.AllowDrop = false;
-            element.DragStarting -= Item_DragStarting;
             element.DragOver -= Item_DragOver;
             element.DragLeave -= Item_DragLeave;
             element.Drop -= Item_Drop;
@@ -753,9 +718,9 @@ protected void UninitializeDrag(UIElement element)
 
         public abstract void Dispose();
 
-        protected void ItemsLayout_DragEnter(object sender, DragEventArgs e)
+        protected void ItemsLayout_DragOver(object sender, DragEventArgs e)
         {
-            CommandsViewModel?.DragEnterCommand?.Execute(e);
+            CommandsViewModel?.DragOverCommand?.Execute(e);
         }
 
         protected void ItemsLayout_Drop(object sender, DragEventArgs e)
diff --git a/Files/Filesystem/FilesystemOperations/FilesystemOperations.cs b/Files/Filesystem/FilesystemOperations/FilesystemOperations.cs
index 6c20b4dfaa58..cc53f8e602e9 100644
--- a/Files/Filesystem/FilesystemOperations/FilesystemOperations.cs
+++ b/Files/Filesystem/FilesystemOperations/FilesystemOperations.cs
@@ -124,7 +124,7 @@ public async Task<IStorageHistory> CopyAsync(IStorageItemWithPath source,
                                                      IProgress<FileSystemStatusCode> errorCode,
                                                      CancellationToken cancellationToken)
         {
-            if (associatedInstance.FilesystemViewModel.WorkingDirectory.StartsWith(App.AppSettings.RecycleBinPath))
+            if (destination.StartsWith(App.AppSettings.RecycleBinPath))
             {
                 errorCode?.Report(FileSystemStatusCode.Unauthorized);
                 progress?.Report(100.0f);
@@ -264,7 +264,7 @@ await DialogDisplayHelper.ShowDialogAsync(
                 }
             }
 
-            if (Path.GetDirectoryName(destination) == associatedInstance.FilesystemViewModel.WorkingDirectory)
+            if (Path.GetDirectoryName(destination) == associatedInstance.FilesystemViewModel.WorkingDirectory.TrimPath())
             {
                 await Windows.ApplicationModel.Core.CoreApplication.MainView.DispatcherQueue.EnqueueAsync(async () =>
                 {
@@ -331,7 +331,7 @@ public async Task<IStorageHistory> MoveAsync(IStorageItemWithPath source,
                 return await CopyAsync(source, destination, collision, progress, errorCode, cancellationToken);
             }
 
-            if (associatedInstance.FilesystemViewModel.WorkingDirectory.StartsWith(App.AppSettings.RecycleBinPath))
+            if (destination.StartsWith(App.AppSettings.RecycleBinPath))
             {
                 errorCode?.Report(FileSystemStatusCode.Unauthorized);
                 progress?.Report(100.0f);
@@ -469,7 +469,7 @@ await DialogDisplayHelper.ShowDialogAsync(
                 errorCode?.Report(fsResult.ErrorCode);
             }
 
-            if (Path.GetDirectoryName(destination) == associatedInstance.FilesystemViewModel.WorkingDirectory)
+            if (Path.GetDirectoryName(destination) == associatedInstance.FilesystemViewModel.WorkingDirectory.TrimPath())
             {
                 await Windows.ApplicationModel.Core.CoreApplication.MainView.DispatcherQueue.EnqueueAsync(async () =>
                 {
diff --git a/Files/Filesystem/FilesystemOperations/Helpers/FilesystemHelpers.cs b/Files/Filesystem/FilesystemOperations/Helpers/FilesystemHelpers.cs
index ecb876941e02..0f203ac39fd0 100644
--- a/Files/Filesystem/FilesystemOperations/Helpers/FilesystemHelpers.cs
+++ b/Files/Filesystem/FilesystemOperations/Helpers/FilesystemHelpers.cs
@@ -1,4 +1,5 @@
-using Files.DataModels;
+using Files.Common;
+using Files.DataModels;
 using Files.Dialogs;
 using Files.Enums;
 using Files.Extensions;
@@ -16,6 +17,7 @@
 using System.Text.RegularExpressions;
 using System.Threading;
 using System.Threading.Tasks;
+using Windows.ApplicationModel.AppService;
 using Windows.ApplicationModel.DataTransfer;
 using Windows.Foundation.Collections;
 using Windows.Graphics.Imaging;
@@ -471,6 +473,10 @@ public async Task<ReturnResult> PerformOperationTypeAsync(DataPackageOperation o
                 {
                     return default;
                 }
+                if (destination.StartsWith(App.AppSettings.RecycleBinPath))
+                {
+                    return await RecycleItemsFromClipboard(packageView, destination, showDialog, registerHistory);
+                }
                 else if (operation.HasFlag(DataPackageOperation.Copy))
                 {
                     return await CopyItemsFromClipboard(packageView, destination, showDialog, registerHistory);
@@ -674,6 +680,36 @@ public async Task<ReturnResult> CopyItemAsync(IStorageItemWithPath source, strin
             return returnStatus;
         }
 
+        public async Task<ReturnResult> RecycleItemsFromClipboard(DataPackageView packageView, string destination, bool showDialog, bool registerHistory)
+        {
+            if (!packageView.Contains(StandardDataFormats.StorageItems))
+            {
+                // Happens if you copy some text and then you Ctrl+V in Files
+                return ReturnResult.BadArgumentException;
+            }
+
+            IReadOnlyList<IStorageItem> source;
+            try
+            {
+                source = await packageView.GetStorageItemsAsync();
+            }
+            catch (Exception ex) when ((uint)ex.HResult == 0x80040064 || (uint)ex.HResult == 0x8004006A)
+            {
+                // Not supported
+                return ReturnResult.Failed;
+            }
+            catch (Exception ex)
+            {
+                App.Logger.Warn(ex, ex.Message);
+                return ReturnResult.UnknownException;
+            }
+            ReturnResult returnStatus = ReturnResult.InProgress;
+
+            returnStatus = await DeleteItemsAsync(source, showDialog, false, registerHistory);
+
+            return returnStatus;
+        }
+
         public async Task<ReturnResult> CopyItemsFromClipboard(DataPackageView packageView, string destination, bool showDialog, bool registerHistory)
         {
             if (packageView.Contains(StandardDataFormats.StorageItems))
@@ -683,9 +719,18 @@ public async Task<ReturnResult> CopyItemsFromClipboard(DataPackageView packageVi
                 {
                     source = await packageView.GetStorageItemsAsync();
                 }
-                catch (Exception ex) when ((uint)ex.HResult == 0x80040064)
+                catch (Exception ex) when ((uint)ex.HResult == 0x80040064 || (uint)ex.HResult == 0x8004006A)
                 {
-                    return ReturnResult.UnknownException;
+                    if (associatedInstance.ServiceConnection != null)
+                    {
+                        var (status, response) = await associatedInstance.ServiceConnection.SendMessageForResponseAsync(new ValueSet() {
+                            { "Arguments", "FileOperation" },
+                            { "fileop", "DragDrop" },
+                            { "droptext", "DragDropWindowText".GetLocalized() },
+                            { "droppath", associatedInstance.FilesystemViewModel.WorkingDirectory } });
+                        return (status == AppServiceResponseStatus.Success && response.Get("Success", false)) ? ReturnResult.Success : ReturnResult.Failed;
+                    }
+                    return ReturnResult.Failed;
                 }
                 catch (Exception ex)
                 {
@@ -733,7 +778,6 @@ public async Task<ReturnResult> CopyItemsFromClipboard(DataPackageView packageVi
             }
 
             // Happens if you copy some text and then you Ctrl+V in Files
-            // Should this be done in ModernShellPage?
             return ReturnResult.BadArgumentException;
         }
 
@@ -918,7 +962,6 @@ public async Task<ReturnResult> MoveItemsFromClipboard(DataPackageView packageVi
             if (!packageView.Contains(StandardDataFormats.StorageItems))
             {
                 // Happens if you copy some text and then you Ctrl+V in Files
-                // Should this be done in ModernShellPage?
                 return ReturnResult.BadArgumentException;
             }
 
@@ -927,9 +970,10 @@ public async Task<ReturnResult> MoveItemsFromClipboard(DataPackageView packageVi
             {
                 source = await packageView.GetStorageItemsAsync();
             }
-            catch (Exception ex) when ((uint)ex.HResult == 0x80040064)
+            catch (Exception ex) when ((uint)ex.HResult == 0x80040064 || (uint)ex.HResult == 0x8004006A)
             {
-                return ReturnResult.UnknownException;
+                // Not supported
+                return ReturnResult.Failed;
             }
             catch (Exception ex)
             {
diff --git a/Files/Filesystem/ListedItem.cs b/Files/Filesystem/ListedItem.cs
index 6ae246d7a963..917ae6a915fc 100644
--- a/Files/Filesystem/ListedItem.cs
+++ b/Files/Filesystem/ListedItem.cs
@@ -314,7 +314,7 @@ public override string ToString()
         public bool IsLibraryItem => this is LibraryItem;
         public bool IsLinkItem => IsShortcutItem && ((ShortcutItem)this).IsUrl;
 
-        public virtual bool IsExecutable => Path.GetExtension(ItemPath)?.Contains("exe") ?? false;
+        public virtual bool IsExecutable => Path.GetExtension(ItemPath)?.ToLower() == ".exe";
         public bool IsPinned => App.SidebarPinnedController.Model.FavoriteItems.Contains(itemPath);
 
         private StorageFile itemFile;
@@ -382,7 +382,7 @@ public ShortcutItem() : base()
         public string WorkingDirectory { get; set; }
         public bool RunAsAdmin { get; set; }
         public bool IsUrl { get; set; }
-        public override bool IsExecutable => Path.GetExtension(TargetPath)?.Contains("exe") ?? false;
+        public override bool IsExecutable => Path.GetExtension(TargetPath)?.ToLower() == ".exe";
     }
 
     public class LibraryItem : ListedItem
diff --git a/Files/Filesystem/StorageFileHelpers/StorageFileExtensions.cs b/Files/Filesystem/StorageFileHelpers/StorageFileExtensions.cs
index 06c51167846a..b975ecffc706 100644
--- a/Files/Filesystem/StorageFileHelpers/StorageFileExtensions.cs
+++ b/Files/Filesystem/StorageFileHelpers/StorageFileExtensions.cs
@@ -1,6 +1,7 @@
 using Files.Common;
 using Files.DataModels.NavigationControlItems;
 using Files.Extensions;
+using Files.Helpers;
 using Files.UserControls;
 using Files.ViewModels;
 using Files.Views;
@@ -257,9 +258,9 @@ public static bool AreItemsInSameDrive(this IEnumerable<IStorageItem> storageIte
             try
             {
                 return storageItems.Any(storageItem =>
-               Path.GetPathRoot(storageItem.Path).Equals(
-                   Path.GetPathRoot(destinationPath),
-                   StringComparison.OrdinalIgnoreCase));
+                    Path.GetPathRoot(storageItem.Path).Equals(
+                        Path.GetPathRoot(destinationPath),
+                        StringComparison.OrdinalIgnoreCase));
             }
             catch
             {
@@ -272,8 +273,8 @@ public static bool AreItemsAlreadyInFolder(this IEnumerable<IStorageItem> storag
             try
             {
                 return storageItems.All(storageItem =>
-                Directory.GetParent(storageItem.Path).FullName.Equals(
-                    destinationPath, StringComparison.OrdinalIgnoreCase));
+                    Path.GetDirectoryName(storageItem.Path).Equals(
+                        destinationPath.TrimPath(), StringComparison.OrdinalIgnoreCase));
             }
             catch
             {
diff --git a/Files/Helpers/PathNormalization.cs b/Files/Helpers/PathNormalization.cs
index 8079147d2005..0c2db2787401 100644
--- a/Files/Helpers/PathNormalization.cs
+++ b/Files/Helpers/PathNormalization.cs
@@ -3,7 +3,7 @@
 
 namespace Files.Helpers
 {
-    public class PathNormalization
+    public static class PathNormalization
     {
         public static string GetPathRoot(string path)
         {
@@ -61,6 +61,11 @@ public static string NormalizePath(string path)
             }
         }
 
+        public static string TrimPath(this string path)
+        {
+            return path?.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
+        }
+
         public static string GetParentDir(string path)
         {
             if (string.IsNullOrEmpty(path))
diff --git a/Files/Interacts/BaseLayoutCommandImplementationModel.cs b/Files/Interacts/BaseLayoutCommandImplementationModel.cs
index 090abbfed4d0..7c9329f0b0ef 100644
--- a/Files/Interacts/BaseLayoutCommandImplementationModel.cs
+++ b/Files/Interacts/BaseLayoutCommandImplementationModel.cs
@@ -12,6 +12,7 @@
 using System.IO;
 using System.Linq;
 using Windows.ApplicationModel.DataTransfer;
+using Windows.ApplicationModel.DataTransfer.DragDrop;
 using Windows.Foundation;
 using Windows.Foundation.Collections;
 using Windows.Storage;
@@ -492,7 +493,7 @@ public virtual void GridViewSizeIncrease(KeyboardAcceleratorInvokedEventArgs e)
             }
         }
 
-        public virtual async void DragEnter(DragEventArgs e)
+        public virtual async void DragOver(DragEventArgs e)
         {
             var deferral = e.GetDeferral();
 
@@ -500,49 +501,72 @@ public virtual async void DragEnter(DragEventArgs e)
             if (e.DataView.Contains(StandardDataFormats.StorageItems))
             {
                 e.Handled = true;
-                e.DragUIOverride.IsCaptionVisible = true;
-                IEnumerable<IStorageItem> draggedItems = new List<IStorageItem>();
+                IEnumerable<IStorageItem> draggedItems;
                 try
                 {
                     draggedItems = await e.DataView.GetStorageItemsAsync();
                 }
-                catch (Exception dropEx) when ((uint)dropEx.HResult == 0x80040064)
+                catch (Exception ex) when ((uint)ex.HResult == 0x80040064 || (uint)ex.HResult == 0x8004006A)
                 {
-                    if (associatedInstance.ServiceConnection != null)
-                    {
-                        await associatedInstance.ServiceConnection.SendMessageAsync(new ValueSet() {
-                            { "Arguments", "FileOperation" },
-                            { "fileop", "DragDrop" },
-                            { "droptext", "DragDropWindowText".GetLocalized() },
-                            { "droppath", associatedInstance.FilesystemViewModel.WorkingDirectory } });
-                    }
+                    // Handled by FTP
+                    draggedItems = new List<IStorageItem>();
                 }
                 catch (Exception ex)
                 {
                     App.Logger.Warn(ex, ex.Message);
-                }
-                if (!draggedItems.Any())
-                {
                     e.AcceptedOperation = DataPackageOperation.None;
                     deferral.Complete();
                     return;
                 }
 
-                var folderName = System.IO.Path.GetFileName(associatedInstance.FilesystemViewModel.WorkingDirectory);
+                var pwd = associatedInstance.FilesystemViewModel.WorkingDirectory.TrimPath();
+                var folderName = (Path.IsPathRooted(pwd) && Path.GetPathRoot(pwd) == pwd) ? Path.GetPathRoot(pwd) : Path.GetFileName(pwd);
                 // As long as one file doesn't already belong to this folder
-                if (associatedInstance.InstanceViewModel.IsPageTypeSearchResults || draggedItems.All(x => Path.GetDirectoryName(x.Path) == associatedInstance.FilesystemViewModel.WorkingDirectory))
+                if (associatedInstance.InstanceViewModel.IsPageTypeSearchResults || (draggedItems.Any() && draggedItems.AreItemsAlreadyInFolder(associatedInstance.FilesystemViewModel.WorkingDirectory)))
                 {
                     e.AcceptedOperation = DataPackageOperation.None;
                 }
-                else if (draggedItems.AreItemsInSameDrive(associatedInstance.FilesystemViewModel.WorkingDirectory))
+                else if (!draggedItems.Any())
                 {
-                    e.DragUIOverride.Caption = string.Format("MoveToFolderCaptionText".GetLocalized(), folderName);
-                    e.AcceptedOperation = DataPackageOperation.Move;
+                    if (pwd.StartsWith(App.AppSettings.RecycleBinPath))
+                    {
+                        e.AcceptedOperation = DataPackageOperation.None;
+                    }
+                    else
+                    {
+                        e.DragUIOverride.IsCaptionVisible = true;
+                        e.DragUIOverride.Caption = string.Format("CopyToFolderCaptionText".GetLocalized(), folderName);
+                        e.AcceptedOperation = DataPackageOperation.Copy;
+                    }
                 }
                 else
                 {
-                    e.DragUIOverride.Caption = string.Format("CopyToFolderCaptionText".GetLocalized(), folderName);
-                    e.AcceptedOperation = DataPackageOperation.Copy;
+                    e.DragUIOverride.IsCaptionVisible = true;
+                    if (pwd.StartsWith(App.AppSettings.RecycleBinPath))
+                    {
+                        e.DragUIOverride.Caption = string.Format("MoveToFolderCaptionText".GetLocalized(), folderName);
+                        e.AcceptedOperation = DataPackageOperation.Move;
+                    }
+                    else if (e.Modifiers.HasFlag(DragDropModifiers.Control))
+                    {
+                        e.DragUIOverride.Caption = string.Format("CopyToFolderCaptionText".GetLocalized(), folderName);
+                        e.AcceptedOperation = DataPackageOperation.Copy;
+                    }
+                    else if (e.Modifiers.HasFlag(DragDropModifiers.Shift))
+                    {
+                        e.DragUIOverride.Caption = string.Format("MoveToFolderCaptionText".GetLocalized(), folderName);
+                        e.AcceptedOperation = DataPackageOperation.Move;
+                    }
+                    else if (draggedItems.AreItemsInSameDrive(associatedInstance.FilesystemViewModel.WorkingDirectory))
+                    {
+                        e.DragUIOverride.Caption = string.Format("MoveToFolderCaptionText".GetLocalized(), folderName);
+                        e.AcceptedOperation = DataPackageOperation.Move;
+                    }
+                    else
+                    {
+                        e.DragUIOverride.Caption = string.Format("CopyToFolderCaptionText".GetLocalized(), folderName);
+                        e.AcceptedOperation = DataPackageOperation.Copy;
+                    }
                 }
             }
 
diff --git a/Files/Interacts/BaseLayoutCommandsViewModel.cs b/Files/Interacts/BaseLayoutCommandsViewModel.cs
index c9df5e453a47..2f00573d142e 100644
--- a/Files/Interacts/BaseLayoutCommandsViewModel.cs
+++ b/Files/Interacts/BaseLayoutCommandsViewModel.cs
@@ -66,7 +66,7 @@ private void InitializeCommands()
             PointerWheelChangedCommand = new RelayCommand<PointerRoutedEventArgs>(commandsModel.PointerWheelChanged);
             GridViewSizeDecreaseCommand = new RelayCommand<KeyboardAcceleratorInvokedEventArgs>(commandsModel.GridViewSizeDecrease);
             GridViewSizeIncreaseCommand = new RelayCommand<KeyboardAcceleratorInvokedEventArgs>(commandsModel.GridViewSizeIncrease);
-            DragEnterCommand = new RelayCommand<DragEventArgs>(commandsModel.DragEnter);
+            DragOverCommand = new RelayCommand<DragEventArgs>(commandsModel.DragOver);
             DropCommand = new RelayCommand<DragEventArgs>(commandsModel.Drop);
             RefreshCommand = new RelayCommand<RoutedEventArgs>(commandsModel.RefreshItems);
             SearchUnindexedItems = new RelayCommand<RoutedEventArgs>(commandsModel.SearchUnindexedItems);
@@ -149,7 +149,7 @@ private void InitializeCommands()
 
         public ICommand GridViewSizeIncreaseCommand { get; private set; }
 
-        public ICommand DragEnterCommand { get; private set; }
+        public ICommand DragOverCommand { get; private set; }
 
         public ICommand DropCommand { get; private set; }
 
diff --git a/Files/Interacts/IBaseLayoutCommandImplementationModel.cs b/Files/Interacts/IBaseLayoutCommandImplementationModel.cs
index 23f81e71c536..8ba7d06a561a 100644
--- a/Files/Interacts/IBaseLayoutCommandImplementationModel.cs
+++ b/Files/Interacts/IBaseLayoutCommandImplementationModel.cs
@@ -79,7 +79,7 @@ public interface IBaseLayoutCommandImplementationModel : IDisposable
 
         void GridViewSizeIncrease(KeyboardAcceleratorInvokedEventArgs e);
 
-        void DragEnter(DragEventArgs e);
+        void DragOver(DragEventArgs e);
 
         void Drop(DragEventArgs e);
 
diff --git a/Files/Strings/en-US/Resources.resw b/Files/Strings/en-US/Resources.resw
index b43829ac5e05..93f2ab512533 100644
--- a/Files/Strings/en-US/Resources.resw
+++ b/Files/Strings/en-US/Resources.resw
@@ -1401,9 +1401,6 @@
   <data name="SettingsDateFormatsTip.AutomationProperties.Name" xml:space="preserve">
     <value>Learn more about date formats</value>
   </data>
-  <data name="DragDropWindowText" xml:space="preserve">
-    <value>Drop here</value>
-  </data>
   <data name="NavSearchButton.AutomationProperties.Name" xml:space="preserve">
     <value>Search</value>
   </data>
diff --git a/Files/UserControls/SidebarControl.xaml.cs b/Files/UserControls/SidebarControl.xaml.cs
index 5cdd638c722e..5902b23e6e39 100644
--- a/Files/UserControls/SidebarControl.xaml.cs
+++ b/Files/UserControls/SidebarControl.xaml.cs
@@ -15,6 +15,7 @@
 using System.Threading;
 using System.Windows.Input;
 using Windows.ApplicationModel.DataTransfer;
+using Windows.ApplicationModel.DataTransfer.DragDrop;
 using Windows.Storage;
 using Windows.System;
 using Windows.UI.Core;
@@ -478,11 +479,10 @@ private async void NavigationViewLocationItem_DragOver(object sender, DragEventA
                 {
                     storageItems = await e.DataView.GetStorageItemsAsync();
                 }
-                catch (Exception ex) when ((uint)ex.HResult == 0x80040064)
+                catch (Exception ex) when ((uint)ex.HResult == 0x80040064 || (uint)ex.HResult == 0x8004006A)
                 {
-                    e.AcceptedOperation = DataPackageOperation.None;
-                    deferral.Complete();
-                    return;
+                    // Handled by FTP
+                    storageItems = new List<IStorageItem>();
                 }
                 catch (Exception ex)
                 {
@@ -492,17 +492,43 @@ private async void NavigationViewLocationItem_DragOver(object sender, DragEventA
                     return;
                 }
 
-                if (storageItems.Count == 0 ||
-                    string.IsNullOrEmpty(locationItem.Path) ||
-                    locationItem.Path.Equals(App.AppSettings.RecycleBinPath, StringComparison.OrdinalIgnoreCase) ||
-                    storageItems.AreItemsAlreadyInFolder(locationItem.Path))
+                if (string.IsNullOrEmpty(locationItem.Path) ||
+                    (storageItems.Any() && storageItems.AreItemsAlreadyInFolder(locationItem.Path)))
                 {
                     e.AcceptedOperation = DataPackageOperation.None;
                 }
+                else if (!storageItems.Any())
+                {
+                    if (locationItem.Path.StartsWith(App.AppSettings.RecycleBinPath))
+                    {
+                        e.AcceptedOperation = DataPackageOperation.None;
+                    }
+                    else
+                    {
+                        e.DragUIOverride.IsCaptionVisible = true;
+                        e.DragUIOverride.Caption = string.Format("CopyToFolderCaptionText".GetLocalized(), locationItem.Text);
+                        e.AcceptedOperation = DataPackageOperation.Copy;
+                    }
+                }
                 else
                 {
                     e.DragUIOverride.IsCaptionVisible = true;
-                    if (storageItems.AreItemsInSameDrive(locationItem.Path) || locationItem.IsDefaultLocation)
+                    if (locationItem.Path.StartsWith(App.AppSettings.RecycleBinPath))
+                    {
+                        e.DragUIOverride.Caption = string.Format("MoveToFolderCaptionText".GetLocalized(), locationItem.Text);
+                        e.AcceptedOperation = DataPackageOperation.Move;
+                    }
+                    else if (e.Modifiers.HasFlag(DragDropModifiers.Control))
+                    {
+                        e.DragUIOverride.Caption = string.Format("CopyToFolderCaptionText".GetLocalized(), locationItem.Text);
+                        e.AcceptedOperation = DataPackageOperation.Copy;
+                    }
+                    else if (e.Modifiers.HasFlag(DragDropModifiers.Shift))
+                    {
+                        e.DragUIOverride.Caption = string.Format("MoveToFolderCaptionText".GetLocalized(), locationItem.Text);
+                        e.AcceptedOperation = DataPackageOperation.Move;
+                    }
+                    else if (storageItems.AreItemsInSameDrive(locationItem.Path) || locationItem.IsDefaultLocation)
                     {
                         e.AcceptedOperation = DataPackageOperation.Move;
                         e.DragUIOverride.Caption = string.Format("MoveToFolderCaptionText".GetLocalized(), locationItem.Text);
@@ -594,11 +620,10 @@ private async void NavigationViewDriveItem_DragOver(object sender, DragEventArgs
             {
                 storageItems = await e.DataView.GetStorageItemsAsync();
             }
-            catch (Exception ex) when ((uint)ex.HResult == 0x80040064)
+            catch (Exception ex) when ((uint)ex.HResult == 0x80040064 || (uint)ex.HResult == 0x8004006A)
             {
-                e.AcceptedOperation = DataPackageOperation.None;
-                deferral.Complete();
-                return;
+                // Handled by FTP
+                storageItems = new List<IStorageItem>();
             }
             catch (Exception ex)
             {
@@ -608,16 +633,31 @@ private async void NavigationViewDriveItem_DragOver(object sender, DragEventArgs
                 return;
             }
 
-            if (storageItems.Count == 0 ||
-                "DriveCapacityUnknown".GetLocalized().Equals(driveItem.SpaceText, StringComparison.OrdinalIgnoreCase) ||
-                storageItems.AreItemsAlreadyInFolder(driveItem.Path))
+            if ("DriveCapacityUnknown".GetLocalized().Equals(driveItem.SpaceText, StringComparison.OrdinalIgnoreCase) ||
+                (storageItems.Any() && storageItems.AreItemsAlreadyInFolder(driveItem.Path)))
             {
                 e.AcceptedOperation = DataPackageOperation.None;
             }
+            else if (!storageItems.Any())
+            {
+                e.DragUIOverride.IsCaptionVisible = true;
+                e.DragUIOverride.Caption = string.Format("CopyToFolderCaptionText".GetLocalized(), driveItem.Text);
+                e.AcceptedOperation = DataPackageOperation.Copy;
+            }
             else
             {
                 e.DragUIOverride.IsCaptionVisible = true;
-                if (storageItems.AreItemsInSameDrive(driveItem.Path))
+                if (e.Modifiers.HasFlag(DragDropModifiers.Control))
+                {
+                    e.DragUIOverride.Caption = string.Format("CopyToFolderCaptionText".GetLocalized(), driveItem.Text);
+                    e.AcceptedOperation = DataPackageOperation.Copy;
+                }
+                else if (e.Modifiers.HasFlag(DragDropModifiers.Shift))
+                {
+                    e.DragUIOverride.Caption = string.Format("MoveToFolderCaptionText".GetLocalized(), driveItem.Text);
+                    e.AcceptedOperation = DataPackageOperation.Move;
+                }
+                else if (storageItems.AreItemsInSameDrive(driveItem.Path))
                 {
                     e.AcceptedOperation = DataPackageOperation.Move;
                     e.DragUIOverride.Caption = string.Format("MoveToFolderCaptionText".GetLocalized(), driveItem.Text);
diff --git a/Files/ViewModels/NavToolbarViewModel.cs b/Files/ViewModels/NavToolbarViewModel.cs
index 3c0f01f99209..424b88b8d437 100644
--- a/Files/ViewModels/NavToolbarViewModel.cs
+++ b/Files/ViewModels/NavToolbarViewModel.cs
@@ -258,7 +258,7 @@ public async void PathBoxItem_DragOver(object sender, DragEventArgs e)
             {
                 storageItems = await e.DataView.GetStorageItemsAsync();
             }
-            catch (Exception ex) when ((uint)ex.HResult == 0x80040064)
+            catch (Exception ex) when ((uint)ex.HResult == 0x80040064 || (uint)ex.HResult == 0x8004006A)
             {
                 e.AcceptedOperation = DataPackageOperation.None;
                 deferral.Complete();
@@ -273,9 +273,9 @@ public async void PathBoxItem_DragOver(object sender, DragEventArgs e)
             }
 
             if (!storageItems.Any(storageItem =>
-            storageItem.Path.Replace(pathBoxItem.Path, string.Empty).
-            Trim(Path.DirectorySeparatorChar).
-            Contains(Path.DirectorySeparatorChar)))
+                storageItem.Path.Replace(pathBoxItem.Path, string.Empty).
+                Trim(Path.DirectorySeparatorChar).
+                Contains(Path.DirectorySeparatorChar)))
             {
                 e.AcceptedOperation = DataPackageOperation.None;
             }
diff --git a/Files/Views/LayoutModes/ColumnViewBase.xaml b/Files/Views/LayoutModes/ColumnViewBase.xaml
index 3d1c6c259f03..014642874cbd 100644
--- a/Files/Views/LayoutModes/ColumnViewBase.xaml
+++ b/Files/Views/LayoutModes/ColumnViewBase.xaml
@@ -1277,8 +1277,8 @@
                     CanDragItems="{x:Bind InstanceViewModel.IsPageTypeSearchResults, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}"
                     ChoosingItemContainer="FileList_ChoosingItemContainer"
                     DoubleTapped="FileList_DoubleTapped"
-                    DragEnter="ItemsLayout_DragEnter"
                     DragItemsStarting="FileList_DragItemsStarting"
+                    DragOver="ItemsLayout_DragOver"
                     Drop="ItemsLayout_Drop"
                     Holding="FileList_Holding"
                     IsDoubleTapEnabled="True"
diff --git a/Files/Views/LayoutModes/ColumnViewBase.xaml.cs b/Files/Views/LayoutModes/ColumnViewBase.xaml.cs
index bf0ea13efaac..c78db9d1adaf 100644
--- a/Files/Views/LayoutModes/ColumnViewBase.xaml.cs
+++ b/Files/Views/LayoutModes/ColumnViewBase.xaml.cs
@@ -305,7 +305,7 @@ public override void ResetItemOpacity()
 
         protected override ListedItem GetItemFromElement(object element)
         {
-            return (element as ListViewItem).DataContext as ListedItem;
+            return (element as ListViewItem).DataContext as ListedItem ?? (element as ListViewItem).Content as ListedItem;
         }
 
         #region IDisposable
diff --git a/Files/Views/LayoutModes/ColumnViewBrowser.xaml b/Files/Views/LayoutModes/ColumnViewBrowser.xaml
index e4ee56c76bc9..8761d3afcd82 100644
--- a/Files/Views/LayoutModes/ColumnViewBrowser.xaml
+++ b/Files/Views/LayoutModes/ColumnViewBrowser.xaml
@@ -1281,8 +1281,8 @@
                                 CanDragItems="{x:Bind InstanceViewModel.IsPageTypeSearchResults, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}"
                                 ChoosingItemContainer="FileList_ChoosingItemContainer"
                                 DoubleTapped="FileList_DoubleTapped"
-                                DragEnter="ItemsLayout_DragEnter"
                                 DragItemsStarting="FileList_DragItemsStarting"
+                                DragOver="ItemsLayout_DragOver"
                                 Drop="ItemsLayout_Drop"
                                 Holding="FileList_Holding"
                                 IsDoubleTapEnabled="True"
diff --git a/Files/Views/LayoutModes/ColumnViewBrowser.xaml.cs b/Files/Views/LayoutModes/ColumnViewBrowser.xaml.cs
index 7e04b7e28408..036d5a19066f 100644
--- a/Files/Views/LayoutModes/ColumnViewBrowser.xaml.cs
+++ b/Files/Views/LayoutModes/ColumnViewBrowser.xaml.cs
@@ -364,7 +364,7 @@ public override void ResetItemOpacity()
 
         protected override ListedItem GetItemFromElement(object element)
         {
-            return (element as ListViewItem).DataContext as ListedItem;
+            return (element as ListViewItem).DataContext as ListedItem ?? (element as ListViewItem).Content as ListedItem;
         }
 
         #region IDisposable
diff --git a/Files/Views/LayoutModes/DetailsLayoutBrowser.xaml b/Files/Views/LayoutModes/DetailsLayoutBrowser.xaml
index b1f99897b567..8d8b71a9390d 100644
--- a/Files/Views/LayoutModes/DetailsLayoutBrowser.xaml
+++ b/Files/Views/LayoutModes/DetailsLayoutBrowser.xaml
@@ -201,8 +201,8 @@
                     CanDragItems="{x:Bind InstanceViewModel.IsPageTypeSearchResults, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}"
                     ChoosingItemContainer="FileList_ChoosingItemContainer"
                     DoubleTapped="FileList_DoubleTapped"
-                    DragEnter="ItemsLayout_DragEnter"
                     DragItemsStarting="FileList_DragItemsStarting"
+                    DragOver="ItemsLayout_DragOver"
                     Drop="ItemsLayout_Drop"
                     IsDoubleTapEnabled="True"
                     IsItemClickEnabled="True"
diff --git a/Files/Views/LayoutModes/DetailsLayoutBrowser.xaml.cs b/Files/Views/LayoutModes/DetailsLayoutBrowser.xaml.cs
index 7dfc741fec85..3a2ad44352a1 100644
--- a/Files/Views/LayoutModes/DetailsLayoutBrowser.xaml.cs
+++ b/Files/Views/LayoutModes/DetailsLayoutBrowser.xaml.cs
@@ -484,7 +484,7 @@ protected override void Page_CharacterReceived(CoreWindow sender, CharacterRecei
 
         protected override ListedItem GetItemFromElement(object element)
         {
-            return (element as ListViewItem).DataContext as ListedItem;
+            return (element as ListViewItem).DataContext as ListedItem ?? (element as ListViewItem).Content as ListedItem;
         }
 
         private void FileListGridItem_PointerPressed(object sender, PointerRoutedEventArgs e)
diff --git a/Files/Views/LayoutModes/GridViewBrowser.xaml b/Files/Views/LayoutModes/GridViewBrowser.xaml
index b6879b87e207..2f5a7fa687aa 100644
--- a/Files/Views/LayoutModes/GridViewBrowser.xaml
+++ b/Files/Views/LayoutModes/GridViewBrowser.xaml
@@ -481,8 +481,8 @@
                     CanDragItems="{x:Bind InstanceViewModel.IsPageTypeSearchResults, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}"
                     ChoosingItemContainer="FileList_ChoosingItemContainer"
                     DoubleTapped="FileList_DoubleTapped"
-                    DragEnter="ItemsLayout_DragEnter"
                     DragItemsStarting="FileList_DragItemsStarting"
+                    DragOver="ItemsLayout_DragOver"
                     Drop="ItemsLayout_Drop"
                     IsDoubleTapEnabled="True"
                     IsItemClickEnabled="True"
diff --git a/Files/Views/LayoutModes/GridViewBrowser.xaml.cs b/Files/Views/LayoutModes/GridViewBrowser.xaml.cs
index 05026b9d5b48..9fa8cf8e8b65 100644
--- a/Files/Views/LayoutModes/GridViewBrowser.xaml.cs
+++ b/Files/Views/LayoutModes/GridViewBrowser.xaml.cs
@@ -443,7 +443,7 @@ protected override void Page_CharacterReceived(CoreWindow sender, CharacterRecei
 
         protected override ListedItem GetItemFromElement(object element)
         {
-            return (element as GridViewItem).DataContext as ListedItem;
+            return (element as GridViewItem).DataContext as ListedItem ?? (element as GridViewItem).Content as ListedItem;
         }
 
         private void FileListGridItem_PointerPressed(object sender, PointerRoutedEventArgs e)