Merge pull request #134 from jjw24/everythingFixes

Everythingfixes
This commit is contained in:
Jeremy Wu 2020-01-26 19:05:30 +09:30 committed by GitHub
commit 9b970ae1a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 275 additions and 197 deletions

View File

@ -2,76 +2,36 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Threading;
using Wox.Infrastructure.Logger;
using Wox.Plugin.Everything.Everything.Exceptions; using Wox.Plugin.Everything.Everything.Exceptions;
namespace Wox.Plugin.Everything.Everything namespace Wox.Plugin.Everything.Everything
{ {
public sealed class EverythingAPI public interface IEverythingApi
{ {
#region DllImport /// <summary>
[DllImport(Main.DLL, CharSet = CharSet.Unicode)] /// Searches the specified key word.
private static extern int Everything_SetSearchW(string lpSearchString); /// </summary>
[DllImport(Main.DLL)] /// <param name="keyWord">The key word.</param>
private static extern void Everything_SetMatchPath(bool bEnable); /// <param name="token">token that allow cancellation</param>
[DllImport(Main.DLL)] /// <param name="offset">The offset.</param>
private static extern void Everything_SetMatchCase(bool bEnable); /// <param name="maxCount">The max count.</param>
[DllImport(Main.DLL)] /// <returns></returns>
private static extern void Everything_SetMatchWholeWord(bool bEnable); List<SearchResult> Search(string keyWord, CancellationToken token, int offset = 0, int maxCount = 100);
[DllImport(Main.DLL)]
private static extern void Everything_SetRegex(bool bEnable);
[DllImport(Main.DLL)]
private static extern void Everything_SetMax(int dwMax);
[DllImport(Main.DLL)]
private static extern void Everything_SetOffset(int dwOffset);
[DllImport(Main.DLL)] void Load(string sdkPath);
private static extern bool Everything_GetMatchPath(); }
[DllImport(Main.DLL)]
private static extern bool Everything_GetMatchCase();
[DllImport(Main.DLL)]
private static extern bool Everything_GetMatchWholeWord();
[DllImport(Main.DLL)]
private static extern bool Everything_GetRegex();
[DllImport(Main.DLL)]
private static extern UInt32 Everything_GetMax();
[DllImport(Main.DLL)]
private static extern UInt32 Everything_GetOffset();
[DllImport(Main.DLL, CharSet = CharSet.Unicode)]
private static extern string Everything_GetSearchW();
[DllImport(Main.DLL)]
private static extern StateCode Everything_GetLastError();
[DllImport(Main.DLL, CharSet = CharSet.Unicode)] public sealed class EverythingApi : IEverythingApi
private static extern bool Everything_QueryW(bool bWait); {
private const int BufferSize = 4096;
[DllImport(Main.DLL)] private readonly object _syncObject = new object();
private static extern void Everything_SortResultsByPath(); // cached buffer to remove redundant allocations.
private readonly StringBuilder _buffer = new StringBuilder(BufferSize);
[DllImport(Main.DLL)] public enum StateCode
private static extern int Everything_GetNumFileResults();
[DllImport(Main.DLL)]
private static extern int Everything_GetNumFolderResults();
[DllImport(Main.DLL)]
private static extern int Everything_GetNumResults();
[DllImport(Main.DLL)]
private static extern int Everything_GetTotFileResults();
[DllImport(Main.DLL)]
private static extern int Everything_GetTotFolderResults();
[DllImport(Main.DLL)]
private static extern int Everything_GetTotResults();
[DllImport(Main.DLL)]
private static extern bool Everything_IsVolumeResult(int nIndex);
[DllImport(Main.DLL)]
private static extern bool Everything_IsFolderResult(int nIndex);
[DllImport(Main.DLL)]
private static extern bool Everything_IsFileResult(int nIndex);
[DllImport(Main.DLL, CharSet = CharSet.Unicode)]
private static extern void Everything_GetResultFullPathNameW(int nIndex, StringBuilder lpString, int nMaxCount);
[DllImport(Main.DLL)]
private static extern void Everything_Reset();
#endregion
enum StateCode
{ {
OK, OK,
MemoryError, MemoryError,
@ -87,15 +47,15 @@ namespace Wox.Plugin.Everything.Everything
/// Gets or sets a value indicating whether [match path]. /// Gets or sets a value indicating whether [match path].
/// </summary> /// </summary>
/// <value><c>true</c> if [match path]; otherwise, <c>false</c>.</value> /// <value><c>true</c> if [match path]; otherwise, <c>false</c>.</value>
public Boolean MatchPath public bool MatchPath
{ {
get get
{ {
return Everything_GetMatchPath(); return EverythingApiDllImport.Everything_GetMatchPath();
} }
set set
{ {
Everything_SetMatchPath(value); EverythingApiDllImport.Everything_SetMatchPath(value);
} }
} }
@ -103,15 +63,15 @@ namespace Wox.Plugin.Everything.Everything
/// Gets or sets a value indicating whether [match case]. /// Gets or sets a value indicating whether [match case].
/// </summary> /// </summary>
/// <value><c>true</c> if [match case]; otherwise, <c>false</c>.</value> /// <value><c>true</c> if [match case]; otherwise, <c>false</c>.</value>
public Boolean MatchCase public bool MatchCase
{ {
get get
{ {
return Everything_GetMatchCase(); return EverythingApiDllImport.Everything_GetMatchCase();
} }
set set
{ {
Everything_SetMatchCase(value); EverythingApiDllImport.Everything_SetMatchCase(value);
} }
} }
@ -119,15 +79,15 @@ namespace Wox.Plugin.Everything.Everything
/// Gets or sets a value indicating whether [match whole word]. /// Gets or sets a value indicating whether [match whole word].
/// </summary> /// </summary>
/// <value><c>true</c> if [match whole word]; otherwise, <c>false</c>.</value> /// <value><c>true</c> if [match whole word]; otherwise, <c>false</c>.</value>
public Boolean MatchWholeWord public bool MatchWholeWord
{ {
get get
{ {
return Everything_GetMatchWholeWord(); return EverythingApiDllImport.Everything_GetMatchWholeWord();
} }
set set
{ {
Everything_SetMatchWholeWord(value); EverythingApiDllImport.Everything_SetMatchWholeWord(value);
} }
} }
@ -135,15 +95,15 @@ namespace Wox.Plugin.Everything.Everything
/// Gets or sets a value indicating whether [enable regex]. /// Gets or sets a value indicating whether [enable regex].
/// </summary> /// </summary>
/// <value><c>true</c> if [enable regex]; otherwise, <c>false</c>.</value> /// <value><c>true</c> if [enable regex]; otherwise, <c>false</c>.</value>
public Boolean EnableRegex public bool EnableRegex
{ {
get get
{ {
return Everything_GetRegex(); return EverythingApiDllImport.Everything_GetRegex();
} }
set set
{ {
Everything_SetRegex(value); EverythingApiDllImport.Everything_SetRegex(value);
} }
} }
@ -152,61 +112,91 @@ namespace Wox.Plugin.Everything.Everything
/// </summary> /// </summary>
public void Reset() public void Reset()
{ {
Everything_Reset(); lock (_syncObject)
}
private void no()
{ {
switch (Everything_GetLastError()) EverythingApiDllImport.Everything_Reset();
{
case StateCode.CreateThreadError:
throw new CreateThreadException();
case StateCode.CreateWindowError:
throw new CreateWindowException();
case StateCode.InvalidCallError:
throw new InvalidCallException();
case StateCode.InvalidIndexError:
throw new InvalidIndexException();
case StateCode.IPCError:
throw new IPCErrorException();
case StateCode.MemoryError:
throw new MemoryErrorException();
case StateCode.RegisterClassExError:
throw new RegisterClassExException();
} }
} }
/// <summary> /// <summary>
/// Searches the specified key word. /// Searches the specified key word and reset the everything API afterwards
/// </summary> /// </summary>
/// <param name="keyWord">The key word.</param> /// <param name="keyWord">The key word.</param>
/// <param name="token">when cancelled the current search will stop and exit (and would not reset)</param>
/// <param name="offset">The offset.</param> /// <param name="offset">The offset.</param>
/// <param name="maxCount">The max count.</param> /// <param name="maxCount">The max count.</param>
/// <returns></returns> /// <returns></returns>
public IEnumerable<SearchResult> Search(string keyWord, int offset = 0, int maxCount = 100) public List<SearchResult> Search(string keyWord, CancellationToken token, int offset = 0, int maxCount = 100)
{ {
if (string.IsNullOrEmpty(keyWord)) if (string.IsNullOrEmpty(keyWord))
throw new ArgumentNullException("keyWord"); throw new ArgumentNullException(nameof(keyWord));
if (offset < 0) if (offset < 0)
throw new ArgumentOutOfRangeException("offset"); throw new ArgumentOutOfRangeException(nameof(offset));
if (maxCount < 0) if (maxCount < 0)
throw new ArgumentOutOfRangeException("maxCount"); throw new ArgumentOutOfRangeException(nameof(maxCount));
lock (_syncObject)
{
if (keyWord.StartsWith("@")) if (keyWord.StartsWith("@"))
{ {
Everything_SetRegex(true); EverythingApiDllImport.Everything_SetRegex(true);
keyWord = keyWord.Substring(1); keyWord = keyWord.Substring(1);
} }
Everything_SetSearchW(keyWord);
Everything_SetOffset(offset);
Everything_SetMax(maxCount);
EverythingApiDllImport.Everything_SetSearchW(keyWord);
EverythingApiDllImport.Everything_SetOffset(offset);
EverythingApiDllImport.Everything_SetMax(maxCount);
if (!Everything_QueryW(true)) if (token.IsCancellationRequested)
{ {
switch (Everything_GetLastError()) return null;
}
if (!EverythingApiDllImport.Everything_QueryW(true))
{
CheckAndThrowExceptionOnError();
return null;
}
var results = new List<SearchResult>();
for (int idx = 0; idx < EverythingApiDllImport.Everything_GetNumResults(); ++idx)
{
if (token.IsCancellationRequested)
{
return null;
}
EverythingApiDllImport.Everything_GetResultFullPathNameW(idx, _buffer, BufferSize);
var result = new SearchResult { FullPath = _buffer.ToString() };
if (EverythingApiDllImport.Everything_IsFolderResult(idx))
result.Type = ResultType.Folder;
else if (EverythingApiDllImport.Everything_IsFileResult(idx))
result.Type = ResultType.File;
results.Add(result);
}
Reset();
return results;
}
}
[DllImport("kernel32.dll")]
private static extern int LoadLibrary(string name);
public void Load(string sdkPath)
{
LoadLibrary(sdkPath);
}
private static void CheckAndThrowExceptionOnError()
{
switch (EverythingApiDllImport.Everything_GetLastError())
{ {
case StateCode.CreateThreadError: case StateCode.CreateThreadError:
throw new CreateThreadException(); throw new CreateThreadException();
@ -223,23 +213,6 @@ namespace Wox.Plugin.Everything.Everything
case StateCode.RegisterClassExError: case StateCode.RegisterClassExError:
throw new RegisterClassExException(); throw new RegisterClassExException();
} }
yield break;
}
const int bufferSize = 4096;
StringBuilder buffer = new StringBuilder(bufferSize);
for (int idx = 0; idx < Everything_GetNumResults(); ++idx)
{
Everything_GetResultFullPathNameW(idx, buffer, bufferSize);
var result = new SearchResult { FullPath = buffer.ToString() };
if (Everything_IsFolderResult(idx))
result.Type = ResultType.Folder;
else if (Everything_IsFileResult(idx))
result.Type = ResultType.File;
yield return result;
}
} }
} }
} }

View File

@ -0,0 +1,92 @@
using System.Runtime.InteropServices;
using System.Text;
namespace Wox.Plugin.Everything.Everything
{
public sealed class EverythingApiDllImport
{
[DllImport(Main.DLL, CharSet = CharSet.Unicode)]
internal static extern int Everything_SetSearchW(string lpSearchString);
[DllImport(Main.DLL)]
internal static extern void Everything_SetMatchPath(bool bEnable);
[DllImport(Main.DLL)]
internal static extern void Everything_SetMatchCase(bool bEnable);
[DllImport(Main.DLL)]
internal static extern void Everything_SetMatchWholeWord(bool bEnable);
[DllImport(Main.DLL)]
internal static extern void Everything_SetRegex(bool bEnable);
[DllImport(Main.DLL)]
internal static extern void Everything_SetMax(int dwMax);
[DllImport(Main.DLL)]
internal static extern void Everything_SetOffset(int dwOffset);
[DllImport(Main.DLL)]
internal static extern bool Everything_GetMatchPath();
[DllImport(Main.DLL)]
internal static extern bool Everything_GetMatchCase();
[DllImport(Main.DLL)]
internal static extern bool Everything_GetMatchWholeWord();
[DllImport(Main.DLL)]
internal static extern bool Everything_GetRegex();
[DllImport(Main.DLL)]
internal static extern uint Everything_GetMax();
[DllImport(Main.DLL)]
internal static extern uint Everything_GetOffset();
[DllImport(Main.DLL, CharSet = CharSet.Unicode)]
internal static extern string Everything_GetSearchW();
[DllImport(Main.DLL)]
internal static extern EverythingApi.StateCode Everything_GetLastError();
[DllImport(Main.DLL, CharSet = CharSet.Unicode)]
internal static extern bool Everything_QueryW(bool bWait);
[DllImport(Main.DLL)]
internal static extern void Everything_SortResultsByPath();
[DllImport(Main.DLL)]
internal static extern int Everything_GetNumFileResults();
[DllImport(Main.DLL)]
internal static extern int Everything_GetNumFolderResults();
[DllImport(Main.DLL)]
internal static extern int Everything_GetNumResults();
[DllImport(Main.DLL)]
internal static extern int Everything_GetTotFileResults();
[DllImport(Main.DLL)]
internal static extern int Everything_GetTotFolderResults();
[DllImport(Main.DLL)]
internal static extern int Everything_GetTotResults();
[DllImport(Main.DLL)]
internal static extern bool Everything_IsVolumeResult(int nIndex);
[DllImport(Main.DLL)]
internal static extern bool Everything_IsFolderResult(int nIndex);
[DllImport(Main.DLL)]
internal static extern bool Everything_IsFileResult(int nIndex);
[DllImport(Main.DLL, CharSet = CharSet.Unicode)]
internal static extern void Everything_GetResultFullPathNameW(int nIndex, StringBuilder lpString, int nMaxCount);
[DllImport(Main.DLL)]
internal static extern void Everything_Reset();
}
}

View File

@ -3,11 +3,12 @@ using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using Wox.Infrastructure; using Wox.Infrastructure;
using Wox.Infrastructure.Logger;
using Wox.Infrastructure.Storage; using Wox.Infrastructure.Storage;
using Wox.Plugin.Everything.Everything; using Wox.Plugin.Everything.Everything;
@ -15,14 +16,16 @@ namespace Wox.Plugin.Everything
{ {
public class Main : IPlugin, ISettingProvider, IPluginI18n, IContextMenu, ISavable public class Main : IPlugin, ISettingProvider, IPluginI18n, IContextMenu, ISavable
{ {
private readonly EverythingAPI _api = new EverythingAPI();
public const string DLL = "Everything.dll"; public const string DLL = "Everything.dll";
private readonly IEverythingApi _api = new EverythingApi();
private PluginInitContext _context; private PluginInitContext _context;
private Settings _settings; private Settings _settings;
private PluginJsonStorage<Settings> _storage; private PluginJsonStorage<Settings> _storage;
private CancellationTokenSource _cancellationTokenSource;
public void Save() public void Save()
{ {
@ -31,55 +34,24 @@ namespace Wox.Plugin.Everything
public List<Result> Query(Query query) public List<Result> Query(Query query)
{ {
_cancellationTokenSource?.Cancel(); // cancel if already exist
var cts = _cancellationTokenSource = new CancellationTokenSource();
var results = new List<Result>(); var results = new List<Result>();
if (!string.IsNullOrEmpty(query.Search)) if (!string.IsNullOrEmpty(query.Search))
{ {
var keyword = query.Search; var keyword = query.Search;
if (_settings.MaxSearchCount <= 0)
{
_settings.MaxSearchCount = 50;
}
try try
{ {
var searchList = _api.Search(keyword, maxCount: _settings.MaxSearchCount).ToList(); var searchList = _api.Search(keyword, cts.Token, maxCount: _settings.MaxSearchCount);
foreach (var s in searchList) if (searchList == null)
{ {
var path = s.FullPath; return results;
string workingDir = null;
if (_settings.UseLocationAsWorkingDir)
workingDir = Path.GetDirectoryName(path);
Result r = new Result();
r.Title = Path.GetFileName(path);
r.SubTitle = path;
r.IcoPath = path;
r.TitleHighlightData = StringMatcher.FuzzySearch(keyword, Path.GetFileName(path)).MatchData;
r.Action = c =>
{
bool hide;
try
{
Process.Start(new ProcessStartInfo
{
FileName = path,
UseShellExecute = true,
WorkingDirectory = workingDir
});
hide = true;
} }
catch (Win32Exception)
foreach (var searchResult in searchList)
{ {
var name = $"Plugin: {_context.CurrentPluginMetadata.Name}"; var r = CreateResult(keyword, searchResult);
var message = "Can't open this file";
_context.API.ShowMsg(name, message, string.Empty);
hide = false;
}
return hide;
};
r.ContextData = s;
r.SubTitleHighlightData = StringMatcher.FuzzySearch(keyword, path).MatchData;
results.Add(r); results.Add(r);
} }
} }
@ -93,6 +65,7 @@ namespace Wox.Plugin.Everything
} }
catch (Exception e) catch (Exception e)
{ {
Log.Exception("EverythingPlugin", "Query Error", e);
results.Add(new Result results.Add(new Result
{ {
Title = _context.API.GetTranslation("wox_plugin_everything_query_error"), Title = _context.API.GetTranslation("wox_plugin_everything_query_error"),
@ -108,13 +81,51 @@ namespace Wox.Plugin.Everything
} }
} }
_api.Reset();
return results; return results;
} }
[DllImport("kernel32.dll")] private Result CreateResult(string keyword, SearchResult searchResult)
private static extern int LoadLibrary(string name); {
var path = searchResult.FullPath;
string workingDir = null;
if (_settings.UseLocationAsWorkingDir)
workingDir = Path.GetDirectoryName(path);
var r = new Result
{
Title = Path.GetFileName(path),
SubTitle = path,
IcoPath = path,
TitleHighlightData = StringMatcher.FuzzySearch(keyword, Path.GetFileName(path)).MatchData,
Action = c =>
{
bool hide;
try
{
Process.Start(new ProcessStartInfo
{
FileName = path, UseShellExecute = true, WorkingDirectory = workingDir
});
hide = true;
}
catch (Win32Exception)
{
var name = $"Plugin: {_context.CurrentPluginMetadata.Name}";
var message = "Can't open this file";
_context.API.ShowMsg(name, message, string.Empty);
hide = false;
}
return hide;
},
ContextData = searchResult,
SubTitleHighlightData = StringMatcher.FuzzySearch(keyword, path).MatchData
};
return r;
}
private List<ContextMenu> GetDefaultContextMenu() private List<ContextMenu> GetDefaultContextMenu()
{ {
@ -149,6 +160,10 @@ namespace Wox.Plugin.Everything
_context = context; _context = context;
_storage = new PluginJsonStorage<Settings>(); _storage = new PluginJsonStorage<Settings>();
_settings = _storage.Load(); _settings = _storage.Load();
if (_settings.MaxSearchCount <= 0)
{
_settings.MaxSearchCount = Settings.DefaultMaxSearchCount;
}
var pluginDirectory = context.CurrentPluginMetadata.PluginDirectory; var pluginDirectory = context.CurrentPluginMetadata.PluginDirectory;
const string sdk = "EverythingSDK"; const string sdk = "EverythingSDK";
@ -158,7 +173,7 @@ namespace Wox.Plugin.Everything
var sdkPath = Path.Combine(sdkDirectory, DLL); var sdkPath = Path.Combine(sdkDirectory, DLL);
Constant.EverythingSDKPath = sdkPath; Constant.EverythingSDKPath = sdkPath;
LoadLibrary(sdkPath); _api.Load(sdkPath);
} }
private static string CpuType() private static string CpuType()

View File

@ -7,11 +7,13 @@ namespace Wox.Plugin.Everything
{ {
public class Settings public class Settings
{ {
public const int DefaultMaxSearchCount = 50;
public string EditorPath { get; set; } = ""; public string EditorPath { get; set; } = "";
public List<ContextMenu> ContextMenus = new List<ContextMenu>(); public List<ContextMenu> ContextMenus = new List<ContextMenu>();
public int MaxSearchCount { get; set; } = 100; public int MaxSearchCount { get; set; } = DefaultMaxSearchCount;
public bool UseLocationAsWorkingDir { get; set; } = false; public bool UseLocationAsWorkingDir { get; set; } = false;
} }

View File

@ -61,6 +61,7 @@
<Compile Include="EverythingSettings.xaml.cs"> <Compile Include="EverythingSettings.xaml.cs">
<DependentUpon>EverythingSettings.xaml</DependentUpon> <DependentUpon>EverythingSettings.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Everything\EverythingApiDllImport.cs" />
<Compile Include="Everything\Exceptions\CreateThreadException.cs" /> <Compile Include="Everything\Exceptions\CreateThreadException.cs" />
<Compile Include="Everything\Exceptions\CreateWindowException.cs" /> <Compile Include="Everything\Exceptions\CreateWindowException.cs" />
<Compile Include="Everything\EverythingAPI.cs" /> <Compile Include="Everything\EverythingAPI.cs" />

View File

@ -32,7 +32,6 @@ namespace Wox.Infrastructure
public static void ValidateDataDirectory(string bundledDataDirectory, string dataDirectory) public static void ValidateDataDirectory(string bundledDataDirectory, string dataDirectory)
{ {
if (!Directory.Exists(dataDirectory)) if (!Directory.Exists(dataDirectory))
{ {
Directory.CreateDirectory(dataDirectory); Directory.CreateDirectory(dataDirectory);

View File

@ -148,10 +148,6 @@ namespace Wox
private static void RegisterAppDomainExceptions() private static void RegisterAppDomainExceptions()
{ {
AppDomain.CurrentDomain.UnhandledException += ErrorReporting.UnhandledExceptionHandle; AppDomain.CurrentDomain.UnhandledException += ErrorReporting.UnhandledExceptionHandle;
AppDomain.CurrentDomain.FirstChanceException += (_, e) =>
{
Log.Exception("|App.RegisterAppDomainExceptions|First Chance Exception:", e.Exception);
};
} }
public void Dispose() public void Dispose()