Skip to content

Commit 6144d4a

Browse files
authored
Merge pull request #3590 from onesounds/250527-FixOpenContaining
Fix file explorer invocation to ensure correct file selection behavior
2 parents 6333cd3 + eb69ce9 commit 6144d4a

File tree

3 files changed

+66
-19
lines changed

3 files changed

+66
-19
lines changed

Flow.Launcher.Infrastructure/NativeMethods.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,7 @@ LOCALE_TRANSIENT_KEYBOARD1
5757
LOCALE_TRANSIENT_KEYBOARD2
5858
LOCALE_TRANSIENT_KEYBOARD3
5959
LOCALE_TRANSIENT_KEYBOARD4
60+
61+
SHParseDisplayName
62+
SHOpenFolderAndSelectItems
63+
CoTaskMemFree

Flow.Launcher.Infrastructure/Win32Helper.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.ComponentModel;
44
using System.Diagnostics;
55
using System.Globalization;
6+
using System.IO;
67
using System.Linq;
78
using System.Runtime.InteropServices;
89
using System.Threading;
@@ -17,6 +18,7 @@
1718
using Windows.Win32.Foundation;
1819
using Windows.Win32.Graphics.Dwm;
1920
using Windows.Win32.UI.Input.KeyboardAndMouse;
21+
using Windows.Win32.UI.Shell.Common;
2022
using Windows.Win32.UI.WindowsAndMessaging;
2123
using Point = System.Windows.Point;
2224
using SystemFonts = System.Windows.SystemFonts;
@@ -753,5 +755,36 @@ private static bool TryGetNotoFont(string langKey, out string notoFont)
753755
}
754756

755757
#endregion
758+
759+
#region Explorer
760+
761+
// https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shopenfolderandselectitems
762+
763+
public static unsafe void OpenFolderAndSelectFile(string filePath)
764+
{
765+
ITEMIDLIST* pidlFolder = null;
766+
ITEMIDLIST* pidlFile = null;
767+
768+
var folderPath = Path.GetDirectoryName(filePath);
769+
770+
try
771+
{
772+
var hrFolder = PInvoke.SHParseDisplayName(folderPath, null, out pidlFolder, 0, null);
773+
if (hrFolder.Failed) throw new COMException("Failed to parse folder path", hrFolder);
774+
775+
var hrFile = PInvoke.SHParseDisplayName(filePath, null, out pidlFile, 0, null);
776+
if (hrFile.Failed) throw new COMException("Failed to parse file path", hrFile);
777+
778+
var hrSelect = PInvoke.SHOpenFolderAndSelectItems(pidlFolder, 1, &pidlFile, 0);
779+
if (hrSelect.Failed) throw new COMException("Failed to open folder and select item", hrSelect);
780+
}
781+
finally
782+
{
783+
if (pidlFile != null) PInvoke.CoTaskMemFree(pidlFile);
784+
if (pidlFolder != null) PInvoke.CoTaskMemFree(pidlFolder);
785+
}
786+
}
787+
788+
#endregion
756789
}
757790
}

Flow.Launcher/PublicAPIInstance.cs

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
using System.Threading;
1212
using System.Threading.Tasks;
1313
using System.Windows;
14-
using System.Windows.Input;
1514
using System.Windows.Media;
1615
using CommunityToolkit.Mvvm.DependencyInjection;
1716
using Flow.Launcher.Core;
@@ -319,45 +318,55 @@ public void SavePluginSettings()
319318

320319
((PluginJsonStorage<T>)_pluginJsonStorages[type]).Save();
321320
}
322-
323-
public void OpenDirectory(string DirectoryPath, string FileNameOrFilePath = null)
321+
322+
public void OpenDirectory(string directoryPath, string fileNameOrFilePath = null)
324323
{
325324
try
326325
{
327-
using var explorer = new Process();
328326
var explorerInfo = _settings.CustomExplorer;
329327
var explorerPath = explorerInfo.Path.Trim().ToLowerInvariant();
330-
var targetPath = FileNameOrFilePath is null
331-
? DirectoryPath
332-
: Path.IsPathRooted(FileNameOrFilePath)
333-
? FileNameOrFilePath
334-
: Path.Combine(DirectoryPath, FileNameOrFilePath);
328+
var targetPath = fileNameOrFilePath is null
329+
? directoryPath
330+
: Path.IsPathRooted(fileNameOrFilePath)
331+
? fileNameOrFilePath
332+
: Path.Combine(directoryPath, fileNameOrFilePath);
335333

336334
if (Path.GetFileNameWithoutExtension(explorerPath) == "explorer")
337335
{
338336
// Windows File Manager
339-
explorer.StartInfo = new ProcessStartInfo
337+
if (fileNameOrFilePath is null)
340338
{
341-
FileName = targetPath,
342-
UseShellExecute = true
343-
};
339+
// Only Open the directory
340+
using var explorer = new Process();
341+
explorer.StartInfo = new ProcessStartInfo
342+
{
343+
FileName = directoryPath,
344+
UseShellExecute = true
345+
};
346+
explorer.Start();
347+
}
348+
else
349+
{
350+
// Open the directory and select the file
351+
Win32Helper.OpenFolderAndSelectFile(targetPath);
352+
}
344353
}
345354
else
346355
{
347356
// Custom File Manager
357+
using var explorer = new Process();
348358
explorer.StartInfo = new ProcessStartInfo
349359
{
350-
FileName = explorerInfo.Path.Replace("%d", DirectoryPath),
360+
FileName = explorerInfo.Path.Replace("%d", directoryPath),
351361
UseShellExecute = true,
352-
Arguments = FileNameOrFilePath is null
353-
? explorerInfo.DirectoryArgument.Replace("%d", DirectoryPath)
362+
Arguments = fileNameOrFilePath is null
363+
? explorerInfo.DirectoryArgument.Replace("%d", directoryPath)
354364
: explorerInfo.FileArgument
355-
.Replace("%d", DirectoryPath)
365+
.Replace("%d", directoryPath)
356366
.Replace("%f", targetPath)
357367
};
368+
explorer.Start();
358369
}
359-
360-
explorer.Start();
361370
}
362371
catch (Win32Exception ex) when (ex.NativeErrorCode == 2)
363372
{
@@ -381,6 +390,7 @@ public void OpenDirectory(string DirectoryPath, string FileNameOrFilePath = null
381390
}
382391
}
383392

393+
384394
private void OpenUri(Uri uri, bool? inPrivate = null)
385395
{
386396
if (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps)

0 commit comments

Comments
 (0)