using Flow.Launcher.Plugin.Everything.Everything; using Flow.Launcher.Plugin.Explorer.Search.Everything.Exceptions; using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Flow.Launcher.Plugin.Explorer.Search.Everything { public static class EverythingApi { private const int BufferSize = 4096; private static readonly object syncObject = new object(); // cached buffer to remove redundant allocations. private static readonly StringBuilder buffer = new StringBuilder(BufferSize); public enum StateCode { OK, MemoryError, IPCError, RegisterClassExError, CreateWindowError, CreateThreadError, InvalidIndexError, InvalidCallError } /// /// Gets or sets a value indicating whether [match path]. /// /// true if [match path]; otherwise, false. public static bool MatchPath { get => EverythingApiDllImport.Everything_GetMatchPath(); set => EverythingApiDllImport.Everything_SetMatchPath(value); } /// /// Gets or sets a value indicating whether [match case]. /// /// true if [match case]; otherwise, false. public static bool MatchCase { get => EverythingApiDllImport.Everything_GetMatchCase(); set => EverythingApiDllImport.Everything_SetMatchCase(value); } /// /// Gets or sets a value indicating whether [match whole word]. /// /// true if [match whole word]; otherwise, false. public static bool MatchWholeWord { get => EverythingApiDllImport.Everything_GetMatchWholeWord(); set => EverythingApiDllImport.Everything_SetMatchWholeWord(value); } /// /// Gets or sets a value indicating whether [enable regex]. /// /// true if [enable regex]; otherwise, false. public static bool EnableRegex { get => EverythingApiDllImport.Everything_GetRegex(); set => EverythingApiDllImport.Everything_SetRegex(value); } /// /// Resets this instance. /// private static void Reset() { lock (syncObject) { EverythingApiDllImport.Everything_Reset(); } } /// /// Checks whether the sort option is Fast Sort. /// public static bool IsFastSortOption(SortOption sortOption) { var fastSortOptionEnabled = EverythingApiDllImport.Everything_IsFastSort(sortOption); // If the Everything service is not running, then this call will incorrectly report // the state as false. This checks for errors thrown by the api and up to the caller to handle. CheckAndThrowExceptionOnError(); return fastSortOptionEnabled; } /// /// Searches the specified key word and reset the everything API afterwards /// /// The key word. /// when cancelled the current search will stop and exit (and would not reset) /// Search Within a parent folder /// Search Within sub folder of the parent folder /// Sort By /// The offset. /// The max count. /// public static IEnumerable SearchAsync(string keyword, CancellationToken token, SortOption sortOption = SortOption.NAME_ASCENDING, string parentPath = "", bool recursive = false, int offset = 0, int maxCount = 100) { if (offset < 0) throw new ArgumentOutOfRangeException(nameof(offset)); if (maxCount < 0) throw new ArgumentOutOfRangeException(nameof(maxCount)); lock (syncObject) { if (keyword.StartsWith("@")) { EverythingApiDllImport.Everything_SetRegex(true); keyword = keyword[1..]; } if (!string.IsNullOrEmpty(parentPath)) { keyword += $" {(recursive ? "" : "parent:")}\"{parentPath}\""; } EverythingApiDllImport.Everything_SetSearchW(keyword); EverythingApiDllImport.Everything_SetOffset(offset); EverythingApiDllImport.Everything_SetMax(maxCount); EverythingApiDllImport.Everything_SetSort(sortOption); if (token.IsCancellationRequested) { return null; } if (!EverythingApiDllImport.Everything_QueryW(true)) { CheckAndThrowExceptionOnError(); return null; } var results = new List(); for (var 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(), Type = EverythingApiDllImport.Everything_IsFolderResult(idx) ? ResultType.Folder : EverythingApiDllImport.Everything_IsFileResult(idx) ? ResultType.File : ResultType.Volume }; results.Add(result); } Reset(); return results; } } private static void CheckAndThrowExceptionOnError() { switch (EverythingApiDllImport.Everything_GetLastError()) { 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(); } } } }