Skip to content

Commit 9b05174

Browse files
Use localized name for shell link programs
1 parent 4849e26 commit 9b05174

File tree

2 files changed

+106
-6
lines changed

2 files changed

+106
-6
lines changed
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
using System;
2+
using System.IO;
3+
using System.Runtime.InteropServices;
4+
using System.Text;
5+
6+
7+
namespace Flow.Launcher.Plugin.Program.Programs
8+
{
9+
// From PT Run
10+
/// <summary>
11+
/// Class to get localized name of shell items like 'My computer'. The localization is based on the 'windows display language'.
12+
/// Reused code from https://stackoverflow.com/questions/41423491/how-to-get-localized-name-of-known-folder for the method <see cref="GetLocalizedName"/>
13+
/// </summary>
14+
public static class ShellLocalization
15+
{
16+
internal const uint DONTRESOLVEDLLREFERENCES = 0x00000001;
17+
internal const uint LOADLIBRARYASDATAFILE = 0x00000002;
18+
19+
[DllImport("shell32.dll", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode)]
20+
internal static extern int SHGetLocalizedName(string pszPath, StringBuilder pszResModule, ref int cch, out int pidsRes);
21+
22+
[DllImport("user32.dll", EntryPoint = "LoadStringW", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode)]
23+
internal static extern int LoadString(IntPtr hModule, int resourceID, StringBuilder resourceValue, int len);
24+
25+
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, EntryPoint = "LoadLibraryExW")]
26+
internal static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, uint dwFlags);
27+
28+
[DllImport("kernel32.dll", ExactSpelling = true)]
29+
internal static extern int FreeLibrary(IntPtr hModule);
30+
31+
[DllImport("kernel32.dll", EntryPoint = "ExpandEnvironmentStringsW", CharSet = CharSet.Unicode, ExactSpelling = true)]
32+
internal static extern uint ExpandEnvironmentStrings(string lpSrc, StringBuilder lpDst, int nSize);
33+
34+
/// <summary>
35+
/// Returns the localized name of a shell item.
36+
/// </summary>
37+
/// <param name="path">Path to the shell item (e. g. shortcut 'File Explorer.lnk').</param>
38+
/// <returns>The localized name as string or <see cref="string.Empty"/>.</returns>
39+
public static string GetLocalizedName(string path)
40+
{
41+
StringBuilder resourcePath = new StringBuilder(1024);
42+
StringBuilder localizedName = new StringBuilder(1024);
43+
int len, id;
44+
len = resourcePath.Capacity;
45+
46+
// If there is no resource to localize a file name the method returns a non zero value.
47+
if (SHGetLocalizedName(path, resourcePath, ref len, out id) == 0)
48+
{
49+
_ = ExpandEnvironmentStrings(resourcePath.ToString(), resourcePath, resourcePath.Capacity);
50+
IntPtr hMod = LoadLibraryEx(resourcePath.ToString(), IntPtr.Zero, DONTRESOLVEDLLREFERENCES | LOADLIBRARYASDATAFILE);
51+
if (hMod != IntPtr.Zero)
52+
{
53+
if (LoadString(hMod, id, localizedName, localizedName.Capacity) != 0)
54+
{
55+
string lString = localizedName.ToString();
56+
_ = FreeLibrary(hMod);
57+
return lString;
58+
}
59+
60+
_ = FreeLibrary(hMod);
61+
}
62+
}
63+
64+
return string.Empty;
65+
}
66+
67+
/// <summary>
68+
/// This method returns the localized path to a shell item (folder or file)
69+
/// </summary>
70+
/// <param name="path">The path to localize</param>
71+
/// <returns>The localized path or the original path if localized version is not available</returns>
72+
public static string GetLocalizedPath(string path)
73+
{
74+
path = Environment.ExpandEnvironmentVariables(path);
75+
string ext = Path.GetExtension(path);
76+
var pathParts = path.Split("\\");
77+
string[] locPath = new string[pathParts.Length];
78+
79+
for (int i = 0; i < pathParts.Length; i++)
80+
{
81+
int iElements = i + 1;
82+
string lName = GetLocalizedName(string.Join("\\", pathParts[..iElements]));
83+
locPath[i] = !string.IsNullOrEmpty(lName) ? lName : pathParts[i];
84+
}
85+
86+
string newPath = string.Join("\\", locPath);
87+
newPath = !newPath.EndsWith(ext, StringComparison.InvariantCultureIgnoreCase) ? newPath + ext : newPath;
88+
89+
return newPath;
90+
}
91+
}
92+
}

Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ public class Win32 : IProgram, IEquatable<Win32>
4444
public bool Enabled { get; set; }
4545
public string Location => ParentDirectory;
4646

47+
// Localized name based on windows display language
48+
public string LocalizedName { get; set; } = string.Empty;
49+
4750
private const string ShortcutExtension = "lnk";
4851
private const string UrlExtension = "url";
4952
private const string ExeExtension = "exe";
@@ -69,27 +72,30 @@ public Result Result(string query, IPublicAPI api)
6972
string title;
7073
MatchResult matchResult;
7174

75+
// Name of the result
76+
string resultName = string.IsNullOrEmpty(LocalizedName) ? Name : LocalizedName;
77+
7278
// We suppose Name won't be null
73-
if (!Main._settings.EnableDescription || Description == null || Name.StartsWith(Description))
79+
if (!Main._settings.EnableDescription || Description == null || resultName.StartsWith(Description))
7480
{
75-
title = Name;
81+
title = resultName;
7682
matchResult = StringMatcher.FuzzySearch(query, title);
7783
}
78-
else if (Description.StartsWith(Name))
84+
else if (Description.StartsWith(resultName))
7985
{
8086
title = Description;
8187
matchResult = StringMatcher.FuzzySearch(query, Description);
8288
}
8389
else
8490
{
85-
title = $"{Name}: {Description}";
86-
var nameMatch = StringMatcher.FuzzySearch(query, Name);
91+
title = $"{resultName}: {Description}";
92+
var nameMatch = StringMatcher.FuzzySearch(query, resultName);
8793
var desciptionMatch = StringMatcher.FuzzySearch(query, Description);
8894
if (desciptionMatch.Score > nameMatch.Score)
8995
{
9096
for (int i = 0; i < desciptionMatch.MatchData.Count; i++)
9197
{
92-
desciptionMatch.MatchData[i] += Name.Length + 2; // 2 is ": "
98+
desciptionMatch.MatchData[i] += resultName.Length + 2; // 2 is ": "
9399
}
94100
matchResult = desciptionMatch;
95101
}
@@ -297,6 +303,8 @@ private static Win32 LnkProgram(string path)
297303
}
298304
}
299305

306+
program.LocalizedName = ShellLocalization.GetLocalizedName(path);
307+
300308
return program;
301309
}
302310
catch (COMException e)

0 commit comments

Comments
 (0)