mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-08 12:18:50 +02:00
@@ -4,20 +4,19 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Width="400"
|
Width="400"
|
||||||
Height="180"
|
Height="120"
|
||||||
WindowStartupLocation="CenterScreen"
|
WindowStartupLocation="CenterScreen">
|
||||||
d:DesignHeight="400" d:DesignWidth="300">
|
|
||||||
<StackPanel Orientation="Vertical">
|
<StackPanel Orientation="Vertical">
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<Label Content="{DynamicResource wox_plugin_program_directory}"/>
|
<Label Content="{DynamicResource wox_plugin_program_directory}"/>
|
||||||
<TextBox Name="Directory" VerticalAlignment="Center" Width="238" Margin="0,7" />
|
<TextBox Name="Directory" VerticalAlignment="Center" Width="300" Margin="0,7" />
|
||||||
<Button Name="BrowseButton" Content="{DynamicResource wox_plugin_program_browse}" HorizontalAlignment="Left" VerticalAlignment="Center" Width="75" Click="BrowseButton_Click" />
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
|
||||||
<Label Content="{DynamicResource wox_plugin_program_max_search_depth}" />
|
<Button Click="BrowseButton_Click" Content="{DynamicResource wox_plugin_program_browse}"
|
||||||
<TextBox Name="MaxDepth" Text="-1" VerticalAlignment="Center" Width="146" Margin="0,7" />
|
HorizontalAlignment="Right" Margin="10" Height="20" Width="70" />
|
||||||
|
<Button Click="ButtonAdd_OnClick" Content="{DynamicResource wox_plugin_program_update}"
|
||||||
|
HorizontalAlignment="Right" Margin="10" Height="20" Width="70" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<Button VerticalAlignment="Center" HorizontalAlignment="Right" Margin="10" Height="20" Width="70" Click="ButtonAdd_OnClick" Content="{DynamicResource wox_plugin_program_update}" />
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Window>
|
</Window>
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ namespace Wox.Plugin.Program
|
|||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
Directory.Text = _editing.Location;
|
Directory.Text = _editing.Location;
|
||||||
MaxDepth.Text = _editing.MaxDepth.ToString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BrowseButton_Click(object sender, RoutedEventArgs e)
|
private void BrowseButton_Click(object sender, RoutedEventArgs e)
|
||||||
@@ -41,25 +40,17 @@ namespace Wox.Plugin.Program
|
|||||||
|
|
||||||
private void ButtonAdd_OnClick(object sender, RoutedEventArgs e)
|
private void ButtonAdd_OnClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
int max;
|
|
||||||
if(!int.TryParse(MaxDepth.Text, out max))
|
|
||||||
{
|
|
||||||
max = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_editing == null)
|
if(_editing == null)
|
||||||
{
|
{
|
||||||
var source = new Settings.ProgramSource
|
var source = new Settings.ProgramSource
|
||||||
{
|
{
|
||||||
Location = Directory.Text,
|
Location = Directory.Text,
|
||||||
MaxDepth = max
|
|
||||||
};
|
};
|
||||||
_settings.ProgramSources.Add(source);
|
_settings.ProgramSources.Add(source);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_editing.Location = Directory.Text;
|
_editing.Location = Directory.Text;
|
||||||
_editing.MaxDepth = max;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DialogResult = true;
|
DialogResult = true;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using Wox.Infrastructure;
|
using Wox.Infrastructure;
|
||||||
using Wox.Infrastructure.Logger;
|
using Wox.Infrastructure.Logger;
|
||||||
@@ -14,8 +15,8 @@ namespace Wox.Plugin.Program
|
|||||||
{
|
{
|
||||||
public class Main : ISettingProvider, IPlugin, IPluginI18n, IContextMenu, ISavable
|
public class Main : ISettingProvider, IPlugin, IPluginI18n, IContextMenu, ISavable
|
||||||
{
|
{
|
||||||
private static List<Win32> _programs = new List<Win32>();
|
private static Win32[] _win32s = { };
|
||||||
private static List<UWP> _uwps = new List<UWP>();
|
private static UWP[] _uwps = { };
|
||||||
|
|
||||||
private PluginInitContext _context;
|
private PluginInitContext _context;
|
||||||
|
|
||||||
@@ -33,22 +34,22 @@ namespace Wox.Plugin.Program
|
|||||||
{
|
{
|
||||||
_cacheStorage = new BinaryStorage<ProgramIndexCache>();
|
_cacheStorage = new BinaryStorage<ProgramIndexCache>();
|
||||||
_cache = _cacheStorage.Load();
|
_cache = _cacheStorage.Load();
|
||||||
_programs = _cache.Programs;
|
_win32s = _cache.Programs;
|
||||||
});
|
});
|
||||||
Log.Info($"Preload {_programs.Count} programs from cache");
|
Log.Info($"Preload {_win32s.Length} programs from cache");
|
||||||
Stopwatch.Debug("Program Index", IndexPrograms);
|
Stopwatch.Debug("Program Index", IndexPrograms);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Save()
|
public void Save()
|
||||||
{
|
{
|
||||||
_settingsStorage.Save();
|
_settingsStorage.Save();
|
||||||
_cache.Programs = _programs;
|
_cache.Programs = _win32s;
|
||||||
_cacheStorage.Save();
|
_cacheStorage.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Result> Query(Query query)
|
public List<Result> Query(Query query)
|
||||||
{
|
{
|
||||||
var results1 = _programs.AsParallel()
|
var results1 = _win32s.AsParallel()
|
||||||
.Where(p => Score(p, query.Search) > 0)
|
.Where(p => Score(p, query.Search) > 0)
|
||||||
.Select(ResultFromProgram);
|
.Select(ResultFromProgram);
|
||||||
|
|
||||||
@@ -64,8 +65,8 @@ namespace Wox.Plugin.Program
|
|||||||
{
|
{
|
||||||
var result = new Result
|
var result = new Result
|
||||||
{
|
{
|
||||||
Title = p.Title,
|
Title = p.FullName,
|
||||||
SubTitle = p.ExecutablePath,
|
SubTitle = p.FullPath,
|
||||||
IcoPath = p.IcoPath,
|
IcoPath = p.IcoPath,
|
||||||
Score = p.Score,
|
Score = p.Score,
|
||||||
ContextData = p,
|
ContextData = p,
|
||||||
@@ -73,8 +74,8 @@ namespace Wox.Plugin.Program
|
|||||||
{
|
{
|
||||||
var info = new ProcessStartInfo
|
var info = new ProcessStartInfo
|
||||||
{
|
{
|
||||||
FileName = p.ExecutablePath,
|
FileName = p.FullPath,
|
||||||
WorkingDirectory = p.Directory
|
WorkingDirectory = p.ParentDirectory
|
||||||
};
|
};
|
||||||
var hide = StartProcess(info);
|
var hide = StartProcess(info);
|
||||||
return hide;
|
return hide;
|
||||||
@@ -104,8 +105,8 @@ namespace Wox.Plugin.Program
|
|||||||
|
|
||||||
private int Score(Win32 program, string query)
|
private int Score(Win32 program, string query)
|
||||||
{
|
{
|
||||||
var score1 = StringMatcher.Score(program.Title, query);
|
var score1 = StringMatcher.Score(program.FullName, query);
|
||||||
var score2 = StringMatcher.ScoreForPinyin(program.Title, query);
|
var score2 = StringMatcher.ScoreForPinyin(program.FullName, query);
|
||||||
var score3 = StringMatcher.Score(program.ExecutableName, query);
|
var score3 = StringMatcher.Score(program.ExecutableName, query);
|
||||||
var score = new[] { score1, score2, score3 }.Max();
|
var score = new[] { score1, score2, score3 }.Max();
|
||||||
program.Score = score;
|
program.Score = score;
|
||||||
@@ -129,51 +130,10 @@ namespace Wox.Plugin.Program
|
|||||||
|
|
||||||
public static void IndexPrograms()
|
public static void IndexPrograms()
|
||||||
{
|
{
|
||||||
_programs = AllWin32Programs();
|
_win32s = Win32.All(_settings);
|
||||||
_uwps = UWP.All();
|
_uwps = UWP.All();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<Win32> AllWin32Programs()
|
|
||||||
{
|
|
||||||
var appPaths = AppPathsPrograms.All();
|
|
||||||
var startMenu = StartMenu.All(_settings.ProgramSuffixes);
|
|
||||||
var unregistered = UnregisteredPrograms.All(_settings.ProgramSources, _settings.ProgramSuffixes);
|
|
||||||
var programs = appPaths.Concat(startMenu).Concat(unregistered);
|
|
||||||
|
|
||||||
programs = programs.AsParallel()
|
|
||||||
// filter duplicate program
|
|
||||||
.GroupBy(x => new { ExecutePath = x.ExecutablePath, ExecuteName = x.ExecutableName })
|
|
||||||
.Select(g => g.First())
|
|
||||||
.Select(ScoreFilter);
|
|
||||||
|
|
||||||
return programs.ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Win32 ScoreFilter(Win32 p)
|
|
||||||
{
|
|
||||||
var start = new[] { "启动", "start" };
|
|
||||||
var doc = new[] { "帮助", "help", "文档", "documentation" };
|
|
||||||
var uninstall = new[] { "卸载", "uninstall" };
|
|
||||||
|
|
||||||
var contained = start.Any(s => p.Title.ToLower().Contains(s));
|
|
||||||
if (contained)
|
|
||||||
{
|
|
||||||
p.Score += 10;
|
|
||||||
}
|
|
||||||
contained = doc.Any(d => p.Title.ToLower().Contains(d));
|
|
||||||
if (contained)
|
|
||||||
{
|
|
||||||
p.Score -= 10;
|
|
||||||
}
|
|
||||||
contained = uninstall.Any(u => p.Title.ToLower().Contains(u));
|
|
||||||
if (contained)
|
|
||||||
{
|
|
||||||
p.Score -= 20;
|
|
||||||
}
|
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Control CreateSettingPanel()
|
public Control CreateSettingPanel()
|
||||||
{
|
{
|
||||||
return new ProgramSetting(_context, _settings);
|
return new ProgramSetting(_context, _settings);
|
||||||
@@ -203,8 +163,8 @@ namespace Wox.Plugin.Program
|
|||||||
{
|
{
|
||||||
var info = new ProcessStartInfo
|
var info = new ProcessStartInfo
|
||||||
{
|
{
|
||||||
FileName = p.ExecutablePath,
|
FileName = p.FullPath,
|
||||||
WorkingDirectory = p.Directory,
|
WorkingDirectory = p.ParentDirectory,
|
||||||
Verb = "runas"
|
Verb = "runas"
|
||||||
};
|
};
|
||||||
var hide = StartProcess(info);
|
var hide = StartProcess(info);
|
||||||
@@ -217,7 +177,7 @@ namespace Wox.Plugin.Program
|
|||||||
Title = _context.API.GetTranslation("wox_plugin_program_open_containing_folder"),
|
Title = _context.API.GetTranslation("wox_plugin_program_open_containing_folder"),
|
||||||
Action = _ =>
|
Action = _ =>
|
||||||
{
|
{
|
||||||
var hide = StartProcess(new ProcessStartInfo(p.Directory));
|
var hide = StartProcess(new ProcessStartInfo(p.ParentDirectory));
|
||||||
return hide;
|
return hide;
|
||||||
},
|
},
|
||||||
IcoPath = "Images/folder.png"
|
IcoPath = "Images/folder.png"
|
||||||
|
|||||||
@@ -7,6 +7,6 @@ namespace Wox.Plugin.Program
|
|||||||
[Serializable]
|
[Serializable]
|
||||||
public class ProgramIndexCache
|
public class ProgramIndexCache
|
||||||
{
|
{
|
||||||
public List<Win32> Programs = new List<Win32>();
|
public Win32[] Programs = { };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25,20 +25,13 @@
|
|||||||
Drop="programSourceView_Drop" >
|
Drop="programSourceView_Drop" >
|
||||||
<ListView.View>
|
<ListView.View>
|
||||||
<GridView>
|
<GridView>
|
||||||
<GridViewColumn Header="{DynamicResource wox_plugin_program_location}" Width="450">
|
<GridViewColumn Header="{DynamicResource wox_plugin_program_location}" Width="550">
|
||||||
<GridViewColumn.CellTemplate>
|
<GridViewColumn.CellTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<TextBlock Text="{Binding Location, ConverterParameter=(null), Converter={program:LocationConverter}}"/>
|
<TextBlock Text="{Binding Location, ConverterParameter=(null), Converter={program:LocationConverter}}"/>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</GridViewColumn.CellTemplate>
|
</GridViewColumn.CellTemplate>
|
||||||
</GridViewColumn>
|
</GridViewColumn>
|
||||||
<GridViewColumn Header="{DynamicResource wox_plugin_program_max_depth_header}" Width="130">
|
|
||||||
<GridViewColumn.CellTemplate>
|
|
||||||
<DataTemplate>
|
|
||||||
<TextBlock Text="{Binding MaxDepth, ConverterParameter=(null)}"/>
|
|
||||||
</DataTemplate>
|
|
||||||
</GridViewColumn.CellTemplate>
|
|
||||||
</GridViewColumn>
|
|
||||||
</GridView>
|
</GridView>
|
||||||
</ListView.View>
|
</ListView.View>
|
||||||
</ListView>
|
</ListView>
|
||||||
|
|||||||
@@ -1,68 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.Win32;
|
|
||||||
|
|
||||||
namespace Wox.Plugin.Program.Programs
|
|
||||||
{
|
|
||||||
[Serializable]
|
|
||||||
public class AppPathsPrograms : Win32
|
|
||||||
{
|
|
||||||
public static IEnumerable<Win32> All()
|
|
||||||
{
|
|
||||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ee872121
|
|
||||||
var programs = new List<Win32>();
|
|
||||||
const string appPaths = @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths";
|
|
||||||
using (var root = Registry.LocalMachine.OpenSubKey(appPaths))
|
|
||||||
{
|
|
||||||
if (root != null)
|
|
||||||
{
|
|
||||||
programs.AddRange(ProgramsFromRegistryKey(root));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
using (var root = Registry.CurrentUser.OpenSubKey(appPaths))
|
|
||||||
{
|
|
||||||
if (root != null)
|
|
||||||
{
|
|
||||||
programs.AddRange(ProgramsFromRegistryKey(root));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return programs;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<Win32> ProgramsFromRegistryKey(RegistryKey root)
|
|
||||||
{
|
|
||||||
var programs = root.GetSubKeyNames()
|
|
||||||
.Select(subkey => ProgramFromRegistrySubkey(root, subkey))
|
|
||||||
.Where(p => !string.IsNullOrEmpty(p.Title));
|
|
||||||
return programs;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Win32 ProgramFromRegistrySubkey(RegistryKey root, string subkey)
|
|
||||||
{
|
|
||||||
using (var key = root.OpenSubKey(subkey))
|
|
||||||
{
|
|
||||||
if (key != null)
|
|
||||||
{
|
|
||||||
var defaultValue = string.Empty;
|
|
||||||
var path = key.GetValue(defaultValue) as string;
|
|
||||||
if (!string.IsNullOrEmpty(path))
|
|
||||||
{
|
|
||||||
// fix path like this: ""\"C:\\folder\\executable.exe\""
|
|
||||||
path = path.Trim('"');
|
|
||||||
path = Environment.ExpandEnvironmentVariables(path);
|
|
||||||
|
|
||||||
if (File.Exists(path))
|
|
||||||
{
|
|
||||||
var entry = CreateEntry(path);
|
|
||||||
entry.ExecutableName = subkey;
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new Win32();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Wox.Plugin.Program.Programs
|
|
||||||
{
|
|
||||||
[Serializable]
|
|
||||||
class StartMenu : Win32
|
|
||||||
{
|
|
||||||
public static IEnumerable<Win32> All(string[] suffixes)
|
|
||||||
{
|
|
||||||
var directory1 = Environment.GetFolderPath(Environment.SpecialFolder.Programs);
|
|
||||||
var directory2 = Environment.GetFolderPath(Environment.SpecialFolder.CommonPrograms);
|
|
||||||
var programs = new List<Win32>();
|
|
||||||
GetAppFromDirectory(programs, directory1, -1, suffixes);
|
|
||||||
GetAppFromDirectory(programs, directory2, -1, suffixes);
|
|
||||||
return programs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -37,6 +37,10 @@ namespace Wox.Plugin.Program.Programs
|
|||||||
|
|
||||||
public int Score { get; set; }
|
public int Score { get; set; }
|
||||||
|
|
||||||
|
public UWP()
|
||||||
|
{
|
||||||
|
Apps = new Application[] { };
|
||||||
|
}
|
||||||
public UWP(Package package)
|
public UWP(Package package)
|
||||||
{
|
{
|
||||||
Package = package;
|
Package = package;
|
||||||
@@ -118,37 +122,32 @@ namespace Wox.Plugin.Program.Programs
|
|||||||
}).ToArray();
|
}).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<UWP> All()
|
public static UWP[] All()
|
||||||
{
|
{
|
||||||
var windows10 = new Version(10, 0);
|
var windows10 = new Version(10, 0);
|
||||||
var support = Environment.OSVersion.Version.Major >= windows10.Major;
|
var support = Environment.OSVersion.Version.Major >= windows10.Major;
|
||||||
if (support)
|
if (support)
|
||||||
{
|
{
|
||||||
var packages = CurrentUserPackages();
|
var packages = CurrentUserPackages().AsParallel().Select(p =>
|
||||||
var uwps = new List<UWP>();
|
|
||||||
// todo use parallel linq
|
|
||||||
Parallel.ForEach(packages, p =>
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var u = new UWP(p);
|
var u = new UWP(p);
|
||||||
if (u.Apps.Length > 0)
|
return u;
|
||||||
{
|
|
||||||
uwps.Add(u);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
// if there are errors, just ignore it and continue
|
// if there are errors, just ignore it and continue
|
||||||
var message = $"Can't parse {p.Id.Name}: {e.Message}";
|
var message = $"Can't parse {p.Id.Name}: {e.Message}";
|
||||||
Log.Error(message);
|
Log.Error(message);
|
||||||
|
return new UWP();
|
||||||
}
|
}
|
||||||
});
|
}).Where(u => u.Apps.Length > 0);
|
||||||
return uwps;
|
return packages.ToArray();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return new List<UWP>();
|
return new UWP[] { };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace Wox.Plugin.Program.Programs
|
|
||||||
{
|
|
||||||
[Serializable]
|
|
||||||
public class UnregisteredPrograms : Win32
|
|
||||||
{
|
|
||||||
public static List<Win32> All(List<Settings.ProgramSource> sources, string[] suffixes)
|
|
||||||
{
|
|
||||||
List<Win32> programs = new List<Win32>();
|
|
||||||
foreach (var source in sources)
|
|
||||||
{
|
|
||||||
if (System.IO.Directory.Exists(source.Location) && source.MaxDepth >= -1)
|
|
||||||
{
|
|
||||||
GetAppFromDirectory(programs, source.Location, source.MaxDepth, suffixes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return programs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,9 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Wox.Infrastructure.Exception;
|
using System.Windows;
|
||||||
|
using IWshRuntimeLibrary;
|
||||||
|
using Microsoft.Win32;
|
||||||
using Wox.Infrastructure.Logger;
|
using Wox.Infrastructure.Logger;
|
||||||
|
|
||||||
namespace Wox.Plugin.Program.Programs
|
namespace Wox.Plugin.Program.Programs
|
||||||
@@ -11,80 +13,231 @@ namespace Wox.Plugin.Program.Programs
|
|||||||
[Serializable]
|
[Serializable]
|
||||||
public class Win32
|
public class Win32
|
||||||
{
|
{
|
||||||
public string Title { get; set; }
|
public string FullName { get; set; }
|
||||||
public string IcoPath { get; set; }
|
public string IcoPath { get; set; }
|
||||||
public string ExecutablePath { get; set; }
|
public string FullPath { get; set; }
|
||||||
public string Directory { get; set; }
|
public string ParentDirectory { get; set; }
|
||||||
public string ExecutableName { get; set; }
|
public string ExecutableName { get; set; }
|
||||||
public int Score { get; set; }
|
public int Score { get; set; }
|
||||||
|
|
||||||
protected static Win32 CreateEntry(string file)
|
private const string ShortcutExtension = "lnk";
|
||||||
|
private const string ApplicationReferenceExtension = "appref-ms";
|
||||||
|
private const string ExeExtension = "exe";
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return ExecutableName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Win32 Win32Program(string path)
|
||||||
{
|
{
|
||||||
var p = new Win32
|
var p = new Win32
|
||||||
{
|
{
|
||||||
Title = Path.GetFileNameWithoutExtension(file),
|
FullName = Path.GetFileNameWithoutExtension(path),
|
||||||
IcoPath = file,
|
IcoPath = path,
|
||||||
ExecutablePath = file,
|
FullPath = path,
|
||||||
Directory = System.IO.Directory.GetParent(file).FullName
|
ParentDirectory = Directory.GetParent(path).FullName,
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (Path.GetExtension(file).ToLower())
|
|
||||||
{
|
|
||||||
case ".exe":
|
|
||||||
p.ExecutableName = Path.GetFileName(file);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var versionInfo = FileVersionInfo.GetVersionInfo(file);
|
|
||||||
if (!string.IsNullOrEmpty(versionInfo.FileDescription))
|
|
||||||
{
|
|
||||||
p.Title = versionInfo.FileDescription;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static void GetAppFromDirectory(List<Win32> apps, string directory, int depth, string[] suffixes)
|
private static Win32 LnkProgram(string path)
|
||||||
{
|
{
|
||||||
if (depth == -1)
|
var shell = new WshShell();
|
||||||
|
var shortcut = (IWshShortcut)shell.CreateShortcut(path);
|
||||||
|
var program = Win32Program(path);
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
|
var description = shortcut.Description;
|
||||||
|
if (!string.IsNullOrEmpty(description))
|
||||||
|
{
|
||||||
|
program.FullName += $": {description}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(shortcut.TargetPath))
|
||||||
|
{
|
||||||
|
var info = FileVersionInfo.GetVersionInfo(shortcut.TargetPath);
|
||||||
|
if (!string.IsNullOrEmpty(info.FileDescription))
|
||||||
|
{
|
||||||
|
program.FullName += $": {info.FileDescription}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return program;
|
||||||
}
|
}
|
||||||
else if (depth > 0)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
depth = depth - 1;
|
Log.Error($"Error when parsing shortcut: {path}");
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Win32 ExeProgram(string path)
|
||||||
|
{
|
||||||
|
var program = Win32Program(path);
|
||||||
|
var versionInfo = FileVersionInfo.GetVersionInfo(path);
|
||||||
|
if (!string.IsNullOrEmpty(versionInfo.FileDescription))
|
||||||
|
{
|
||||||
|
program.FullName = versionInfo.FileDescription;
|
||||||
|
}
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<string> ProgramPaths(string directory, string[] suffixes)
|
||||||
|
{
|
||||||
|
if (Directory.Exists(directory))
|
||||||
|
{
|
||||||
|
var files = Directory.EnumerateFiles(directory, "*", SearchOption.AllDirectories).Where(
|
||||||
|
f => suffixes.Contains(Extension(f))
|
||||||
|
);
|
||||||
|
return files;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return;
|
return new string[] { };
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var f in System.IO.Directory.GetFiles(directory))
|
private static string Extension(string path)
|
||||||
|
{
|
||||||
|
var extension = Path.GetExtension(path)?.ToLower();
|
||||||
|
if (!string.IsNullOrEmpty(extension))
|
||||||
{
|
{
|
||||||
if (suffixes.Any(o => f.EndsWith("." + o)))
|
return extension.Substring(1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ParallelQuery<Win32> UnregisteredPrograms(List<Settings.ProgramSource> sources, string[] suffixes)
|
||||||
|
{
|
||||||
|
var paths = sources.Where(s => Directory.Exists(s.Location))
|
||||||
|
.SelectMany(s => ProgramPaths(s.Location, suffixes))
|
||||||
|
.ToArray();
|
||||||
|
var programs1 = paths.AsParallel().Where(p => Extension(p) == ExeExtension).Select(ExeProgram);
|
||||||
|
var programs2 = paths.AsParallel().Where(p => Extension(p) == ShortcutExtension).Select(ExeProgram);
|
||||||
|
var programs3 = from p in paths.AsParallel()
|
||||||
|
let e = Extension(p)
|
||||||
|
where e != ShortcutExtension && e != ExeExtension
|
||||||
|
select Win32Program(p);
|
||||||
|
return programs1.Concat(programs2).Concat(programs3);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ParallelQuery<Win32> StartMenuPrograms(string[] suffixes)
|
||||||
|
{
|
||||||
|
var directory1 = Environment.GetFolderPath(Environment.SpecialFolder.Programs);
|
||||||
|
var directory2 = Environment.GetFolderPath(Environment.SpecialFolder.CommonPrograms);
|
||||||
|
var paths1 = ProgramPaths(directory1, suffixes);
|
||||||
|
var paths2 = ProgramPaths(directory2, suffixes);
|
||||||
|
var paths = paths1.Concat(paths2).ToArray();
|
||||||
|
var programs1 = paths.AsParallel().Where(p => Extension(p) == ShortcutExtension).Select(LnkProgram);
|
||||||
|
var programs2 = paths.AsParallel().Where(p => Extension(p) == ApplicationReferenceExtension).Select(Win32Program);
|
||||||
|
return programs1.Concat(programs2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static ParallelQuery<Win32> AppPathsPrograms(string[] suffixes)
|
||||||
|
{
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/ee872121
|
||||||
|
const string appPaths = @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths";
|
||||||
|
var programs = new List<Win32>();
|
||||||
|
using (var root = Registry.LocalMachine.OpenSubKey(appPaths))
|
||||||
|
{
|
||||||
|
if (root != null)
|
||||||
{
|
{
|
||||||
Win32 p;
|
programs.AddRange(ProgramsFromRegistryKey(root));
|
||||||
try
|
|
||||||
{
|
|
||||||
p = CreateEntry(f);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
var woxPluginException = new WoxPluginException("Program",
|
|
||||||
$"GetAppFromDirectory failed: {directory}", e);
|
|
||||||
Log.Exception(woxPluginException);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
apps.Add(p);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach (var d in System.IO.Directory.GetDirectories(directory))
|
using (var root = Registry.CurrentUser.OpenSubKey(appPaths))
|
||||||
{
|
{
|
||||||
GetAppFromDirectory(apps, d, depth, suffixes);
|
if (root != null)
|
||||||
|
{
|
||||||
|
programs.AddRange(ProgramsFromRegistryKey(root));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
var filtered = programs.AsParallel().Where(p => suffixes.Contains(Extension(p.ExecutableName)));
|
||||||
|
return filtered;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<Win32> ProgramsFromRegistryKey(RegistryKey root)
|
||||||
|
{
|
||||||
|
var programs = root.GetSubKeyNames()
|
||||||
|
.Select(subkey => ProgramFromRegistrySubkey(root, subkey))
|
||||||
|
.Where(p => !string.IsNullOrEmpty(p.FullName));
|
||||||
|
return programs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Win32 ProgramFromRegistrySubkey(RegistryKey root, string subkey)
|
||||||
|
{
|
||||||
|
using (var key = root.OpenSubKey(subkey))
|
||||||
|
{
|
||||||
|
if (key != null)
|
||||||
|
{
|
||||||
|
var defaultValue = string.Empty;
|
||||||
|
var path = key.GetValue(defaultValue) as string;
|
||||||
|
if (!string.IsNullOrEmpty(path))
|
||||||
|
{
|
||||||
|
// fix path like this: ""\"C:\\folder\\executable.exe\""
|
||||||
|
path = path.Trim('"');
|
||||||
|
path = Environment.ExpandEnvironmentVariables(path);
|
||||||
|
|
||||||
|
if (System.IO.File.Exists(path))
|
||||||
|
{
|
||||||
|
var entry = Win32Program(path);
|
||||||
|
entry.ExecutableName = subkey;
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new Win32();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Win32 ScoreFilter(Win32 p)
|
||||||
|
{
|
||||||
|
var start = new[] { "启动", "start" };
|
||||||
|
var doc = new[] { "帮助", "help", "文档", "documentation" };
|
||||||
|
var uninstall = new[] { "卸载", "uninstall" };
|
||||||
|
|
||||||
|
var contained = start.Any(s => p.FullName.ToLower().Contains(s));
|
||||||
|
if (contained)
|
||||||
|
{
|
||||||
|
p.Score += 10;
|
||||||
|
}
|
||||||
|
contained = doc.Any(d => p.FullName.ToLower().Contains(d));
|
||||||
|
if (contained)
|
||||||
|
{
|
||||||
|
p.Score -= 10;
|
||||||
|
}
|
||||||
|
contained = uninstall.Any(u => p.FullName.ToLower().Contains(u));
|
||||||
|
if (contained)
|
||||||
|
{
|
||||||
|
p.Score -= 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Win32[] All(Settings settings)
|
||||||
|
{
|
||||||
|
ParallelQuery<Win32> programs = new List<Win32>().AsParallel();
|
||||||
|
if (settings.EnableRegistrySource)
|
||||||
|
{
|
||||||
|
var appPaths = AppPathsPrograms(settings.ProgramSuffixes);
|
||||||
|
programs = programs.Concat(appPaths);
|
||||||
|
}
|
||||||
|
if (settings.EnableStartMenuSource)
|
||||||
|
{
|
||||||
|
var startMenu = StartMenuPrograms(settings.ProgramSuffixes);
|
||||||
|
programs = programs.Concat(startMenu);
|
||||||
|
}
|
||||||
|
var unregistered = UnregisteredPrograms(settings.ProgramSources, settings.ProgramSuffixes);
|
||||||
|
programs = programs.Concat(unregistered).Select(ScoreFilter);
|
||||||
|
return programs.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ namespace Wox.Plugin.Program
|
|||||||
public class ProgramSource
|
public class ProgramSource
|
||||||
{
|
{
|
||||||
public string Location { get; set; }
|
public string Location { get; set; }
|
||||||
public int MaxDepth { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,6 @@
|
|||||||
<DependentUpon>AddProgramSource.xaml</DependentUpon>
|
<DependentUpon>AddProgramSource.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="FileChangeWatcher.cs" />
|
<Compile Include="FileChangeWatcher.cs" />
|
||||||
<Compile Include="Programs\StartMenu.cs" />
|
|
||||||
<Compile Include="Programs\UWP.cs" />
|
<Compile Include="Programs\UWP.cs" />
|
||||||
<Compile Include="Programs\Win32.cs" />
|
<Compile Include="Programs\Win32.cs" />
|
||||||
<Compile Include="SuffixesConverter.cs" />
|
<Compile Include="SuffixesConverter.cs" />
|
||||||
@@ -80,8 +79,6 @@
|
|||||||
<Compile Include="ProgramSetting.xaml.cs">
|
<Compile Include="ProgramSetting.xaml.cs">
|
||||||
<DependentUpon>ProgramSetting.xaml</DependentUpon>
|
<DependentUpon>ProgramSetting.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Programs\AppPathsPrograms.cs" />
|
|
||||||
<Compile Include="Programs\UnregisteredPrograms.cs" />
|
|
||||||
<Compile Include="Settings.cs" />
|
<Compile Include="Settings.cs" />
|
||||||
<Compile Include="ProgramSuffixes.xaml.cs">
|
<Compile Include="ProgramSuffixes.xaml.cs">
|
||||||
<DependentUpon>ProgramSuffixes.xaml</DependentUpon>
|
<DependentUpon>ProgramSuffixes.xaml</DependentUpon>
|
||||||
@@ -154,6 +151,17 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Analyzer Include="..\..\packages\UwpDesktop.10.0.10586.2\analyzers\dotnet\UwpDesktopAnalyzer.dll" />
|
<Analyzer Include="..\..\packages\UwpDesktop.10.0.10586.2\analyzers\dotnet\UwpDesktopAnalyzer.dll" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<COMReference Include="IWshRuntimeLibrary">
|
||||||
|
<Guid>{F935DC20-1CF0-11D0-ADB9-00C04FD58A0B}</Guid>
|
||||||
|
<VersionMajor>1</VersionMajor>
|
||||||
|
<VersionMinor>0</VersionMinor>
|
||||||
|
<Lcid>0</Lcid>
|
||||||
|
<WrapperTool>tlbimp</WrapperTool>
|
||||||
|
<Isolated>False</Isolated>
|
||||||
|
<EmbedInteropTypes>True</EmbedInteropTypes>
|
||||||
|
</COMReference>
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<Import Project="..\..\packages\UwpDesktop.10.0.10586.2\build\portable-net45+uap\UwpDesktop.targets" Condition="Exists('..\..\packages\UwpDesktop.10.0.10586.2\build\portable-net45+uap\UwpDesktop.targets')" />
|
<Import Project="..\..\packages\UwpDesktop.10.0.10586.2\build\portable-net45+uap\UwpDesktop.targets" Condition="Exists('..\..\packages\UwpDesktop.10.0.10586.2\build\portable-net45+uap\UwpDesktop.targets')" />
|
||||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||||
|
|||||||
@@ -33,6 +33,12 @@ namespace Wox.Core.Plugin
|
|||||||
|
|
||||||
foreach (var metadata in metadatas)
|
foreach (var metadata in metadatas)
|
||||||
{
|
{
|
||||||
|
#if DEBUG
|
||||||
|
var assembly = Assembly.Load(AssemblyName.GetAssemblyName(metadata.ExecuteFilePath));
|
||||||
|
var types = assembly.GetTypes();
|
||||||
|
var type = types.First(o => o.IsClass && !o.IsAbstract && o.GetInterfaces().Contains(typeof(IPlugin)));
|
||||||
|
var plugin = (IPlugin)Activator.CreateInstance(type);
|
||||||
|
#else
|
||||||
Assembly assembly;
|
Assembly assembly;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -64,6 +70,7 @@ namespace Wox.Core.Plugin
|
|||||||
Log.Exception(new WoxPluginException(metadata.Name, "Can't create instance", e));
|
Log.Exception(new WoxPluginException(metadata.Name, "Can't create instance", e));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
PluginPair pair = new PluginPair
|
PluginPair pair = new PluginPair
|
||||||
{
|
{
|
||||||
Plugin = plugin,
|
Plugin = plugin,
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ namespace Wox.Infrastructure.Logger
|
|||||||
public static void Exception(System.Exception e)
|
public static void Exception(System.Exception e)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
throw e;
|
|
||||||
#else
|
#else
|
||||||
var type = CallerType();
|
var type = CallerType();
|
||||||
var logger = LogManager.GetLogger(type);
|
var logger = LogManager.GetLogger(type);
|
||||||
|
|||||||
Reference in New Issue
Block a user