Skip to content

[Post 2.3] Add support for folder shortcuts in shell folders #9163

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
May 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/Files.FullTrust/Helpers/ShellFolderHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,10 @@ public static ShellFileItem GetShellFileItem(ShellItem folderItem)
folderItem.Properties.TryGetValue<string>(
Ole32.PROPERTYKEY.System.ItemNameDisplay, out var fileName);
fileName ??= Path.GetFileName(folderItem.Name); // Original file name
fileName ??= folderItem.GetDisplayName(ShellItemDisplayString.ParentRelativeParsing);
var itemNameOrOriginalPath = folderItem.Name ?? fileName;
string filePath = string.IsNullOrEmpty(Path.GetDirectoryName(parsingPath)) ? // Null if root
parsingPath : Path.Combine(Path.GetDirectoryName(parsingPath), folderItem.Name); // In recycle bin "Name" contains original file path + name
parsingPath : Path.Combine(Path.GetDirectoryName(parsingPath), itemNameOrOriginalPath); // In recycle bin "Name" contains original file path + name
if (!isFolder && !string.IsNullOrEmpty(parsingPath) && Path.GetExtension(parsingPath) is string realExtension && !string.IsNullOrEmpty(realExtension))
{
if (!string.IsNullOrEmpty(fileName) && !fileName.EndsWith(realExtension, StringComparison.OrdinalIgnoreCase))
Expand Down
9 changes: 7 additions & 2 deletions src/Files.FullTrust/MessageHandlers/Win32MessageHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,9 @@ public async Task ParseArgumentsAsync(PipeStream connection, Dictionary<string,
{
try
{
var shellFileItem = ShellFolderExtensions.GetShellFileItem(folderItem);
var shellFileItem = folderItem is ShellLink link ?
ShellFolderExtensions.GetShellLinkItem(link) :
ShellFolderExtensions.GetShellFileItem(folderItem);
flc.Add(shellFileItem);
}
catch (FileNotFoundException)
Expand All @@ -163,7 +165,10 @@ public async Task ParseArgumentsAsync(PipeStream connection, Dictionary<string,
return (folder, flc);
});
sfResponseEnum.Add("Folder", JsonConvert.SerializeObject(folder));
sfResponseEnum.Add("Enumerate", JsonConvert.SerializeObject(folderContentsList));
sfResponseEnum.Add("Enumerate", JsonConvert.SerializeObject(folderContentsList, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects
}));
await Win32API.SendMessageAsync(connection, sfResponseEnum, message.Get("RequestID", (string)null));
break;

Expand Down
1 change: 1 addition & 0 deletions src/Files.Uwp/Files.Uwp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@
<Compile Include="Helpers\CommonPaths.cs" />
<Compile Include="Helpers\FileExtensionHelpers.cs" />
<Compile Include="Helpers\ItemListDisplayHelpers\BlockingListEnumerator.cs" />
<Compile Include="Helpers\KnownTypesBinder.cs" />
<Compile Include="Helpers\LocalizedEnumHelper.cs" />
<Compile Include="Helpers\ResourceHelpers.cs" />
<Compile Include="Helpers\FtpHelpers.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,29 @@ public static async Task<ListedItem> AddFolderAsync(BaseStorageFolder folder, St
var basicProperties = await folder.GetBasicPropertiesAsync();
if (!cancellationToken.IsCancellationRequested)
{
if (folder is BinStorageFolder binFolder)
if (folder is ShortcutStorageFolder linkFolder)
{
return new ShortcutItem(folder.FolderRelativeId, dateReturnFormat)
{
PrimaryItemAttribute = StorageItemTypes.Folder,
IsHiddenItem = false,
Opacity = 1,
FileImage = null,
LoadFileIcon = false,
ItemNameRaw = folder.DisplayName,
ItemDateModifiedReal = basicProperties.DateModified,
ItemDateCreatedReal = folder.DateCreated,
ItemType = folder.DisplayType,
ItemPath = folder.Path,
FileSize = null,
FileSizeBytes = 0,
TargetPath = linkFolder.TargetPath,
Arguments = linkFolder.Arguments,
WorkingDirectory = linkFolder.WorkingDirectory,
RunAsAdmin = linkFolder.RunAsAdmin
};
}
else if (folder is BinStorageFolder binFolder)
{
return new RecycleBinItem(folder.FolderRelativeId, dateReturnFormat)
{
Expand Down Expand Up @@ -242,7 +264,33 @@ CancellationToken cancellationToken
}
else
{
if (file is BinStorageFile binFile)
if (file is ShortcutStorageFile linkFile)
{
var isUrl = linkFile.Name.EndsWith(".url", StringComparison.OrdinalIgnoreCase);
return new ShortcutItem(file.FolderRelativeId, dateReturnFormat)
{
PrimaryItemAttribute = StorageItemTypes.File,
FileExtension = itemFileExtension,
IsHiddenItem = false,
Opacity = 1,
FileImage = null,
LoadFileIcon = itemThumbnailImgVis,
LoadWebShortcutGlyph = isUrl,
ItemNameRaw = itemName,
ItemDateModifiedReal = itemModifiedDate,
ItemDateCreatedReal = itemCreatedDate,
ItemType = itemType,
ItemPath = itemPath,
FileSize = itemSize,
FileSizeBytes = (long)itemSizeBytes,
TargetPath = linkFile.TargetPath,
Arguments = linkFile.Arguments,
WorkingDirectory = linkFile.WorkingDirectory,
RunAsAdmin = linkFile.RunAsAdmin,
IsUrl = isUrl,
};
}
else if (file is BinStorageFile binFile)
{
return new RecycleBinItem(file.FolderRelativeId, dateReturnFormat)
{
Expand Down
27 changes: 25 additions & 2 deletions src/Files.Uwp/Filesystem/StorageItems/ShellStorageFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,22 @@

namespace Files.Uwp.Filesystem.StorageItems
{
public class ShortcutStorageFile : ShellStorageFile, IShortcutStorageItem
{
public string TargetPath { get; }
public string Arguments { get; }
public string WorkingDirectory { get; }
public bool RunAsAdmin { get; }

public ShortcutStorageFile(ShellLinkItem item) : base(item)
{
TargetPath = item.TargetPath;
Arguments = item.Arguments;
WorkingDirectory = item.WorkingDirectory;
RunAsAdmin = item.RunAsAdmin;
}
}

public class BinStorageFile : ShellStorageFile, IBinStorageItem
{
public string OriginalPath { get; }
Expand Down Expand Up @@ -58,11 +74,18 @@ public ShellStorageFile(ShellFileItem item)

public static ShellStorageFile FromShellItem(ShellFileItem item)
{
if (item.RecyclePath != item.FilePath)
if (item is ShellLinkItem linkItem)
{
return new ShortcutStorageFile(linkItem);
}
else if (item.RecyclePath.Contains("$Recycle.Bin", StringComparison.Ordinal))
{
return new BinStorageFile(item);
}
return new ShellStorageFile(item);
else
{
return new ShellStorageFile(item);
}
}

public static IAsyncOperation<BaseStorageFile> FromPathAsync(string path)
Expand Down
45 changes: 40 additions & 5 deletions src/Files.Uwp/Filesystem/StorageItems/ShellStorageFolder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,30 @@

namespace Files.Uwp.Filesystem.StorageItems
{
public class ShortcutStorageFolder : ShellStorageFolder, IShortcutStorageItem
{
public string TargetPath { get; }
public string Arguments { get; }
public string WorkingDirectory { get; }
public bool RunAsAdmin { get; }

public ShortcutStorageFolder(ShellLinkItem item) : base(item)
{
TargetPath = item.TargetPath;
Arguments = item.Arguments;
WorkingDirectory = item.WorkingDirectory;
RunAsAdmin = item.RunAsAdmin;
}
}

public interface IShortcutStorageItem : IStorageItem
{
string TargetPath { get; }
string Arguments { get; }
string WorkingDirectory { get; }
bool RunAsAdmin { get; }
}

public class BinStorageFolder : ShellStorageFolder, IBinStorageItem
{
public string OriginalPath { get; }
Expand Down Expand Up @@ -58,19 +82,26 @@ public ShellStorageFolder(ShellFileItem item)

public static bool IsShellPath(string path)
{
return path is not null &&
path.StartsWith("shell:", StringComparison.OrdinalIgnoreCase) ||
return path is not null &&
path.StartsWith("shell:", StringComparison.OrdinalIgnoreCase) ||
path.StartsWith("::{", StringComparison.Ordinal) ||
path.StartsWith(@"\\SHELL\", StringComparison.Ordinal);
}

public static ShellStorageFolder FromShellItem(ShellFileItem item)
{
if (item.RecyclePath != item.FilePath)
if (item is ShellLinkItem linkItem)
{
return new ShortcutStorageFolder(linkItem);
}
else if (item.RecyclePath.Contains("$Recycle.Bin", StringComparison.Ordinal))
{
return new BinStorageFolder(item);
}
return new ShellStorageFolder(item);
else
{
return new ShellStorageFolder(item);
}
}

public static IAsyncOperation<BaseStorageFolder> FromPathAsync(string path)
Expand Down Expand Up @@ -106,7 +137,11 @@ public static IAsyncOperation<BaseStorageFolder> FromPathAsync(string path)
if (status == AppServiceResponseStatus.Success)
{
var folder = JsonConvert.DeserializeObject<ShellFileItem>(response.Get("Folder", ""));
var items = JsonConvert.DeserializeObject<List<ShellFileItem>>(response.Get("Enumerate", ""));
var items = JsonConvert.DeserializeObject<List<ShellFileItem>>(response.Get("Enumerate", ""), new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.Objects,
SerializationBinder = new KnownTypesBinder() { KnownTypes = { typeof(ShellFileItem), typeof(ShellLinkItem) } }
});
return (folder, items);
}
}
Expand Down
30 changes: 30 additions & 0 deletions src/Files.Uwp/Helpers/KnownTypesBinder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Files.Uwp.Helpers
{
public class KnownTypesBinder : ISerializationBinder
{
public IList<Type> KnownTypes { get; } = new List<Type>();

public Type BindToType(string assemblyName, string typeName)
{
if (!KnownTypes.Any(x => x.Name == typeName || x.FullName == typeName))
{
throw new ArgumentException();
}
else
{
return KnownTypes.SingleOrDefault(t => t.Name == typeName || t.FullName == typeName);
}
}

public void BindToName(Type serializedType, out string assemblyName, out string typeName)
{
assemblyName = null;
typeName = serializedType.Name;
}
}
}
26 changes: 2 additions & 24 deletions src/Files.Uwp/UserControls/MultitaskingControl/TabItem/TabItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Files.Uwp.Helpers;

namespace Files.Uwp.UserControls.MultitaskingControl
{
Expand Down Expand Up @@ -80,7 +81,7 @@ public class TabItemArguments
{
private static KnownTypesBinder TypesBinder = new KnownTypesBinder
{
KnownTypes = new List<Type> { typeof(PaneNavigationArguments) }
KnownTypes = { typeof(PaneNavigationArguments) }
};

public Type InitialPageType { get; set; }
Expand All @@ -98,27 +99,4 @@ public class TabItemArguments
SerializationBinder = TypesBinder
});
}

public class KnownTypesBinder : ISerializationBinder
{
public IList<Type> KnownTypes { get; set; }

public Type BindToType(string assemblyName, string typeName)
{
if (!KnownTypes.Any(x => x.Name == typeName))
{
throw new ArgumentException();
}
else
{
return KnownTypes.SingleOrDefault(t => t.Name == typeName);
}
}

public void BindToName(Type serializedType, out string assemblyName, out string typeName)
{
assemblyName = null;
typeName = serializedType.Name;
}
}
}