Skip to content

Commit a8d4f5d

Browse files
Merge pull request #1736 from VictoriousRaptor/LocalizedLnkName
Use localized name for shell link programs
2 parents b338494 + 804a5d5 commit a8d4f5d

File tree

4 files changed

+223
-84
lines changed

4 files changed

+223
-84
lines changed

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

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Runtime.InteropServices;
44
using Accessibility;
55
using System.Runtime.InteropServices.ComTypes;
6+
using Flow.Launcher.Plugin.Program.Logger;
67

78
namespace Flow.Launcher.Plugin.Program.Programs
89
{
@@ -119,9 +120,19 @@ public string retrieveTargetPath(string path)
119120
// To set the app description
120121
if (!String.IsNullOrEmpty(target))
121122
{
122-
buffer = new StringBuilder(MAX_PATH);
123-
((IShellLinkW)link).GetDescription(buffer, MAX_PATH);
124-
description = buffer.ToString();
123+
try
124+
{
125+
buffer = new StringBuilder(MAX_PATH);
126+
((IShellLinkW)link).GetDescription(buffer, MAX_PATH);
127+
description = buffer.ToString();
128+
}
129+
catch (COMException e)
130+
{
131+
// C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\MiracastView.lnk always cause exception
132+
ProgramLogger.LogException($"|IShellLinkW|retrieveTargetPath|{path}" +
133+
"|Error caused likely due to trying to get the description of the program",
134+
e);
135+
}
125136

126137
buffer.Clear();
127138
((IShellLinkW)link).GetArguments(buffer, MAX_PATH);
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/UWP.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -249,24 +249,24 @@ public static bool SupportUWP()
249249

250250
private static IEnumerable<Package> CurrentUserPackages()
251251
{
252-
var u = WindowsIdentity.GetCurrent().User;
252+
var user = WindowsIdentity.GetCurrent().User;
253253

254-
if (u != null)
254+
if (user != null)
255255
{
256-
var id = u.Value;
257-
PackageManager m;
256+
var userId = user.Value;
257+
PackageManager packageManager;
258258
try
259259
{
260-
m = new PackageManager();
260+
packageManager = new PackageManager();
261261
}
262262
catch
263263
{
264264
// Bug from https://github.com/microsoft/CsWinRT, using Microsoft.Windows.SDK.NET.Ref 10.0.19041.0.
265265
// Only happens on the first time, so a try catch can fix it.
266-
m = new PackageManager();
266+
packageManager = new PackageManager();
267267
}
268-
var ps = m.FindPackagesForUser(id);
269-
ps = ps.Where(p =>
268+
var packages = packageManager.FindPackagesForUser(userId);
269+
packages = packages.Where(p =>
270270
{
271271
try
272272
{
@@ -277,12 +277,12 @@ private static IEnumerable<Package> CurrentUserPackages()
277277
}
278278
catch (Exception e)
279279
{
280-
ProgramLogger.LogException("UWP", "CurrentUserPackages", $"{id}", "An unexpected error occurred and "
280+
ProgramLogger.LogException("UWP", "CurrentUserPackages", $"{p.Id.FullName}", "An unexpected error occurred and "
281281
+ $"unable to verify if package is valid", e);
282282
return false;
283283
}
284284
});
285-
return ps;
285+
return packages;
286286
}
287287
else
288288
{

0 commit comments

Comments
 (0)