Skip to content

Commit f6f3297

Browse files
Fix: Fixed issue where archives opened in new tab instead of existing one (#17394)
1 parent a6b39a9 commit f6f3297

File tree

5 files changed

+116
-27
lines changed

5 files changed

+116
-27
lines changed

src/Files.App/Constants.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,5 +270,17 @@ static UserEnvironmentPaths()
270270
{ NetworkFolderPath.ToUpperInvariant(), NetworkFolderPath },
271271
};
272272
}
273+
274+
public static class Distributions
275+
{
276+
public static readonly string[] KnownAppNames =
277+
{
278+
"49306atecsolution.FilesUWP", // store stable
279+
"FilesStable", // sideload stable
280+
"FilesPreview", // sideload preview
281+
"49306atecsolution.FilesPreview", // store preview
282+
"FilesDev", // dev
283+
};
284+
}
273285
}
274286
}

src/Files.App/Helpers/Win32/Win32Helper.Process.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,5 @@ public static List<Process> WhoIsLocking(string[] resources)
126126

127127
return processes;
128128
}
129-
130-
public static Task<string> GetFileAssociationAsync(string filePath)
131-
{
132-
return GetFileAssociationAsync(filePath, true);
133-
}
134129
}
135130
}

src/Files.App/Helpers/Win32/Win32Helper.Storage.cs

Lines changed: 100 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the MIT License. See the LICENSE.
33

44
using Microsoft.Extensions.Logging;
5+
using Microsoft.Win32;
56
using Microsoft.Win32.SafeHandles;
67
using System.Collections.Concurrent;
78
using System.Drawing;
@@ -163,28 +164,15 @@ public static Task StartSTATask(Action action)
163164
return taskCompletionSource.Task;
164165
}
165166

166-
public static async Task<string?> GetFileAssociationAsync(string filename, bool checkDesktopFirst = false)
167+
public static async Task<string?> GetDefaultFileAssociationAsync(string filename, bool checkDesktopFirst = true)
167168
{
168-
// Find UWP apps
169-
async Task<string?> GetUwpAssoc()
170-
{
171-
var uwpApps = await Launcher.FindFileHandlersAsync(Path.GetExtension(filename));
172-
return uwpApps.Any() ? uwpApps[0].PackageFamilyName : null;
173-
}
169+
// check if there exists an user choice first
170+
var userChoice = GetUserChoiceFileAssociation(filename);
171+
if (!string.IsNullOrEmpty(userChoice))
172+
return userChoice;
174173

175-
// Find desktop apps
176-
string? GetDesktopAssoc()
177-
{
178-
var lpResult = new StringBuilder(2048);
179-
var hResult = Shell32.FindExecutable(filename, null, lpResult);
174+
return await GetFileAssociationAsync(filename, checkDesktopFirst);
180175

181-
return hResult.ToInt64() > 32 ? lpResult.ToString() : null;
182-
}
183-
184-
if (checkDesktopFirst)
185-
return GetDesktopAssoc() ?? await GetUwpAssoc();
186-
187-
return await GetUwpAssoc() ?? GetDesktopAssoc();
188176
}
189177

190178
public static string ExtractStringFromDLL(string file, int number)
@@ -1210,5 +1198,98 @@ public static bool GetWin32FindDataForPath(string targetPath, out Win32PInvoke.W
12101198

12111199
return false;
12121200
}
1201+
1202+
private static string? GetPackageFamilyNameFromAppRegistryName(string appRegistryName)
1203+
{
1204+
using var appXKey = Registry.ClassesRoot.OpenSubKey(appRegistryName + @"\Application");
1205+
var appUserModelIdObj = appXKey?.GetValue("AppUserModelId");
1206+
string? appUserModelId = appUserModelIdObj?.ToString();
1207+
string? packageFamilyName = null;
1208+
if (!string.IsNullOrEmpty(appUserModelId))
1209+
{
1210+
int bangIndex = appUserModelId.IndexOf('!');
1211+
packageFamilyName = bangIndex > 0 ? appUserModelId[..bangIndex] : appUserModelId;
1212+
}
1213+
1214+
return packageFamilyName;
1215+
}
1216+
1217+
private static string? GetUserChoiceFileAssociation(string filename)
1218+
{
1219+
var fileExtension = Path.GetExtension(filename);
1220+
if (string.IsNullOrEmpty(filename))
1221+
return null;
1222+
1223+
try
1224+
{
1225+
// Get ProgId from UserChoice
1226+
using var userChoiceKey = Registry.CurrentUser.OpenSubKey($@"Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\{fileExtension}\UserChoice");
1227+
var progIdObj = userChoiceKey?.GetValue("ProgId");
1228+
string? progId = progIdObj?.ToString();
1229+
1230+
if (string.IsNullOrEmpty(progId))
1231+
return null;
1232+
1233+
// Get the package family name if it's an AppX app
1234+
if (progId.StartsWith("AppX", StringComparison.OrdinalIgnoreCase))
1235+
{
1236+
string? packageFamilyName = GetPackageFamilyNameFromAppRegistryName(progId);
1237+
if (!string.IsNullOrEmpty(packageFamilyName))
1238+
return packageFamilyName;
1239+
}
1240+
1241+
// Find the open command for the ProgId
1242+
using var commandKey = Registry.ClassesRoot.OpenSubKey($@"{progId}\shell\open\command");
1243+
var command = commandKey?.GetValue(null)?.ToString();
1244+
1245+
if (string.IsNullOrEmpty(command))
1246+
return null;
1247+
1248+
// Extract executable path from command string (e.g. "\"C:\\Program Files\\App\\app.exe\" \"%1\"")
1249+
var exePath = command.Trim();
1250+
if (exePath.StartsWith("\""))
1251+
{
1252+
int endQuote = exePath.IndexOf('\"', 1);
1253+
if (endQuote > 1)
1254+
exePath = exePath.Substring(1, endQuote - 1);
1255+
}
1256+
else
1257+
{
1258+
int firstSpace = exePath.IndexOf(' ');
1259+
if (firstSpace > 0)
1260+
exePath = exePath.Substring(0, firstSpace);
1261+
}
1262+
1263+
return File.Exists(exePath) ? exePath : null;
1264+
}
1265+
catch
1266+
{
1267+
return null;
1268+
}
1269+
}
1270+
1271+
private static async Task<string?> GetFileAssociationAsync(string filename, bool checkDesktopFirst = true)
1272+
{
1273+
// Find UWP apps
1274+
async Task<string?> GetUwpAssoc()
1275+
{
1276+
var uwpApps = await Launcher.FindFileHandlersAsync(Path.GetExtension(filename));
1277+
return uwpApps.Any() ? uwpApps[0].PackageFamilyName : null;
1278+
}
1279+
1280+
// Find desktop apps
1281+
string? GetDesktopAssoc()
1282+
{
1283+
var lpResult = new StringBuilder(2048);
1284+
var hResult = Shell32.FindExecutable(filename, null, lpResult);
1285+
1286+
return hResult.ToInt64() > 32 ? lpResult.ToString() : null;
1287+
}
1288+
1289+
if (checkDesktopFirst)
1290+
return GetDesktopAssoc() ?? await GetUwpAssoc();
1291+
1292+
return await GetUwpAssoc() ?? GetDesktopAssoc();
1293+
}
12131294
}
12141295
}

src/Files.App/Utils/Shell/LaunchHelper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ private static async Task<bool> HandleApplicationLaunch(string application, stri
155155
var groups = split.GroupBy(x => new
156156
{
157157
Dir = Path.GetDirectoryName(x),
158-
Prog = Win32Helper.GetFileAssociationAsync(x).Result ?? Path.GetExtension(x)
158+
Prog = Win32Helper.GetDefaultFileAssociationAsync(x).Result ?? Path.GetExtension(x)
159159
});
160160

161161
foreach (var group in groups)

src/Files.App/Utils/Storage/StorageItems/ZipStorageFolder.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,11 @@ public static async Task<bool> CheckDefaultZipApp(string filePath)
9898
{
9999
Func<Task<bool>> queryFileAssoc = async () =>
100100
{
101-
var assoc = await Win32Helper.GetFileAssociationAsync(filePath);
101+
var assoc = await Win32Helper.GetDefaultFileAssociationAsync(filePath);
102102
if (assoc is not null)
103103
{
104-
return assoc == Package.Current.Id.FamilyName
104+
return Constants.Distributions.KnownAppNames.Any(x => assoc.StartsWith(x, StringComparison.OrdinalIgnoreCase))
105+
|| assoc == Package.Current.Id.FamilyName
105106
|| assoc.EndsWith("Files.App\\Files.exe", StringComparison.OrdinalIgnoreCase)
106107
|| assoc.Equals(IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "explorer.exe"), StringComparison.OrdinalIgnoreCase);
107108
}

0 commit comments

Comments
 (0)