Use PInvoke to improve code quality

This commit is contained in:
Jack251970 2025-05-27 14:36:09 +08:00
parent 41c5b36fba
commit 086aeab6c0
3 changed files with 50 additions and 61 deletions

View file

@ -57,3 +57,7 @@ LOCALE_TRANSIENT_KEYBOARD1
LOCALE_TRANSIENT_KEYBOARD2
LOCALE_TRANSIENT_KEYBOARD3
LOCALE_TRANSIENT_KEYBOARD4
SHParseDisplayName
SHOpenFolderAndSelectItems
CoTaskMemFree

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
@ -17,6 +18,7 @@ using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.Graphics.Dwm;
using Windows.Win32.UI.Input.KeyboardAndMouse;
using Windows.Win32.UI.Shell.Common;
using Windows.Win32.UI.WindowsAndMessaging;
using Point = System.Windows.Point;
using SystemFonts = System.Windows.SystemFonts;
@ -753,5 +755,34 @@ namespace Flow.Launcher.Infrastructure
}
#endregion
#region Explorer
public static unsafe void OpenFolderAndSelectFile(string filePath)
{
ITEMIDLIST* pidlFolder = null;
ITEMIDLIST* pidlFile = null;
var folderPath = Path.GetDirectoryName(filePath);
try
{
var hrFolder = PInvoke.SHParseDisplayName(folderPath, null, out pidlFolder, 0, null);
if (hrFolder.Failed) throw new COMException("Failed to parse folder path", hrFolder);
var hrFile = PInvoke.SHParseDisplayName(filePath, null, out pidlFile, 0, null);
if (hrFile.Failed) throw new COMException("Failed to parse file path", hrFile);
var hrSelect = PInvoke.SHOpenFolderAndSelectItems(pidlFolder, 1, &pidlFile, 0);
if (hrSelect.Failed) throw new COMException("Failed to open folder and select item", hrSelect);
}
finally
{
if (pidlFile != null) PInvoke.CoTaskMemFree(pidlFile);
if (pidlFolder != null) PInvoke.CoTaskMemFree(pidlFolder);
}
}
#endregion
}
}

View file

@ -8,11 +8,9 @@ using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using CommunityToolkit.Mvvm.DependencyInjection;
using Flow.Launcher.Core;
@ -320,88 +318,44 @@ namespace Flow.Launcher
((PluginJsonStorage<T>)_pluginJsonStorages[type]).Save();
}
[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
private static extern int SHParseDisplayName(
[MarshalAs(UnmanagedType.LPWStr)] string name,
IntPtr bindingContext,
out IntPtr pidl,
uint sfgaoIn,
out uint psfgaoOut
);
[DllImport("shell32.dll")]
private static extern int SHOpenFolderAndSelectItems(
IntPtr pidlFolder,
uint cidl,
[MarshalAs(UnmanagedType.LPArray)] IntPtr[] apidl,
uint dwFlags
);
[DllImport("ole32.dll")]
private static extern void CoTaskMemFree(IntPtr pv);
private void OpenFolderAndSelectItem(string filePath)
{
IntPtr pidlFolder = IntPtr.Zero;
IntPtr pidlFile = IntPtr.Zero;
uint attr;
string folderPath = Path.GetDirectoryName(filePath);
try
{
SHParseDisplayName(folderPath, IntPtr.Zero, out pidlFolder, 0, out attr);
SHParseDisplayName(filePath, IntPtr.Zero, out pidlFile, 0, out attr);
if (pidlFolder != IntPtr.Zero && pidlFile != IntPtr.Zero)
{
SHOpenFolderAndSelectItems(pidlFolder, 1, new[] { pidlFile }, 0);
}
}
finally
{
if (pidlFile != IntPtr.Zero)
CoTaskMemFree(pidlFile);
if (pidlFolder != IntPtr.Zero)
CoTaskMemFree(pidlFolder);
}
}
public void OpenDirectory(string directoryPath, string fileNameOrFilePath = null)
{
try
{
string targetPath = fileNameOrFilePath is null
var explorerInfo = _settings.CustomExplorer;
var explorerPath = explorerInfo.Path.Trim().ToLowerInvariant();
var targetPath = fileNameOrFilePath is null
? directoryPath
: Path.IsPathRooted(fileNameOrFilePath)
? fileNameOrFilePath
: Path.Combine(directoryPath, fileNameOrFilePath);
var explorerInfo = _settings.CustomExplorer;
var explorerPath = explorerInfo.Path.Trim().ToLowerInvariant();
if (Path.GetFileNameWithoutExtension(explorerPath) == "explorer")
{
// Windows File Manager
if (fileNameOrFilePath is null)
{
// 폴더만 열기
Process.Start(new ProcessStartInfo
// Only Open the directory
using var explorer = new Process();
explorer.StartInfo = new ProcessStartInfo
{
FileName = directoryPath,
UseShellExecute = true
})?.Dispose();
};
explorer.Start();
}
else
{
// SHOpenFolderAndSelectItems 방식
OpenFolderAndSelectItem(targetPath);
// Open the directory and select the file
Win32Helper.OpenFolderAndSelectFile(targetPath);
}
}
else
{
// 커스텀 파일 관리자
var shellProcess = new ProcessStartInfo
// Custom File Manager
using var explorer = new Process();
explorer.StartInfo = new ProcessStartInfo
{
FileName = explorerInfo.Path.Replace("%d", directoryPath),
UseShellExecute = true,
@ -411,7 +365,7 @@ namespace Flow.Launcher
.Replace("%d", directoryPath)
.Replace("%f", targetPath)
};
Process.Start(shellProcess)?.Dispose();
explorer.Start();
}
}
catch (Win32Exception ex) when (ex.NativeErrorCode == 2)