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
13 changes: 13 additions & 0 deletions src/Files.App/Helpers/DynamicDialogFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,19 @@ public static DynamicDialog GetFor_ConsentDialog()
return dialog;
}

public static DynamicDialog GetFor_ShortcutNotFound(string targetPath)
{
DynamicDialog dialog = new(new DynamicDialogViewModel
{
TitleText = "ShortcutCannotBeOpened".GetLocalizedResource(),
SubtitleText = string.Format("DeleteShortcutDescription".GetLocalizedResource(), targetPath),
PrimaryButtonText = "Delete".GetLocalizedResource(),
SecondaryButtonText = "No".GetLocalizedResource(),
DynamicButtons = DynamicDialogButtons.Primary | DynamicDialogButtons.Secondary
});
return dialog;
}

public static DynamicDialog GetFor_RenameDialog()
{
DynamicDialog dialog = null;
Expand Down
40 changes: 15 additions & 25 deletions src/Files.App/Helpers/NavigationHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using Windows.ApplicationModel.AppService;
using Windows.Foundation.Collections;
using Windows.Storage;
using Windows.Storage.Search;
using Windows.System;
Expand Down Expand Up @@ -135,38 +132,31 @@ public static async Task<bool> OpenPath(string path, IShellPage associatedInstan
bool isHiddenItem = NativeFileOperationsHelper.HasFileAttribute(path, System.IO.FileAttributes.Hidden);
bool isDirectory = NativeFileOperationsHelper.HasFileAttribute(path, System.IO.FileAttributes.Directory);
bool isReparsePoint = NativeFileOperationsHelper.HasFileAttribute(path, System.IO.FileAttributes.ReparsePoint);
bool IsShortcut = path.EndsWith(".lnk", StringComparison.Ordinal) || path.EndsWith(".url", StringComparison.Ordinal);
bool isShortcut = associatedInstance.SlimContentPage.SelectedItem is { IsShortcut: true };
FilesystemResult opened = (FilesystemResult)false;

var shortcutInfo = new ShellLinkItem();
if (itemType == null || IsShortcut || isHiddenItem || isReparsePoint)
if (itemType == null || isShortcut || isHiddenItem || isReparsePoint)
{
if (IsShortcut)
if (isShortcut)
{
var connection = await AppServiceConnectionHelper.Instance;
var shInfo = await Win32Shell.ParseLink(path);

if (connection == null)
if (shInfo == null)
return false;

var (status, response) = await connection.SendMessageForResponseAsync(new ValueSet()
{
{ "Arguments", "FileOperation" },
{ "fileop", "ParseLink" },
{ "filepath", path }
});
itemType = shInfo.IsFolder ? FilesystemItemType.Directory : FilesystemItemType.File;

if (status == AppServiceResponseStatus.Success && response.ContainsKey("ShortcutInfo"))
{
var shInfo = JsonSerializer.Deserialize<ShellLinkItem>(response["ShortcutInfo"].GetString());
if (shInfo != null)
{
shortcutInfo = shInfo;
}
itemType = shInfo != null && shInfo.IsFolder ? FilesystemItemType.Directory : FilesystemItemType.File;
}
else
shortcutInfo = shInfo;

if (shortcutInfo.InvalidTarget)
{
return false;
if (await DialogDisplayHelper.ShowDialogAsync(DynamicDialogFactory.GetFor_ShortcutNotFound(shortcutInfo.TargetPath)) != DynamicDialogResult.Primary)
return false;

// Delete shortcut
var shortcutItem = StorageHelpers.FromPathAndType(path, FilesystemItemType.File);
await associatedInstance.FilesystemHelpers.DeleteItemAsync(shortcutItem, false, false, true);
}
}
else if (isReparsePoint)
Expand Down
53 changes: 49 additions & 4 deletions src/Files.App/Shell/Win32Shell.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
using Files.Shared;
using Files.Shared.Extensions;
#nullable enable

using Files.Shared;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Vanara.PInvoke;
using Vanara.Windows.Shell;
using Windows.Storage;

namespace Files.App.Shell
{
Expand Down Expand Up @@ -90,5 +89,51 @@ public static (bool HasRecycleBin, long NumItems, long BinSize) QueryRecycleBin(
return (false, 0, 0);
}
}

public static async Task<ShellLinkItem?> ParseLink(string filePath)
{
if (string.IsNullOrEmpty(filePath))
return null;

string targetPath = string.Empty;

try
{
if (filePath.EndsWith(".lnk", StringComparison.OrdinalIgnoreCase))
{
using var link = new ShellLink(filePath, LinkResolution.NoUIWithMsgPump, null, TimeSpan.FromMilliseconds(100));
targetPath = link.TargetPath;
return ShellFolderExtensions.GetShellLinkItem(link);
}

if (filePath.EndsWith(".url", StringComparison.OrdinalIgnoreCase))
{
targetPath = await Win32API.StartSTATask(() =>
{
var ipf = new Url.IUniformResourceLocator();
(ipf as System.Runtime.InteropServices.ComTypes.IPersistFile)?.Load(filePath, 0);
ipf.GetUrl(out var retVal);
return retVal;
});

return string.IsNullOrEmpty(targetPath) ? null : new ShellLinkItem { TargetPath = targetPath };
}
}
catch (FileNotFoundException ex) // Could not parse shortcut
{
App.Logger?.Warn(ex, ex.Message);
// Return a item containing the invalid target path
return new ShellLinkItem
{
TargetPath = string.IsNullOrEmpty(targetPath) ? string.Empty : targetPath,
InvalidTarget = true
};
}
catch (Exception ex)
{
App.Logger?.Warn(ex, ex.Message);
}
return null;
}
}
}
6 changes: 6 additions & 0 deletions src/Files.App/Strings/en-US/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -2832,4 +2832,10 @@
<data name="RestoreSelection" xml:space="preserve">
<value>Restore</value>
</data>
<data name="ShortcutCannotBeOpened" xml:space="preserve">
<value>Shortcut cannot be opened</value>
</data>
<data name="DeleteShortcutDescription" xml:space="preserve">
<value>The target destination cannot be found {0}. Do you want to delete this shortcut?</value>
</data>
</root>
1 change: 1 addition & 0 deletions src/Files.Shared/ShellLinkItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ public class ShellLinkItem : ShellFileItem
public string Arguments { get; set; }
public string WorkingDirectory { get; set; }
public bool RunAsAdmin { get; set; }
public bool InvalidTarget { get; set; }

public ShellLinkItem()
{
Expand Down