Skip to content
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
27 changes: 27 additions & 0 deletions Common/ShellLinkItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace Files.Common
{
public class ShellLinkItem : ShellFileItem
{
public string TargetPath;
public string Arguments;
public string WorkingDirectory;
public bool RunAsAdmin;

public ShellLinkItem()
{
}

public ShellLinkItem(ShellFileItem baseItem)
{
this.RecyclePath = baseItem.RecyclePath;
this.FileName = baseItem.FileName;
this.FilePath = baseItem.FilePath;
this.RecycleDate = baseItem.RecycleDate;
this.ModifiedDate = baseItem.ModifiedDate;
this.CreatedDate = baseItem.CreatedDate;
this.FileSize = baseItem.FileSize;
this.FileSizeBytes = baseItem.FileSizeBytes;
this.FileType = baseItem.FileType;
}
}
}
22 changes: 21 additions & 1 deletion Files.Launcher/Helpers/ShellFolderHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ 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
string filePath = folderItem.Name; // Original file path + name (recycle bin only)
string filePath = Path.Combine(Path.GetDirectoryName(parsingPath), folderItem.Name); // 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 Expand Up @@ -72,5 +72,25 @@ public static ShellFileItem GetShellFileItem(ShellItem folderItem)
Ole32.PROPERTYKEY.System.ItemTypeText, out var fileType);
return new ShellFileItem(isFolder, parsingPath, fileName, filePath, recycleDate, modifiedDate, createdDate, fileSize, fileSizeBytes ?? 0, fileType);
}

public static ShellLinkItem GetShellLinkItem(ShellLink linkItem)
{
if (linkItem == null)
{
return null;
}
var baseItem = GetShellFileItem(linkItem);
if (baseItem == null)
{
return null;
}
var link = new ShellLinkItem(baseItem);
link.IsFolder = !string.IsNullOrEmpty(link.TargetPath) && linkItem.Target.IsFolder;
link.RunAsAdmin = linkItem.RunAsAdministrator;
link.Arguments = linkItem.Arguments;
link.WorkingDirectory = linkItem.WorkingDirectory;
link.TargetPath = linkItem.TargetPath;
return link;
}
}
}
18 changes: 3 additions & 15 deletions Files.Launcher/MessageHandlers/FileOperationsHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -507,11 +507,7 @@ await Win32API.StartSTATask(() =>
using var link = new ShellLink(linkPath, LinkResolution.NoUIWithMsgPump, null, TimeSpan.FromMilliseconds(100));
await Win32API.SendMessageAsync(connection, new ValueSet()
{
{ "TargetPath", link.TargetPath },
{ "Arguments", link.Arguments },
{ "WorkingDirectory", link.WorkingDirectory },
{ "RunAsAdmin", link.RunAsAdministrator },
{ "IsFolder", !string.IsNullOrEmpty(link.TargetPath) && link.Target.IsFolder }
{ "ShortcutInfo", JsonConvert.SerializeObject(ShellFolderExtensions.GetShellLinkItem(link)) }
}, message.Get("RequestID", (string)null));
}
else if (linkPath.EndsWith(".url", StringComparison.OrdinalIgnoreCase))
Expand All @@ -525,11 +521,7 @@ await Win32API.StartSTATask(() =>
});
await Win32API.SendMessageAsync(connection, new ValueSet()
{
{ "TargetPath", linkUrl },
{ "Arguments", null },
{ "WorkingDirectory", null },
{ "RunAsAdmin", false },
{ "IsFolder", false }
{ "ShortcutInfo", JsonConvert.SerializeObject(new ShellLinkItem() { TargetPath = linkUrl }) }
}, message.Get("RequestID", (string)null));
}
}
Expand All @@ -539,11 +531,7 @@ await Win32API.StartSTATask(() =>
Program.Logger.Warn(ex, ex.Message);
await Win32API.SendMessageAsync(connection, new ValueSet()
{
{ "TargetPath", null },
{ "Arguments", null },
{ "WorkingDirectory", null },
{ "RunAsAdmin", false },
{ "IsFolder", false }
{ "ShortcutInfo", JsonConvert.SerializeObject(null) }
}, message.Get("RequestID", (string)null));
}
break;
Expand Down
26 changes: 17 additions & 9 deletions Files.Launcher/MessageHandlers/NetworkDrivesHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,23 +45,31 @@ private async Task ParseNetworkDriveOperationAsync(PipeStream connection, Dictio
case "GetNetworkLocations":
var networkLocations = await Win32API.StartSTATask(() =>
{
var netl = new ValueSet();
var locations = new List<ShellLinkItem>();
using (var nethood = new ShellFolder(Shell32.KNOWNFOLDERID.FOLDERID_NetHood))
{
foreach (var link in nethood)
foreach (var item in nethood)
{
var linkPath = (string)link.Properties["System.Link.TargetParsingPath"];
if (linkPath != null)
if (item is ShellLink link)
{
netl.Add(link.Name, linkPath);
locations.Add(ShellFolderExtensions.GetShellLinkItem(link));
}
else
{
var linkPath = (string)item.Properties["System.Link.TargetParsingPath"];
if (linkPath != null)
{
var linkItem = ShellFolderExtensions.GetShellFileItem(item);
locations.Add(new ShellLinkItem(linkItem) { TargetPath = linkPath });
}
}
}
}
return netl;
return locations;
});
networkLocations ??= new ValueSet();
networkLocations.Add("Count", networkLocations.Count);
await Win32API.SendMessageAsync(connection, networkLocations, message.Get("RequestID", (string)null));
var response = new ValueSet();
response.Add("NetworkLocations", JsonConvert.SerializeObject(networkLocations));
await Win32API.SendMessageAsync(connection, response, message.Get("RequestID", (string)null));
break;

case "OpenMapNetworkDriveDialog":
Expand Down
6 changes: 3 additions & 3 deletions Files/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ protected override async void OnLaunched(LaunchActivatedEventArgs e)
bool canEnablePrelaunch = ApiInformation.IsMethodPresent("Windows.ApplicationModel.Core.CoreApplication", "EnablePrelaunch");

await EnsureSettingsAndConfigurationAreBootstrapped();
InitializeAppComponentsAsync().ContinueWith(t => Logger.Warn(t.Exception, "Error during LoadOtherStuffAsync()"), TaskContinuationOptions.OnlyOnFaulted);
_ = InitializeAppComponentsAsync().ContinueWith(t => Logger.Warn(t.Exception, "Error during InitializeAppComponentsAsync()"), TaskContinuationOptions.OnlyOnFaulted);

var rootFrame = EnsureWindowIsInitialized();

Expand Down Expand Up @@ -261,7 +261,7 @@ protected override async void OnFileActivated(FileActivatedEventArgs e)
SystemInformation.Instance.TrackAppUse(e);

await EnsureSettingsAndConfigurationAreBootstrapped();
InitializeAppComponentsAsync().ContinueWith(t => Logger.Warn(t.Exception, "Error during LoadOtherStuffAsync()"), TaskContinuationOptions.OnlyOnFaulted);
_ = InitializeAppComponentsAsync().ContinueWith(t => Logger.Warn(t.Exception, "Error during InitializeAppComponentsAsync()"), TaskContinuationOptions.OnlyOnFaulted);

var rootFrame = EnsureWindowIsInitialized();

Expand Down Expand Up @@ -327,7 +327,7 @@ protected override async void OnActivated(IActivatedEventArgs args)
Logger.Info($"App activated by {args.Kind.ToString()}");

await EnsureSettingsAndConfigurationAreBootstrapped();
InitializeAppComponentsAsync().ContinueWith(t => Logger.Warn(t.Exception, "Error during LoadOtherStuffAsync()"), TaskContinuationOptions.OnlyOnFaulted);
_ = InitializeAppComponentsAsync().ContinueWith(t => Logger.Warn(t.Exception, "Error during InitializeAppComponentsAsync()"), TaskContinuationOptions.OnlyOnFaulted);

var rootFrame = EnsureWindowIsInitialized();

Expand Down
24 changes: 15 additions & 9 deletions Files/Filesystem/NetworkDrivesManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Microsoft.Toolkit.Mvvm.ComponentModel;
using Microsoft.Toolkit.Mvvm.DependencyInjection;
using Microsoft.Toolkit.Uwp;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
Expand Down Expand Up @@ -68,15 +69,16 @@ public async Task EnumerateDrivesAsync()
{ "Arguments", "NetworkDriveOperation" },
{ "netdriveop", "GetNetworkLocations" }
});
if (status == AppServiceResponseStatus.Success && response.ContainsKey("Count"))
if (status == AppServiceResponseStatus.Success && response.ContainsKey("NetworkLocations"))
{
foreach (var key in response.Keys
.Where(k => k != "Count" && k != "RequestID"))
var items = JsonConvert.DeserializeObject<List<ShellLinkItem>>((string)response["NetworkLocations"]);
foreach (var item in items ?? new())
{
var networkItem = new DriveItem()
{
Text = key,
Path = (string)response[key],
Text = System.IO.Path.GetFileNameWithoutExtension(item.FileName),
Path = item.TargetPath,
DeviceID = item.FilePath,
Type = DriveType.Network,
ItemType = NavigationControlItemType.Drive
};
Expand Down Expand Up @@ -147,12 +149,16 @@ await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPrio
.OrderByDescending(o => string.Equals(o.Text, "Network".GetLocalized(), StringComparison.OrdinalIgnoreCase))
.ThenBy(o => o.Text))
{
var resource = await UIHelpers.GetIconResourceInfo(Constants.ImageRes.Folder);
if (resource != null)
if (!string.IsNullOrEmpty(drive.DeviceID))
{
drive.IconData = resource.IconDataBytes;
drive.Icon = await drive.IconData.ToBitmapAsync();
drive.IconData = await FileThumbnailHelper.LoadIconWithoutOverlayAsync(drive.DeviceID, 24);
}
if (drive.IconData == null)
{
var resource = await UIHelpers.GetIconResourceInfo(Constants.ImageRes.Folder);
drive.IconData = resource?.IconDataBytes;
}
drive.Icon = await drive.IconData.ToBitmapAsync();
if (!section.ChildItems.Contains(drive))
{
section.ChildItems.Add(drive);
Expand Down
21 changes: 11 additions & 10 deletions Files/Filesystem/StorageEnumerators/Win32StorageEnumerator.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
using ByteSizeLib;
using Files.Common;
using Files.Extensions;
using Files.Filesystem.StorageItems;
using Files.Helpers;
using Files.Helpers.FileListCache;
using Files.Services;
using Microsoft.Toolkit.Mvvm.DependencyInjection;
using Microsoft.Toolkit.Uwp;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
Expand Down Expand Up @@ -259,21 +261,20 @@ CancellationToken cancellationToken
{
return null;
}
if (status == AppServiceResponseStatus.Success
&& response.ContainsKey("TargetPath"))
if (status == AppServiceResponseStatus.Success && response.ContainsKey("ShortcutInfo"))
{
var isUrl = findData.cFileName.EndsWith(".url", StringComparison.OrdinalIgnoreCase);
string target = (string)response["TargetPath"];
var shInfo = JsonConvert.DeserializeObject<ShellLinkItem>((string)response["ShortcutInfo"]);

return new ShortcutItem(null, dateReturnFormat)
{
PrimaryItemAttribute = (bool)response["IsFolder"] ? StorageItemTypes.Folder : StorageItemTypes.File,
PrimaryItemAttribute = shInfo.IsFolder ? StorageItemTypes.Folder : StorageItemTypes.File,
FileExtension = itemFileExtension,
IsHiddenItem = isHidden,
Opacity = opacity,
FileImage = null,
LoadFileIcon = !(bool)response["IsFolder"] && itemThumbnailImgVis,
LoadWebShortcutGlyph = !(bool)response["IsFolder"] && isUrl && itemEmptyImgVis,
LoadFileIcon = !shInfo.IsFolder && itemThumbnailImgVis,
LoadWebShortcutGlyph = !shInfo.IsFolder && isUrl && itemEmptyImgVis,
ItemNameRaw = itemName,
ItemDateModifiedReal = itemModifiedDate,
ItemDateAccessedReal = itemLastAccessDate,
Expand All @@ -282,10 +283,10 @@ CancellationToken cancellationToken
ItemPath = itemPath,
FileSize = itemSize,
FileSizeBytes = itemSizeBytes,
TargetPath = target,
Arguments = (string)response["Arguments"],
WorkingDirectory = (string)response["WorkingDirectory"],
RunAsAdmin = (bool)response["RunAsAdmin"],
TargetPath = shInfo.TargetPath,
Arguments = shInfo.Arguments,
WorkingDirectory = shInfo.WorkingDirectory,
RunAsAdmin = shInfo.RunAsAdmin,
IsUrl = isUrl,
};
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Files.Extensions;
using Files.Extensions;
using System;
using System.Collections;
using System.Collections.Generic;
Expand Down Expand Up @@ -110,11 +110,11 @@ protected void OnCollectionChanged(NotifyCollectionChangedEventArgs e, bool coun
{
if (!isBulkOperationStarted)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Item[]"));
PropertyChanged?.Invoke(this, EventArgsCache.IndexerPropertyChanged);
CollectionChanged?.Invoke(this, e);
if (countChanged)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Count)));
PropertyChanged?.Invoke(this, EventArgsCache.CountPropertyChanged);
}
}

Expand Down Expand Up @@ -211,9 +211,9 @@ public virtual void EndBulkOperation()
GroupedCollection?.ForEach(gp => gp.EndBulkOperation());
GroupedCollection?.EndBulkOperation();

OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Count)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Item[]"));
OnCollectionChanged(EventArgsCache.ResetCollectionChanged);
PropertyChanged?.Invoke(this, EventArgsCache.CountPropertyChanged);
PropertyChanged?.Invoke(this, EventArgsCache.IndexerPropertyChanged);
}

public void Add(T item)
Expand All @@ -234,7 +234,7 @@ public void Clear()
}
GroupedCollection?.Clear();

OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
OnCollectionChanged(EventArgsCache.ResetCollectionChanged);
}

public bool Contains(T item)
Expand Down Expand Up @@ -307,7 +307,7 @@ public void RemoveAt(int index)

public void AddRange(IEnumerable<T> items)
{
if (items.Count() == 0)
if (!items.Any())
{
return;
}
Expand All @@ -322,7 +322,7 @@ public void AddRange(IEnumerable<T> items)

public void InsertRange(int index, IEnumerable<T> items)
{
if (items.Count() == 0)
if (!items.Any())
{
return;
}
Expand Down Expand Up @@ -425,5 +425,12 @@ int IList.Add(object value)
void IList.Remove(object value) => Remove((T)value);

void ICollection.CopyTo(Array array, int index) => CopyTo((T[])array, index);

private static class EventArgsCache
{
internal static readonly PropertyChangedEventArgs CountPropertyChanged = new PropertyChangedEventArgs("Count");
internal static readonly PropertyChangedEventArgs IndexerPropertyChanged = new PropertyChangedEventArgs("Item[]");
internal static readonly NotifyCollectionChangedEventArgs ResetCollectionChanged = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
}
}
}
}
Loading