From 27c43541db8cdb825627afe8b4f553a37bf9eb3f Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Wed, 2 Sep 2026 22:33:33 +0800 Subject: [PATCH 1/4] Improve Everything client validation and error handling --- .gitignore | 3 +- .../Everything/Everything3ApiDllImport.cs | 4 +- .../Search/Everything/EverythingApiV3.cs | 122 ++++++++++++------ .../Everything/EverythingSearchManager.cs | 39 ++++-- 4 files changed, 112 insertions(+), 56 deletions(-) diff --git a/.gitignore b/.gitignore index a293100e615..9a1728ebbd7 100644 --- a/.gitignore +++ b/.gitignore @@ -304,4 +304,5 @@ Output-Performance.txt # vscode .vscode -.history \ No newline at end of file +.history +/.copilot diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs index 5e24d7298a4..2ee669f40d7 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs @@ -34,6 +34,9 @@ public static void Load(string directory) [DllImport(Dll, CharSet = CharSet.Unicode)] internal static extern IntPtr Everything3_ConnectW(string instanceName); + [DllImport(Dll)] + internal static extern uint Everything3_GetMajorVersion(IntPtr client); + [DllImport(Dll)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool Everything3_DestroyClient(IntPtr client); @@ -129,7 +132,6 @@ public static void Load(string directory) [DllImport(Dll)] internal static extern uint Everything3_GetLastError(); - [DllImport(Dll)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool Everything3_IsPropertyFastSort(IntPtr client, uint propertyId); diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs index afdf5c9ad98..b2127bd8a7a 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs @@ -12,10 +12,11 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything public class EverythingApiV3 : IEverythingApi { private const int BufferSize = 4096; - private static readonly SemaphoreSlim _semaphore = new(1, 1); - private static readonly StringBuilder _buffer = new(BufferSize); + private readonly SemaphoreSlim _semaphore = new(1, 1); + private readonly StringBuilder _buffer = new(BufferSize); private readonly string _instanceName; + private IntPtr _client; public EverythingApiV3(string instanceName) { @@ -44,11 +45,13 @@ public EverythingApiV3(string instanceName) const uint EVERYTHING3_ERROR_PROPERTY_NOT_FOUND = 0xE0000007; const uint EVERYTHING3_OK = 0; - private static void LogIfEverything3CallFailed(string callName, bool succeeded) + private void CheckEverything3Call(string callName, bool succeeded) { if (!succeeded) { Main.Context?.API?.LogDebug(nameof(EverythingApiV3), $"{callName} failed"); + CheckAndThrowExceptionOnErrorFromEverything3(); + throw new InvalidCallException(); } } @@ -71,9 +74,13 @@ public async Task CheckAvailableAsync(CancellationToken token = default) try { - if (!TryConnectEverything3(out var client)) + token.ThrowIfCancellationRequested(); + + if (!EverythingClientConnected()) + { + _client = IntPtr.Zero; throw new IPCErrorException(); - _ = Everything3ApiDllImport.Everything3_DestroyClient(client); + } } finally { @@ -100,10 +107,10 @@ private async IAsyncEnumerable SearchCoreAsync(EverythingSearchOpt if (token.IsCancellationRequested) yield break; - if (!TryConnectEverything3(out var client)) + if (!EverythingClientConnected()) throw new IPCErrorException(); - await foreach (var result in SearchWithEverything3Async(client, preparedOption, query, token)) + await foreach (var result in SearchWithEverything3Async(preparedOption, query, token)) yield return result; } finally @@ -122,15 +129,16 @@ public async Task IncrementRunCounterAsync(string fileOrFolder) } try { - if (TryConnectEverything3(out var client)) + if (EverythingClientConnected()) { try { - Everything3ApiDllImport.Everything3_IncRunCountFromFilenameW(client, fileOrFolder); + Everything3ApiDllImport.Everything3_IncRunCountFromFilenameW(_client, fileOrFolder); } - finally + catch (IPCErrorException) { - _ = Everything3ApiDllImport.Everything3_DestroyClient(client); + DestroyEverythingClient(_client); + throw; } } } @@ -146,37 +154,47 @@ public async Task IncrementRunCounterAsync(string fileOrFolder) public bool IsFastSortOption(EverythingSortOption sortOption) { - if (!TryConnectEverything3(out var client)) - throw new IPCErrorException(); + _semaphore.Wait(); try { + if (!EverythingClientConnected()) + throw new IPCErrorException(); + if (TryConvertSortOption(sortOption, out var propertyId, out _)) { - var isFastSort = Everything3ApiDllImport.Everything3_IsPropertyFastSort(client, propertyId); + var isFastSort = Everything3ApiDllImport.Everything3_IsPropertyFastSort(_client, propertyId); CheckAndThrowExceptionOnErrorFromEverything3(); return isFastSort; } } + catch (IPCErrorException) + { + DestroyEverythingClient(_client); + throw; + } finally { - _ = Everything3ApiDllImport.Everything3_DestroyClient(client); + _semaphore.Release(); } return false; } - private static async IAsyncEnumerable SearchWithEverything3Async(IntPtr client, + private async IAsyncEnumerable SearchWithEverything3Async( EverythingSearchOption option, EverythingHelper.PreparedQuery query, [EnumeratorCancellation] CancellationToken token) { IntPtr searchState = IntPtr.Zero; IntPtr resultList = IntPtr.Zero; + var completed = false; var includeRunCount = option.IsRunCounterEnabled || option.SortOption == EverythingSortOption.RUN_COUNT_DESCENDING || option.SortOption == EverythingSortOption.RUN_COUNT_ASCENDING; try { + if (token.IsCancellationRequested) + yield break; searchState = Everything3ApiDllImport.Everything3_CreateSearchState(); if (searchState == IntPtr.Zero) { @@ -184,37 +202,41 @@ private static async IAsyncEnumerable SearchWithEverything3Async(I yield break; } - LogIfEverything3CallFailed(nameof(Everything3ApiDllImport.Everything3_SetSearchRegex), + CheckEverything3Call(nameof(Everything3ApiDllImport.Everything3_SetSearchRegex), Everything3ApiDllImport.Everything3_SetSearchRegex(searchState, option.UseRegex)); - LogIfEverything3CallFailed(nameof(Everything3ApiDllImport.Everything3_SetSearchMatchPath), + CheckEverything3Call(nameof(Everything3ApiDllImport.Everything3_SetSearchMatchPath), Everything3ApiDllImport.Everything3_SetSearchMatchPath(searchState, option.IsFullPathSearch)); - LogIfEverything3CallFailed(nameof(Everything3ApiDllImport.Everything3_SetSearchTextW), + CheckEverything3Call(nameof(Everything3ApiDllImport.Everything3_SetSearchTextW), Everything3ApiDllImport.Everything3_SetSearchTextW(searchState, query.SearchText)); - LogIfEverything3CallFailed(nameof(Everything3ApiDllImport.Everything3_SetSearchHideResultOmissions), + CheckEverything3Call(nameof(Everything3ApiDllImport.Everything3_SetSearchHideResultOmissions), Everything3ApiDllImport.Everything3_SetSearchHideResultOmissions(searchState, true)); - LogIfEverything3CallFailed(nameof(Everything3ApiDllImport.Everything3_SetSearchViewportOffset), + CheckEverything3Call(nameof(Everything3ApiDllImport.Everything3_SetSearchViewportOffset), Everything3ApiDllImport.Everything3_SetSearchViewportOffset(searchState, (nuint)option.Offset)); - LogIfEverything3CallFailed(nameof(Everything3ApiDllImport.Everything3_SetSearchViewportCount), + CheckEverything3Call(nameof(Everything3ApiDllImport.Everything3_SetSearchViewportCount), Everything3ApiDllImport.Everything3_SetSearchViewportCount(searchState, (nuint)option.MaxCount)); if (TryConvertSortOption(option.SortOption, out var sortPropertyId, out var ascending)) { if (!Everything3ApiDllImport.Everything3_AddSearchSort(searchState, sortPropertyId, ascending)) { - CheckAndThrowExceptionOnErrorFromEverything3(); - yield break; + CheckEverything3Call(nameof(Everything3ApiDllImport.Everything3_AddSearchSort), false); } } - _ = Everything3ApiDllImport.Everything3_ClearSearchPropertyRequests(searchState); - _ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequestHighlighted(searchState, EVERYTHING3_PROPERTY_ID_NAME); - _ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequest(searchState, EVERYTHING3_PROPERTY_ID_PATH_AND_NAME); + CheckEverything3Call(nameof(Everything3ApiDllImport.Everything3_ClearSearchPropertyRequests), + Everything3ApiDllImport.Everything3_ClearSearchPropertyRequests(searchState)); + CheckEverything3Call(nameof(Everything3ApiDllImport.Everything3_AddSearchPropertyRequestHighlighted), + Everything3ApiDllImport.Everything3_AddSearchPropertyRequestHighlighted(searchState, EVERYTHING3_PROPERTY_ID_NAME)); + CheckEverything3Call(nameof(Everything3ApiDllImport.Everything3_AddSearchPropertyRequest), + Everything3ApiDllImport.Everything3_AddSearchPropertyRequest(searchState, EVERYTHING3_PROPERTY_ID_PATH_AND_NAME)); if (includeRunCount) - _ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequest(searchState, EVERYTHING3_PROPERTY_ID_RUN_COUNT); + { + CheckEverything3Call(nameof(Everything3ApiDllImport.Everything3_AddSearchPropertyRequest), + Everything3ApiDllImport.Everything3_AddSearchPropertyRequest(searchState, EVERYTHING3_PROPERTY_ID_RUN_COUNT)); + } if (token.IsCancellationRequested) yield break; - - resultList = Everything3ApiDllImport.Everything3_Search(client, searchState); + resultList = Everything3ApiDllImport.Everything3_Search(_client, searchState); if (resultList == IntPtr.Zero) { CheckAndThrowExceptionOnErrorFromEverything3(); @@ -234,6 +256,8 @@ private static async IAsyncEnumerable SearchWithEverything3Async(I yield return result; } + + completed = true; } finally { @@ -243,13 +267,14 @@ private static async IAsyncEnumerable SearchWithEverything3Async(I if (searchState != IntPtr.Zero) _ = Everything3ApiDllImport.Everything3_DestroySearchState(searchState); - _ = Everything3ApiDllImport.Everything3_DestroyClient(client); + if (!completed) + DestroyEverythingClient(_client); } await Task.CompletedTask; } - private static bool TryCreateSearchResult(IntPtr resultList, nuint resultIndex, bool includeRunCount, out SearchResult result) + private bool TryCreateSearchResult(IntPtr resultList, nuint resultIndex, bool includeRunCount, out SearchResult result) { result = default; @@ -267,7 +292,7 @@ private static bool TryCreateSearchResult(IntPtr resultList, nuint resultIndex, return true; } - private static int GetResultScore(IntPtr resultList, nuint resultIndex) + private int GetResultScore(IntPtr resultList, nuint resultIndex) { var runCount = Everything3ApiDllImport.Everything3_GetResultRunCount(resultList, resultIndex); var lastError = Everything3ApiDllImport.Everything3_GetLastError(); @@ -288,7 +313,7 @@ private static int GetResultScore(IntPtr resultList, nuint resultIndex) return (int)runCount; } - private static bool TryGetResultFullPath(IntPtr resultList, nuint resultIndex, out string fullPath) + private bool TryGetResultFullPath(IntPtr resultList, nuint resultIndex, out string fullPath) { _buffer.Clear(); var fullPathLength = Everything3ApiDllImport.Everything3_GetResultFullPathNameW(resultList, resultIndex, _buffer, BufferSize); @@ -303,7 +328,7 @@ private static bool TryGetResultFullPath(IntPtr resultList, nuint resultIndex, o return !string.IsNullOrEmpty(fullPath); } - private static ResultType GetResultType(IntPtr resultList, nuint resultIndex) + private ResultType GetResultType(IntPtr resultList, nuint resultIndex) { return Everything3ApiDllImport.Everything3_IsFolderResult(resultList, resultIndex) ? ResultType.Folder @@ -312,7 +337,7 @@ private static ResultType GetResultType(IntPtr resultList, nuint resultIndex) : ResultType.File; } - private static List GetHighlightData(IntPtr resultList, nuint resultIndex) + private List GetHighlightData(IntPtr resultList, nuint resultIndex) { _buffer.Clear(); var highlightedFileNameLength = Everything3ApiDllImport.Everything3_GetResultPropertyTextHighlightedW( @@ -327,10 +352,27 @@ private static List GetHighlightData(IntPtr resultList, nuint resultIndex) : []; } - private bool TryConnectEverything3(out IntPtr client) + private bool EverythingClientConnected() + { + if (_client == IntPtr.Zero) + _client = Everything3ApiDllImport.Everything3_ConnectW(_instanceName); + + if (_client == IntPtr.Zero || Everything3ApiDllImport.Everything3_GetMajorVersion(_client) == 0) + { + DestroyEverythingClient(_client); + _client = Everything3ApiDllImport.Everything3_ConnectW(_instanceName); + } + + return _client != IntPtr.Zero && Everything3ApiDllImport.Everything3_GetMajorVersion(_client) != 0; + } + + private void DestroyEverythingClient(IntPtr client) { - client = Everything3ApiDllImport.Everything3_ConnectW(_instanceName); - return client != IntPtr.Zero; + if (client == IntPtr.Zero || client != _client) + return; + + _ = Everything3ApiDllImport.Everything3_DestroyClient(_client); + _client = IntPtr.Zero; } /// @@ -451,7 +493,7 @@ private static bool TryConvertSortOption(EverythingSortOption sortOption, out ui } } - private static void CheckAndThrowExceptionOnErrorFromEverything3() + private void CheckAndThrowExceptionOnErrorFromEverything3() { switch (Everything3ApiDllImport.Everything3_GetLastError()) { diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs index 98fbe240067..cbf39ab36ae 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs @@ -68,9 +68,7 @@ public async IAsyncEnumerable ContentSearchAsync(string plainSearc IsRunCounterEnabled: Settings.EverythingEnableRunCount); await foreach (var result in api.SearchAsync(option, token)) - { yield return result; - } } public async IAsyncEnumerable EnumerateAsync(string path, string search, bool recursive, [EnumeratorCancellation] CancellationToken token) @@ -119,7 +117,6 @@ public void InitializeApi(string sdkDirectory) private async Task EnsureAvailableAsync(CancellationToken token) { - var engineName = Enum.GetName(Settings.IndexSearchEngineOption.Everything)!; try { await api.CheckAvailableAsync(token); @@ -128,28 +125,42 @@ private async Task EnsureAvailableAsync(CancellationToken token) { // ignore, the search was cancelled } - catch (Exceptions.IPCErrorException) when (api is LegacyEverythingApi) + catch (Exception ex) when (IsAvailabilityException(ex)) { - throw new EngineNotAvailableException(engineName, + throw WrapEngineNotAvailableException(ex); + } + } + + internal static bool IsAvailabilityException(Exception exception) => + exception is Exceptions.IPCErrorException || + exception is DllNotFoundException || + exception is EntryPointNotFoundException; + + internal EngineNotAvailableException WrapEngineNotAvailableException(Exception exception) + { + var engineName = Enum.GetName(Settings.IndexSearchEngineOption.Everything)!; + + if (exception is Exceptions.IPCErrorException && api is LegacyEverythingApi) + { + return new EngineNotAvailableException(engineName, Localize.flowlauncher_plugin_everything_click_to_launch_or_install(), Localize.flowlauncher_plugin_everything_is_not_running(), Constants.EverythingErrorImagePath, ClickToInstallEverythingAsync); } - catch (Exceptions.IPCErrorException) + + if (exception is Exceptions.IPCErrorException) { - throw new EngineNotAvailableException(engineName, + return new EngineNotAvailableException(engineName, Localize.flowlauncher_plugin_everything_15_resolution(), Localize.flowlauncher_plugin_everything_15_unavailable(), Constants.EverythingErrorImagePath); } - catch (Exception ex) when (ex is DllNotFoundException || ex is EntryPointNotFoundException) - { - throw new EngineNotAvailableException(engineName, - Localize.flowlauncher_plugin_everything_architecture_check(), - Constants.GeneralSearchErrorImagePath, - Localize.flowlauncher_plugin_everything_sdk_issue()); - } + + return new EngineNotAvailableException(engineName, + Localize.flowlauncher_plugin_everything_architecture_check(), + Constants.GeneralSearchErrorImagePath, + Localize.flowlauncher_plugin_everything_sdk_issue()); } private async ValueTask ClickToInstallEverythingAsync(ActionContext _) From 43fda2f28b96ee038fb634e4725f6efa32fbcadb Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Wed, 2 Sep 2026 23:09:26 +0800 Subject: [PATCH 2/4] Fix runcount increment fail check and UI blocking --- .../Search/Everything/EverythingApiV3.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs index b2127bd8a7a..a3ea2d1f8cf 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs @@ -133,7 +133,8 @@ public async Task IncrementRunCounterAsync(string fileOrFolder) { try { - Everything3ApiDllImport.Everything3_IncRunCountFromFilenameW(_client, fileOrFolder); + var incremented = Everything3ApiDllImport.Everything3_IncRunCountFromFilenameW(_client, fileOrFolder) != 0; + CheckEverything3Call(nameof(Everything3ApiDllImport.Everything3_IncRunCountFromFilenameW), incremented); } catch (IPCErrorException) { @@ -154,7 +155,8 @@ public async Task IncrementRunCounterAsync(string fileOrFolder) public bool IsFastSortOption(EverythingSortOption sortOption) { - _semaphore.Wait(); + if (!_semaphore.Wait(TimeSpan.FromSeconds(1))) + return false; try { @@ -363,7 +365,7 @@ private bool EverythingClientConnected() _client = Everything3ApiDllImport.Everything3_ConnectW(_instanceName); } - return _client != IntPtr.Zero && Everything3ApiDllImport.Everything3_GetMajorVersion(_client) != 0; + return _client != IntPtr.Zero; } private void DestroyEverythingClient(IntPtr client) From bfbd82ea1154ce7b68cbbe487340a2d2ae3c4fe4 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Wed, 2 Sep 2026 23:33:12 +0800 Subject: [PATCH 3/4] minor fix --- .../Search/Everything/EverythingApiV3.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs index a3ea2d1f8cf..e9b78eec3ae 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs @@ -51,7 +51,6 @@ private void CheckEverything3Call(string callName, bool succeeded) { Main.Context?.API?.LogDebug(nameof(EverythingApiV3), $"{callName} failed"); CheckAndThrowExceptionOnErrorFromEverything3(); - throw new InvalidCallException(); } } @@ -508,6 +507,8 @@ private void CheckAndThrowExceptionOnErrorFromEverything3() throw new InvalidCallException(); case EVERYTHING3_ERROR_PROPERTY_NOT_FOUND: throw new ArgumentException("EVERYTHING3_ERROR_PROPERTY_NOT_FOUND"); + default: + throw new InvalidCallException(); } } } From dbf072089041a9e66c973564f7e8466c0d16bde4 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Wed, 2 Sep 2026 23:44:01 +0800 Subject: [PATCH 4/4] Do not throw when OK Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> --- .../Search/Everything/EverythingApiV3.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs index e9b78eec3ae..c2d2c54afbf 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs @@ -507,6 +507,8 @@ private void CheckAndThrowExceptionOnErrorFromEverything3() throw new InvalidCallException(); case EVERYTHING3_ERROR_PROPERTY_NOT_FOUND: throw new ArgumentException("EVERYTHING3_ERROR_PROPERTY_NOT_FOUND"); + case EVERYTHING3_OK: + return; default: throw new InvalidCallException(); }