├── .gitattributes ├── .github ├── dependabot.yml └── workflows │ └── dotnet-desktop.yml ├── .gitignore ├── EverythingSearchClient.sln ├── EverythingSearchClient ├── EverythingBusyException.cs ├── EverythingIPC.cs ├── EverythingSearchClient.csproj ├── IpcWindow.cs ├── MessageReceiverWindow.cs ├── Result.cs ├── ResultsNotReceivedException.cs ├── SearchClient.cs └── ServiceControl.cs ├── ExampleApp ├── ExampleApp.csproj └── Program.cs ├── Images ├── MagnifyingGlass.afdesign ├── MagnifyingGlass.ico └── MagnifyingGlass_x128.png ├── LICENSE ├── README.md ├── README_nuget.md ├── Reference ├── Everything-SDK-ipc │ └── everything_ipc.h └── EverythingDemo │ ├── EverythingDemo.cpp │ ├── EverythingDemo.sln │ ├── EverythingDemo.vcxproj │ └── EverythingDemo.vcxproj.filters ├── TestNugetConsoleApp ├── Program.cs ├── README.md ├── TestNugetConsoleApp.csproj ├── TestNugetConsoleApp.sln └── nuget.config └── TestProject ├── DataGenerator.cs ├── README.md ├── TestBusyBehavior.cs ├── TestProject.csproj ├── TestQuery2Results.cs ├── TestResultLimit.cs ├── TestSearchFlags.cs ├── TestServiceInfo.cs ├── TestSortedResults.cs └── Usings.cs /.gitattributes: -------------------------------------------------------------------------------- 1 | Reference/** linguist-vendored 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Dependabot with version updates 2 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file 3 | 4 | version: 2 5 | updates: 6 | # Github Actions 7 | - package-ecosystem: "github-actions" 8 | directory: "/" 9 | schedule: 10 | interval: "weekly" 11 | open-pull-requests-limit: 10 12 | 13 | # projects nugets 14 | - package-ecosystem: "nuget" 15 | directory: "/" 16 | schedule: 17 | interval: "weekly" 18 | open-pull-requests-limit: 10 19 | -------------------------------------------------------------------------------- /.github/workflows/dotnet-desktop.yml: -------------------------------------------------------------------------------- 1 | name: Build & Test 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | workflow_dispatch: 9 | 10 | env: 11 | VSTEST_CONNECTION_TIMEOUT: 120 12 | 13 | jobs: 14 | build: 15 | strategy: 16 | matrix: 17 | configuration: [Debug, Release] 18 | runs-on: windows-latest 19 | 20 | steps: 21 | - name: Checkout 22 | uses: actions/checkout@v4 23 | with: 24 | fetch-depth: 0 25 | 26 | - name: Install .NET 27 | uses: actions/setup-dotnet@v4 28 | with: 29 | dotnet-version: 6.0.x 30 | 31 | # - name: Download & run Everything 32 | # shell: pwsh 33 | # run: | 34 | # $html = Invoke-WebRequest -Uri https://www.voidtools.com 35 | # $dl = $html.links | where href -match "^.+\.x86\.zip$" | select -expandproperty href 36 | # $dl = (New-Object System.Uri ([Uri]"https://www.voidtools.com", $dl)).AbsoluteUri 37 | # $zipPath = [IO.Path]::Join((pwd), "Everything.x86.zip") 38 | # Invoke-WebRequest -Uri $dl -OutFile $zipPath 39 | # 7z x $zipPath 40 | # Start-Process (Resolve-Path "Everything.exe") -WindowStyle Hidden 41 | # Start-Sleep -Seconds 4 42 | 43 | - name: Install dependencies 44 | run: dotnet restore 45 | 46 | - name: Inject build number 47 | shell: pwsh 48 | run: | 49 | $csproj = New-Object System.XML.XMLDocument 50 | $csprojPath = Resolve-Path "EverythingSearchClient\EverythingSearchClient.csproj" 51 | $csproj.Load($csprojPath) 52 | $version = New-Object System.Version $csproj.Project.PropertyGroup.Version 53 | $version = New-Object System.Version @( $version.Major, $version.Minor, ([System.Math]::Max(0, $version.Build)), $env:GITHUB_RUN_NUMBER ) 54 | Write-Host "Version number: $version" 55 | $csproj.Project.PropertyGroup.Version = $version.ToString() 56 | $csproj.Save($csprojPath) 57 | Write-Output "FULL_VERSION_NUMBER=$version" >> $env:GITHUB_ENV 58 | 59 | - name: Build application 60 | run: dotnet build --configuration ${{ matrix.configuration }} --no-restore 61 | 62 | # - name: Run unit tests 63 | # run: dotnet test --configuration ${{ matrix.configuration }} --no-restore --verbosity normal --logger "console;verbosity=detailed" 64 | 65 | # - name: Inject nuget dependency 66 | # shell: pwsh 67 | # run: | 68 | # $xml = New-Object System.XML.XMLDocument 69 | # $xmlPath = Resolve-Path "TestNugetConsoleApp\nuget.config" 70 | # $xml.Load($xmlPath) 71 | # $xml.SelectSingleNode("configuration/packageSources/add[@key='local project']").value = ("..\EverythingSearchClient\bin\${{ matrix.configuration }}") 72 | # $xml.Save($xmlPath) 73 | 74 | # $xmlPath = Resolve-Path "TestNugetConsoleApp\TestNugetConsoleApp.csproj" 75 | # $xml.Load($xmlPath) 76 | # $xml.SelectSingleNode("Project/ItemGroup/PackageReference[@Include='EverythingSearchClient']").Version = "${{ env.FULL_VERSION_NUMBER }}" 77 | # $xml.Save($xmlPath) 78 | 79 | # - name: Build nuget test app 80 | # shell: pwsh 81 | # run: | 82 | # cd TestNugetConsoleApp 83 | # dotnet build --configuration ${{ matrix.configuration }} 84 | 85 | # - name: Run nuget test app 86 | # shell: pwsh 87 | # run: | 88 | # cd TestNugetConsoleApp 89 | # $exe = gci TestNugetConsoleApp.exe -recurse 90 | # & $exe 91 | 92 | - name: Upload artifact 93 | if: ${{ matrix.configuration == 'Release' }} 94 | uses: actions/upload-artifact@v4 95 | with: 96 | name: EverythingSearchClient-Nuget-${{ env.FULL_VERSION_NUMBER }} 97 | path: EverythingSearchClient\bin\Release\*.nupkg 98 | if-no-files-found: error 99 | retention-days: 7 100 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vs 2 | **/bin/ 3 | **/obj/ 4 | Reference/EverythingDemo/Debug 5 | Reference/EverythingDemo/Release 6 | Reference/EverythingDemo/x64 7 | Reference/EverythingDemo/EverythingDemo.vcxproj.user 8 | desktop.ini 9 | ExampleApp/Properties/launchSettings.json 10 | -------------------------------------------------------------------------------- /EverythingSearchClient.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.33103.201 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EverythingSearchClient", "EverythingSearchClient\EverythingSearchClient.csproj", "{818182F7-44E1-4D72-9EC5-50DEB3244446}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExampleApp", "ExampleApp\ExampleApp.csproj", "{7603333C-5B53-47D1-BD11-C919597ADB2F}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestProject", "TestProject\TestProject.csproj", "{AD72A1BE-1427-4726-BE30-A2FE86C30ADE}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {818182F7-44E1-4D72-9EC5-50DEB3244446}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {818182F7-44E1-4D72-9EC5-50DEB3244446}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {818182F7-44E1-4D72-9EC5-50DEB3244446}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {818182F7-44E1-4D72-9EC5-50DEB3244446}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {7603333C-5B53-47D1-BD11-C919597ADB2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {7603333C-5B53-47D1-BD11-C919597ADB2F}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {7603333C-5B53-47D1-BD11-C919597ADB2F}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {7603333C-5B53-47D1-BD11-C919597ADB2F}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {AD72A1BE-1427-4726-BE30-A2FE86C30ADE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {AD72A1BE-1427-4726-BE30-A2FE86C30ADE}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {AD72A1BE-1427-4726-BE30-A2FE86C30ADE}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {AD72A1BE-1427-4726-BE30-A2FE86C30ADE}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {0707502C-B3CE-426A-B70C-9B3D87A7EED6} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /EverythingSearchClient/EverythingBusyException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace EverythingSearchClient 8 | { 9 | public class EverythingBusyException: Exception 10 | { 11 | public EverythingBusyException() : base("Everything service is busy") { } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /EverythingSearchClient/EverythingIPC.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Runtime.InteropServices; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace EverythingSearchClient 9 | { 10 | 11 | /// 12 | /// This class is based on `everything_ipc.h` from the Everything SDK 13 | /// 14 | internal class EverythingIPC 15 | { 16 | 17 | /// 18 | /// find the everything IPC window 19 | /// 20 | internal const string EVERYTHING_IPC_WNDCLASS = "EVERYTHING_TASKBAR_NOTIFICATION"; 21 | 22 | /// 23 | /// Main message to contact Everything IPC 24 | /// 25 | internal const uint EVERYTHING_WM_IPC = 0x0400; // (WM_USER) 26 | 27 | /// 28 | /// int major_version = (int)SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_GET_MAJOR_VERSION,0); 29 | /// 30 | internal const uint EVERYTHING_IPC_GET_MAJOR_VERSION = 0; 31 | 32 | /// 33 | /// int minor_version = (int)SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_GET_MINOR_VERSION,0); 34 | /// 35 | internal const uint EVERYTHING_IPC_GET_MINOR_VERSION = 1; 36 | 37 | /// 38 | /// int revision = (int)SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_GET_REVISION,0); 39 | /// 40 | internal const uint EVERYTHING_IPC_GET_REVISION = 2; 41 | 42 | /// 43 | /// int build = (int)SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_GET_BUILD,0); 44 | /// 45 | internal const uint EVERYTHING_IPC_GET_BUILD_NUMBER = 3; 46 | 47 | /// 48 | /// int is_db_busy = (int)SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_DB_BUSY,0); 49 | /// db is busy, issueing another action will cancel the current one (if possible). 50 | /// 51 | internal const uint EVERYTHING_IPC_IS_DB_BUSY = 402; 52 | 53 | [StructLayout(LayoutKind.Sequential)] 54 | internal struct EVERYTHING_IPC_QUERY 55 | { 56 | // the window that will receive the new results. 57 | // only 32bits are required to store a window handle. (even on x64) 58 | public UInt32 reply_hwnd; 59 | 60 | // the value to set the dwData member in the COPYDATASTRUCT struct 61 | // sent by Everything when the query is complete. 62 | public UInt32 reply_copydata_message; 63 | 64 | // search flags (see EVERYTHING_IPC_MATCHCASE | EVERYTHING_IPC_MATCHWHOLEWORD | EVERYTHING_IPC_MATCHPATH) 65 | public UInt32 search_flags; 66 | 67 | // only return results after 'offset' results (0 to return from the first result) 68 | // useful for scrollable lists 69 | public UInt32 offset; 70 | 71 | // the number of results to return 72 | // zero to return no results 73 | // EVERYTHING_IPC_ALLRESULTS to return ALL results 74 | public UInt32 max_results; 75 | 76 | // followed by null terminated wide string. variable lengthed search string buffer. 77 | } 78 | 79 | /// 80 | /// match case 81 | /// 82 | internal const uint EVERYTHING_IPC_MATCHCASE = 0x00000001; 83 | 84 | /// 85 | /// match whole word 86 | /// 87 | internal const uint EVERYTHING_IPC_MATCHWHOLEWORD = 0x00000002; 88 | 89 | /// 90 | /// include paths in search 91 | /// 92 | internal const uint EVERYTHING_IPC_MATCHPATH = 0x00000004; 93 | 94 | /// 95 | /// enable regex 96 | /// 97 | internal const uint EVERYTHING_IPC_REGEX = 0x00000008; 98 | 99 | /// 100 | /// the WM_COPYDATA message for a query. 101 | /// Use the unicode UTF16 variant 102 | /// 103 | internal const uint EVERYTHING_IPC_COPYDATAQUERYW = 2; 104 | 105 | /// 106 | /// the WM_COPYDATA message for a query 2. 107 | /// Use the unicode UTF16 variant 108 | /// 109 | internal const uint EVERYTHING_IPC_COPYDATA_QUERY2W = 18; 110 | 111 | /// 112 | /// The item is a folder. (it's a file if not set) 113 | /// 114 | internal const uint EVERYTHING_IPC_FOLDER = 0x00000001; 115 | 116 | /// 117 | /// the file or folder is a drive/root. 118 | /// 119 | internal const uint EVERYTHING_IPC_DRIVE = 0x00000002; 120 | 121 | [StructLayout(LayoutKind.Sequential)] 122 | internal struct EVERYTHING_IPC_QUERY2 123 | { 124 | // the window that will receive the new results. 125 | // only 32bits are required to store a window handle. (even on x64) 126 | public UInt32 reply_hwnd; 127 | 128 | // the value to set the dwData member in the COPYDATASTRUCT struct 129 | // sent by Everything when the query is complete. 130 | public UInt32 reply_copydata_message; 131 | 132 | // search flags (see EVERYTHING_IPC_MATCHCASE | EVERYTHING_IPC_MATCHWHOLEWORD | EVERYTHING_IPC_MATCHPATH) 133 | public UInt32 search_flags; 134 | 135 | // only return results after 'offset' results (0 to return from the first result) 136 | // useful for scrollable lists 137 | public UInt32 offset; 138 | 139 | // the number of results to return 140 | // zero to return no results 141 | // EVERYTHING_IPC_ALLRESULTS to return ALL results 142 | public UInt32 max_results; 143 | 144 | // request types. 145 | // one or more of EVERYTHING_IPC_QUERY2_REQUEST_* types. 146 | public UInt32 request_flags; 147 | 148 | // sort type, set to one of EVERYTHING_IPC_SORT_* types. 149 | // set to EVERYTHING_IPC_SORT_NAME_ASCENDING for the best performance (there will never be a performance hit when sorting by name ascending). 150 | // Other sorts will also be instant if the corresponding fast sort is enabled from Tools -> Options -> Indexes. 151 | public UInt32 sort_type; 152 | 153 | // followed by null terminated search. 154 | } 155 | 156 | /// 157 | /// Request name string 158 | /// 159 | internal const uint EVERYTHING_IPC_QUERY2_REQUEST_NAME = 0x00000001; 160 | 161 | /// 162 | /// Request path string 163 | /// 164 | internal const uint EVERYTHING_IPC_QUERY2_REQUEST_PATH = 0x00000002; 165 | 166 | /// 167 | /// Request path-and-name string 168 | /// 169 | internal const uint EVERYTHING_IPC_QUERY2_REQUEST_FULL_PATH_AND_NAME = 0x00000004; 170 | 171 | /// 172 | /// Request file name extension string 173 | /// 174 | internal const uint EVERYTHING_IPC_QUERY2_REQUEST_EXTENSION = 0x00000008; 175 | 176 | /// 177 | /// Request file size 178 | /// 179 | internal const uint EVERYTHING_IPC_QUERY2_REQUEST_SIZE = 0x00000010; 180 | 181 | /// 182 | /// Request file creation date 183 | /// 184 | internal const uint EVERYTHING_IPC_QUERY2_REQUEST_DATE_CREATED = 0x00000020; 185 | 186 | /// 187 | /// Request file modified date 188 | /// 189 | internal const uint EVERYTHING_IPC_QUERY2_REQUEST_DATE_MODIFIED = 0x00000040; 190 | 191 | /// 192 | /// Request file attributes 193 | /// 194 | internal const uint EVERYTHING_IPC_QUERY2_REQUEST_DATE_ACCESSED = 0x00000080; 195 | 196 | /// 197 | /// Request file attributes 198 | /// 199 | internal const uint EVERYTHING_IPC_QUERY2_REQUEST_ATTRIBUTES = 0x00000100; 200 | 201 | /// 202 | /// Sort results by file name ascending 203 | /// 204 | internal const uint EVERYTHING_IPC_SORT_NAME_ASCENDING = 1; 205 | 206 | /// 207 | /// Sort results by file name name decending 208 | /// 209 | internal const uint EVERYTHING_IPC_SORT_NAME_DESCENDING = 2; 210 | 211 | /// 212 | /// Sort results by full path ascending 213 | /// 214 | internal const uint EVERYTHING_IPC_SORT_PATH_ASCENDING = 3; 215 | 216 | /// 217 | /// Sort results by full path decending 218 | /// 219 | internal const uint EVERYTHING_IPC_SORT_PATH_DESCENDING = 4; 220 | 221 | /// 222 | /// Sort results by file size ascending 223 | /// 224 | internal const uint EVERYTHING_IPC_SORT_SIZE_ASCENDING = 5; 225 | 226 | /// 227 | /// Sort results by file size decending 228 | /// 229 | internal const uint EVERYTHING_IPC_SORT_SIZE_DESCENDING = 6; 230 | 231 | /// 232 | /// Sort results by extension ascending 233 | /// 234 | internal const uint EVERYTHING_IPC_SORT_EXTENSION_ASCENDING = 7; 235 | 236 | /// 237 | /// Sort results by extension decending 238 | /// 239 | internal const uint EVERYTHING_IPC_SORT_EXTENSION_DESCENDING = 8; 240 | 241 | /// 242 | /// Sort results by creation date ascending 243 | /// 244 | internal const uint EVERYTHING_IPC_SORT_DATE_CREATED_ASCENDING = 11; 245 | 246 | /// 247 | /// Sort results by creation date decending 248 | /// 249 | internal const uint EVERYTHING_IPC_SORT_DATE_CREATED_DESCENDING = 12; 250 | 251 | /// 252 | /// Sort results by date of last modification ascending 253 | /// 254 | internal const uint EVERYTHING_IPC_SORT_DATE_MODIFIED_ASCENDING = 13; 255 | 256 | /// 257 | /// Sort results by date of last modification decending 258 | /// 259 | internal const uint EVERYTHING_IPC_SORT_DATE_MODIFIED_DESCENDING = 14; 260 | 261 | } 262 | 263 | } 264 | -------------------------------------------------------------------------------- /EverythingSearchClient/EverythingSearchClient.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0 5 | 6 | enable 7 | enable 8 | True 9 | Everything Search Client 10 | 0.8.0 11 | SGrottel 12 | A .NET client library for Voidtools' Everything search engine, without the native Everything SDK dll. 13 | Copyright 2022-2024, by SGrottel 14 | https://go.grottel.net/EverythingSearchClient 15 | https://github.com/sgrottel/EverythingSearchClient.git 16 | git 17 | Apache-2.0 18 | README_nuget.md 19 | MagnifyingGlass_x128.png 20 | Voidtools;Everything;Search 21 | 22 | 23 | 24 | 25 | True 26 | \ 27 | 28 | 29 | True 30 | \ 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /EverythingSearchClient/IpcWindow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Runtime.InteropServices; 5 | using System.Runtime.Versioning; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace EverythingSearchClient 10 | { 11 | 12 | /// 13 | /// Manages the detected IpcWindow of Everything 14 | /// 15 | [SupportedOSPlatform("windows")] 16 | internal class IpcWindow 17 | { 18 | 19 | public IntPtr HWnd { get; private set; } = IntPtr.Zero; 20 | 21 | public IpcWindow() 22 | { 23 | Detect(); 24 | } 25 | 26 | public void Detect() 27 | { 28 | HWnd = FindWindow(EverythingIPC.EVERYTHING_IPC_WNDCLASS, null); 29 | } 30 | 31 | public bool IsAvailable 32 | { 33 | get 34 | { 35 | return HWnd != IntPtr.Zero; 36 | } 37 | } 38 | 39 | public bool IsBusy() 40 | { 41 | uint b = SendMessage(HWnd, EverythingIPC.EVERYTHING_WM_IPC, EverythingIPC.EVERYTHING_IPC_IS_DB_BUSY, 0); 42 | return b != 0; 43 | } 44 | 45 | public Version GetVersion() 46 | { 47 | int ma = (int)SendMessage(HWnd, EverythingIPC.EVERYTHING_WM_IPC, EverythingIPC.EVERYTHING_IPC_GET_MAJOR_VERSION, 0); 48 | int mi = (int)SendMessage(HWnd, EverythingIPC.EVERYTHING_WM_IPC, EverythingIPC.EVERYTHING_IPC_GET_MINOR_VERSION, 0); 49 | int re = (int)SendMessage(HWnd, EverythingIPC.EVERYTHING_WM_IPC, EverythingIPC.EVERYTHING_IPC_GET_REVISION, 0); 50 | int bu = (int)SendMessage(HWnd, EverythingIPC.EVERYTHING_WM_IPC, EverythingIPC.EVERYTHING_IPC_GET_BUILD_NUMBER, 0); 51 | // funny, how "revision" and "build" are order arbitrarily by different people/organizations 52 | return new Version(ma, mi, re, bu); 53 | } 54 | 55 | [DllImport("user32.dll", SetLastError = true)] 56 | private static extern IntPtr FindWindow(string lpClassName, string? lpWindowName); 57 | 58 | [DllImport("user32.dll", CharSet = CharSet.Auto)] 59 | private static extern uint SendMessage(IntPtr hWnd, uint Msg, uint wParam, uint lParam); 60 | 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /EverythingSearchClient/MessageReceiverWindow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Runtime.InteropServices; 7 | using System.Runtime.Versioning; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | 11 | namespace EverythingSearchClient 12 | { 13 | 14 | /// 15 | /// Native message only window to receive the results from Everything IPC 16 | /// 17 | [SupportedOSPlatform("windows")] 18 | internal class MessageReceiverWindow 19 | { 20 | #region P/Invoke 21 | 22 | #region Window Creation 23 | 24 | delegate IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam); 25 | 26 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 27 | struct WNDCLASS 28 | { 29 | public uint style; 30 | public IntPtr lpfnWndProc; 31 | public int cbClsExtra; 32 | public int cbWndExtra; 33 | public IntPtr hInstance; 34 | public IntPtr hIcon; 35 | public IntPtr hCursor; 36 | public IntPtr hbrBackground; 37 | public IntPtr lpszMenuName; 38 | public IntPtr lpszClassName; 39 | } 40 | 41 | [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] 42 | [return: MarshalAs(UnmanagedType.Bool)] 43 | private static extern bool GetClassInfoW(IntPtr hInstance, string lpClassName, ref WNDCLASS lpWndClass); 44 | 45 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 46 | struct WNDCLASSEXW { 47 | public uint cbSize; 48 | public uint style; 49 | public IntPtr lpfnWndProc; 50 | public int cbClsExtra; 51 | public int cbWndExtra; 52 | public IntPtr hInstance; 53 | public IntPtr hIcon; 54 | public IntPtr hCursor; 55 | public IntPtr hbrBackground; 56 | [MarshalAs(UnmanagedType.LPWStr)] 57 | public string lpszMenuName; 58 | [MarshalAs(UnmanagedType.LPWStr)] 59 | public string lpszClassName; 60 | public IntPtr hIconSm; 61 | } 62 | 63 | //[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] 64 | //static extern ushort RegisterClassW([In] ref WNDCLASS lpWndClass); 65 | 66 | [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] 67 | private static extern ushort RegisterClassExW(ref WNDCLASSEXW wndClass); 68 | 69 | [DllImport("user32.dll", SetLastError = true)] 70 | static extern IntPtr CreateWindowExW( 71 | uint dwExStyle, 72 | [MarshalAs(UnmanagedType.LPWStr)] string lpClassName, 73 | [MarshalAs(UnmanagedType.LPWStr)] string lpWindowName, 74 | uint dwStyle, 75 | int x, 76 | int y, 77 | int nWidth, 78 | int nHeight, 79 | IntPtr hWndParent, 80 | IntPtr hMenu, 81 | IntPtr hInstance, 82 | IntPtr lpParam); 83 | 84 | [DllImport("user32.dll", SetLastError = true)] 85 | static extern System.IntPtr DefWindowProcW(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam); 86 | 87 | [DllImport("user32.dll", SetLastError = true)] 88 | static extern bool DestroyWindow(IntPtr hWnd); 89 | 90 | #endregion 91 | 92 | private static IntPtr GetHInstance() 93 | { 94 | Module? m = Assembly.GetEntryAssembly()?.ManifestModule; 95 | if (m == null) 96 | { 97 | m = typeof(SearchClient).Module; 98 | } 99 | return Marshal.GetHINSTANCE(m); 100 | } 101 | 102 | #region Window Messages 103 | 104 | private const uint WM_COPYDATA = 0x004A; 105 | private const uint WM_CLOSE = 0x0010; 106 | private const uint WM_USER = 0x0400; 107 | 108 | [DllImport("user32.dll")] 109 | static extern void PostQuitMessage(int nExitCode); 110 | 111 | [DllImport("user32.dll")] 112 | static extern bool WaitMessage(); 113 | 114 | [StructLayout(LayoutKind.Sequential)] 115 | struct NativeMessage 116 | { 117 | public IntPtr handle; 118 | public uint msg; 119 | public IntPtr wParam; 120 | public IntPtr lParam; 121 | public uint time; 122 | public System.Drawing.Point p; 123 | } 124 | 125 | [DllImport("user32.dll")] 126 | [return: MarshalAs(UnmanagedType.Bool)] 127 | static extern bool PeekMessage(out NativeMessage lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax, uint wRemoveMsg); 128 | 129 | [DllImport("user32.dll")] 130 | static extern int GetMessage(out NativeMessage lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax); 131 | 132 | [DllImport("user32.dll")] 133 | static extern bool TranslateMessage([In] ref NativeMessage lpMsg); 134 | 135 | [DllImport("user32.dll")] 136 | static extern IntPtr DispatchMessage([In] ref NativeMessage lpmsg); 137 | 138 | /// 139 | /// https://www.pinvoke.net/default.aspx/Structures/COPYDATASTRUCT.html 140 | /// 141 | [StructLayout(LayoutKind.Sequential)] 142 | struct COPYDATASTRUCT 143 | { 144 | public IntPtr dwData; 145 | public int cbData; 146 | public IntPtr lpData; 147 | } 148 | 149 | [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 150 | private static extern uint SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); 151 | 152 | [DllImport("User32.dll", CharSet = CharSet.Auto, SetLastError = true)] 153 | internal static extern IntPtr PostMessage(IntPtr hwnd, uint msg, IntPtr wparam, IntPtr lparam); 154 | 155 | public enum ChangeWindowMessageFilterExAction : uint 156 | { 157 | Reset = 0, Allow = 1, DisAllow = 2 158 | }; 159 | 160 | [DllImport("user32.dll", SetLastError = true)] 161 | public static extern bool ChangeWindowMessageFilterEx(IntPtr hWnd, uint msg, ChangeWindowMessageFilterExAction action, IntPtr changeInfo); 162 | 163 | #endregion 164 | 165 | #endregion 166 | 167 | internal MessageReceiverWindow() 168 | { 169 | IntPtr hInst = GetHInstance(); 170 | 171 | EnsureWindowClassRegistered(hInst); 172 | 173 | hWnd = CreateWindowExW(0, WindowClassName, "", 0, 0, 0, 0, 0, IntPtr.Zero, IntPtr.Zero, hInst, IntPtr.Zero); 174 | if (hWnd == IntPtr.Zero) 175 | { 176 | int ec = Marshal.GetLastPInvokeError(); 177 | throw new InvalidOperationException($"Window not initialized {ec}"); 178 | } 179 | 180 | // Allow unelevated EverythingIPC-Windows to send data to this potentially elevated user window 181 | ChangeWindowMessageFilterEx(hWnd, WM_COPYDATA, ChangeWindowMessageFilterExAction.Allow, IntPtr.Zero); 182 | 183 | requests.Add(new((uint)new Random().Next(), this)); 184 | } 185 | 186 | ~MessageReceiverWindow() 187 | { 188 | var f = requests.Find((x) => x.Item2 == this); 189 | if (f != null) 190 | { 191 | requests.Remove(f); 192 | } 193 | 194 | if (hWnd != IntPtr.Zero) 195 | { 196 | DestroyWindow(hWnd); 197 | hWnd = IntPtr.Zero; 198 | } 199 | } 200 | 201 | internal bool BuildQuery(string query, SearchClient.SearchFlags flags, uint maxResults, uint offset) 202 | { 203 | var f = requests.Find((x) => x.Item2 == this); 204 | if (f == null) 205 | { 206 | throw new Exception("Initialization broken"); 207 | } 208 | if (hWnd == IntPtr.Zero) 209 | { 210 | throw new InvalidOperationException("Window not initialized"); 211 | } 212 | 213 | EverythingIPC.EVERYTHING_IPC_QUERY q = new(); 214 | q.reply_hwnd = (UInt32)hWnd; 215 | q.reply_copydata_message = f.Item1; 216 | q.search_flags = 0; 217 | if (flags.HasFlag(SearchClient.SearchFlags.MatchCase)) q.search_flags |= EverythingIPC.EVERYTHING_IPC_MATCHCASE; 218 | if (flags.HasFlag(SearchClient.SearchFlags.MatchWholeWord)) q.search_flags |= EverythingIPC.EVERYTHING_IPC_MATCHWHOLEWORD; 219 | if (flags.HasFlag(SearchClient.SearchFlags.MatchPath)) q.search_flags |= EverythingIPC.EVERYTHING_IPC_MATCHPATH; 220 | if (flags.HasFlag(SearchClient.SearchFlags.RegEx)) q.search_flags |= EverythingIPC.EVERYTHING_IPC_REGEX; 221 | q.max_results = maxResults; 222 | q.offset = offset; 223 | 224 | int querySize = Marshal.SizeOf(); 225 | int rawQuerySize = querySize + 2 * (query.Length + 1); 226 | rawQueryData = new byte[rawQuerySize]; 227 | 228 | IntPtr tmp = Marshal.AllocHGlobal(querySize); 229 | Marshal.StructureToPtr(q, tmp, false); 230 | Marshal.Copy(tmp, rawQueryData, 0, querySize); 231 | Marshal.FreeHGlobal(tmp); 232 | 233 | byte[] queryStringBytes = Encoding.Unicode.GetBytes(query + '\0'); 234 | Debug.Assert(queryStringBytes.Length + querySize == rawQuerySize); 235 | queryStringBytes.CopyTo(rawQueryData, querySize); 236 | 237 | queryVersion = 1; 238 | return rawQueryData.Length > 0; 239 | } 240 | 241 | internal bool BuildQuery2( 242 | string query, 243 | SearchClient.SearchFlags flags, 244 | uint maxResults, 245 | uint offset, 246 | SearchClient.SortBy sortBy, 247 | SearchClient.SortDirection sortDirection) 248 | { 249 | var f = requests.Find((x) => x.Item2 == this); 250 | if (f == null) 251 | { 252 | throw new Exception("Initialization broken"); 253 | } 254 | if (hWnd == IntPtr.Zero) 255 | { 256 | throw new InvalidOperationException("Window not initialized"); 257 | } 258 | 259 | EverythingIPC.EVERYTHING_IPC_QUERY2 q2 = new(); 260 | q2.reply_hwnd = (UInt32)hWnd; 261 | q2.reply_copydata_message = f.Item1; 262 | q2.search_flags = 0; 263 | if (flags.HasFlag(SearchClient.SearchFlags.MatchCase)) q2.search_flags |= EverythingIPC.EVERYTHING_IPC_MATCHCASE; 264 | if (flags.HasFlag(SearchClient.SearchFlags.MatchWholeWord)) q2.search_flags |= EverythingIPC.EVERYTHING_IPC_MATCHWHOLEWORD; 265 | if (flags.HasFlag(SearchClient.SearchFlags.MatchPath)) q2.search_flags |= EverythingIPC.EVERYTHING_IPC_MATCHPATH; 266 | if (flags.HasFlag(SearchClient.SearchFlags.RegEx)) q2.search_flags |= EverythingIPC.EVERYTHING_IPC_REGEX; 267 | q2.max_results = maxResults; 268 | q2.offset = offset; 269 | q2.request_flags = EverythingIPC.EVERYTHING_IPC_QUERY2_REQUEST_NAME 270 | | EverythingIPC.EVERYTHING_IPC_QUERY2_REQUEST_PATH 271 | | EverythingIPC.EVERYTHING_IPC_QUERY2_REQUEST_SIZE 272 | | EverythingIPC.EVERYTHING_IPC_QUERY2_REQUEST_DATE_CREATED 273 | | EverythingIPC.EVERYTHING_IPC_QUERY2_REQUEST_DATE_MODIFIED 274 | | EverythingIPC.EVERYTHING_IPC_QUERY2_REQUEST_ATTRIBUTES; 275 | if (sortBy != SearchClient.SortBy.None) 276 | { 277 | switch (sortBy) 278 | { 279 | case SearchClient.SortBy.Name: 280 | q2.sort_type = (sortDirection == SearchClient.SortDirection.Ascending) 281 | ? EverythingIPC.EVERYTHING_IPC_SORT_NAME_ASCENDING 282 | : EverythingIPC.EVERYTHING_IPC_SORT_NAME_DESCENDING; 283 | break; 284 | case SearchClient.SortBy.Path: 285 | q2.sort_type = (sortDirection == SearchClient.SortDirection.Ascending) 286 | ? EverythingIPC.EVERYTHING_IPC_SORT_PATH_ASCENDING 287 | : EverythingIPC.EVERYTHING_IPC_SORT_PATH_DESCENDING; 288 | break; 289 | case SearchClient.SortBy.Size: 290 | q2.sort_type = (sortDirection == SearchClient.SortDirection.Ascending) 291 | ? EverythingIPC.EVERYTHING_IPC_SORT_SIZE_ASCENDING 292 | : EverythingIPC.EVERYTHING_IPC_SORT_SIZE_DESCENDING; 293 | break; 294 | case SearchClient.SortBy.Extension: 295 | q2.sort_type = (sortDirection == SearchClient.SortDirection.Ascending) 296 | ? EverythingIPC.EVERYTHING_IPC_SORT_EXTENSION_ASCENDING 297 | : EverythingIPC.EVERYTHING_IPC_SORT_EXTENSION_DESCENDING; 298 | break; 299 | case SearchClient.SortBy.DateCreated: 300 | q2.sort_type = (sortDirection == SearchClient.SortDirection.Ascending) 301 | ? EverythingIPC.EVERYTHING_IPC_SORT_DATE_CREATED_ASCENDING 302 | : EverythingIPC.EVERYTHING_IPC_SORT_DATE_CREATED_DESCENDING; 303 | break; 304 | case SearchClient.SortBy.DateModified: 305 | q2.sort_type = (sortDirection == SearchClient.SortDirection.Ascending) 306 | ? EverythingIPC.EVERYTHING_IPC_SORT_DATE_MODIFIED_ASCENDING 307 | : EverythingIPC.EVERYTHING_IPC_SORT_DATE_MODIFIED_DESCENDING; 308 | break; 309 | } 310 | } 311 | 312 | int querySize = Marshal.SizeOf(); 313 | int rawQuerySize = querySize + 2 * (query.Length + 1); 314 | rawQueryData = new byte[rawQuerySize]; 315 | 316 | IntPtr tmp = Marshal.AllocHGlobal(querySize); 317 | Marshal.StructureToPtr(q2, tmp, false); 318 | Marshal.Copy(tmp, rawQueryData, 0, querySize); 319 | Marshal.FreeHGlobal(tmp); 320 | 321 | byte[] queryStringBytes = Encoding.Unicode.GetBytes(query + '\0'); 322 | Debug.Assert(queryStringBytes.Length + querySize == rawQuerySize); 323 | queryStringBytes.CopyTo(rawQueryData, querySize); 324 | 325 | queryVersion = 2; 326 | return rawQueryData.Length > 0; 327 | } 328 | 329 | private static List> requests = new(); 330 | 331 | private IntPtr hWnd; 332 | private byte[] rawQueryData = Array.Empty(); 333 | private int queryVersion = 0; 334 | 335 | internal int QueryVersion { get => queryVersion; } 336 | 337 | private WndProc delegWndProc = ReceiverWndProc; 338 | 339 | internal bool SendQuery(IntPtr ipcHWnd) 340 | { 341 | if (hWnd == IntPtr.Zero) 342 | { 343 | throw new InvalidOperationException("Window not initialized"); 344 | } 345 | if (rawQueryData.Length <= 0) 346 | { 347 | throw new InvalidOperationException("No query data built"); 348 | } 349 | if (queryVersion != 1 && queryVersion != 2) 350 | { 351 | throw new InvalidOperationException("Unsupported query data version built"); 352 | } 353 | 354 | IntPtr queryData = IntPtr.Zero; 355 | IntPtr cdsMem = IntPtr.Zero; 356 | uint result = 0; 357 | 358 | try 359 | { 360 | queryData = Marshal.AllocHGlobal(rawQueryData.Length); 361 | Marshal.Copy(rawQueryData, 0, queryData, rawQueryData.Length); 362 | 363 | COPYDATASTRUCT cds = new(); 364 | switch (queryVersion) 365 | { 366 | case 1: 367 | cds.dwData = (IntPtr)EverythingIPC.EVERYTHING_IPC_COPYDATAQUERYW; 368 | break; 369 | case 2: 370 | cds.dwData = (IntPtr)EverythingIPC.EVERYTHING_IPC_COPYDATA_QUERY2W; 371 | break; 372 | } 373 | cds.cbData = rawQueryData.Length; 374 | cds.lpData = queryData; 375 | 376 | cdsMem = Marshal.AllocHGlobal(Marshal.SizeOf()); 377 | Marshal.StructureToPtr(cds, cdsMem, true); 378 | 379 | result = SendMessage(ipcHWnd, WM_COPYDATA, hWnd, cdsMem); 380 | 381 | } 382 | finally 383 | { 384 | Marshal.FreeHGlobal(cdsMem); 385 | Marshal.FreeHGlobal(queryData); 386 | } 387 | 388 | return result != 0; 389 | } 390 | 391 | internal void MessagePump() 392 | { 393 | NativeMessage msg; 394 | int ret; 395 | 396 | while ((ret = GetMessage(out msg, IntPtr.Zero, 0, 0)) != 0) 397 | { 398 | if (ret == -1) 399 | { 400 | // illegal window handle 401 | break; 402 | } 403 | 404 | if (msg.msg == WM_USER) 405 | { 406 | // use WM_USER as additional push for a graceful close 407 | PostQuitMessage(0); 408 | break; 409 | } 410 | 411 | TranslateMessage(ref msg); 412 | DispatchMessage(ref msg); 413 | } 414 | } 415 | 416 | private const string WindowClassName = "EverythingSearchReceiverClient"; 417 | 418 | private static IntPtr ReceiverWndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) 419 | { 420 | if (msg == WM_CLOSE) 421 | { 422 | PostQuitMessage(0); 423 | } 424 | else 425 | if (msg == WM_COPYDATA) 426 | { 427 | COPYDATASTRUCT data = Marshal.PtrToStructure(lParam); 428 | var f = requests.Find((p) => p.Item1 == (uint)data.dwData); 429 | if (f != null) 430 | { 431 | f.Item2.ParseResultData(data.lpData, data.cbData); 432 | } 433 | PostQuitMessage(0); 434 | } 435 | return DefWindowProcW(hWnd, msg, wParam, lParam); 436 | } 437 | 438 | private void EnsureWindowClassRegistered(IntPtr hInst) 439 | { 440 | WNDCLASS wc = new(); 441 | if (!GetClassInfoW(hInst, WindowClassName, ref wc)) 442 | { 443 | WNDCLASSEXW wcex = new(); 444 | wcex.cbSize = (uint)Marshal.SizeOf(); 445 | wcex.hInstance = hInst; 446 | wcex.lpszClassName = WindowClassName; 447 | wcex.lpfnWndProc = Marshal.GetFunctionPointerForDelegate(delegWndProc); 448 | 449 | ushort atom = RegisterClassExW(ref wcex); 450 | int ec = Marshal.GetLastWin32Error(); 451 | if (atom == 0) 452 | { 453 | throw new Exception($"Failed to register response message-only window class {ec}"); 454 | } 455 | 456 | GetClassInfoW(hInst, WindowClassName, ref wc); 457 | } 458 | } 459 | 460 | public Result? Result { get; private set; } = null; 461 | 462 | class ResultImplementation : Result 463 | { 464 | public ResultImplementation(uint totalItems, uint offset, Item[] items) 465 | { 466 | TotalItems = totalItems; 467 | Offset = offset; 468 | Items = items; 469 | } 470 | } 471 | 472 | class ResultItemImplementation : Result.Item 473 | { 474 | public ResultItemImplementation(Result.ItemFlags flags, string filename, string path) 475 | { 476 | Flags = flags; 477 | Name = filename; 478 | Path = path; 479 | } 480 | 481 | public ResultItemImplementation( 482 | Result.ItemFlags flags, 483 | string filename, 484 | string path, 485 | ulong? fileSize, 486 | DateTime? createTime, 487 | DateTime? lastWriteTime, 488 | uint? attributes) 489 | { 490 | Flags = flags; 491 | Name = filename; 492 | Path = path; 493 | Size = fileSize; 494 | CreationTime = createTime; 495 | LastWriteTime = lastWriteTime; 496 | if (attributes.HasValue) 497 | { 498 | FileAttributes = (Result.ItemFileAttributes)attributes.Value; 499 | } 500 | } 501 | } 502 | 503 | private void ParseResultData(IntPtr mem, int size) 504 | { 505 | if (queryVersion == 1) 506 | { 507 | ParseResultDataVersion1(mem, size); 508 | } 509 | else if (queryVersion == 2) 510 | { 511 | ParseResultDataVersion2(mem, size); 512 | } 513 | } 514 | 515 | private void ParseResultDataVersion1(IntPtr mem, int size) 516 | { 517 | UInt32 TotalItems = (uint)Marshal.ReadInt32(mem + 2 * 4); 518 | int NumItems = Marshal.ReadInt32(mem + 5 * 4); 519 | UInt32 Offset = (uint)Marshal.ReadInt32(mem + 6 * 4); 520 | List items = new List(NumItems); 521 | 522 | for (int i = 0; i < NumItems; i++) 523 | { 524 | Result.ItemFlags flags = MapItemFlags(Marshal.ReadInt32(mem + (7 + i * 3 + 0) * 4)); 525 | UInt32 filename_offset = (uint)Marshal.ReadInt32(mem + (7 + i * 3 + 1) * 4); 526 | string? filename = Marshal.PtrToStringUni(mem + (int)filename_offset); 527 | if (string.IsNullOrEmpty(filename)) continue; 528 | UInt32 path_offset = (uint)Marshal.ReadInt32(mem + (7 + i * 3 + 2) * 4); 529 | string? path = Marshal.PtrToStringUni(mem + (int)path_offset); 530 | if (string.IsNullOrEmpty(path)) continue; 531 | items.Add(new ResultItemImplementation(flags, filename, path)); 532 | } 533 | 534 | Result = new ResultImplementation(TotalItems, Offset, items.ToArray()); 535 | } 536 | 537 | private void ParseResultDataVersion2(IntPtr mem, int size) 538 | { 539 | uint TotalItems = (uint)Marshal.ReadInt32(mem + 0 * 4); 540 | int NumItems = Marshal.ReadInt32(mem + 1 * 4); 541 | uint Offset = (uint)Marshal.ReadInt32(mem + 2 * 4); 542 | uint requestFlags = (uint)Marshal.ReadInt32(mem + 3 * 4); 543 | List items = new List(NumItems); 544 | 545 | for (int i = 0; i < NumItems; i++) 546 | { 547 | Result.ItemFlags flags = MapItemFlags(Marshal.ReadInt32(mem + (5 + i * 2 + 0) * 4)); 548 | int offset = Marshal.ReadInt32(mem + (5 + i * 2 + 1) * 4); 549 | 550 | string? filename = null; 551 | string? path = null; 552 | ulong? fileSize = null; 553 | DateTime? createDate = null; 554 | DateTime? modDate = null; 555 | uint? fileAttributes = null; 556 | 557 | // data found at data_offset 558 | // if EVERYTHING_IPC_QUERY2_REQUEST_NAME was set in request_flags, DWORD name_length in characters (excluding the null terminator); followed by null terminated text. 559 | if ((requestFlags & EverythingIPC.EVERYTHING_IPC_QUERY2_REQUEST_NAME) == EverythingIPC.EVERYTHING_IPC_QUERY2_REQUEST_NAME) 560 | { 561 | int len = Marshal.ReadInt32(mem + offset); 562 | offset += 4; 563 | filename = Marshal.PtrToStringUni(mem + offset, len); 564 | offset += (len + 1) * 2; 565 | } 566 | // if EVERYTHING_IPC_QUERY2_REQUEST_PATH was set in request_flags, DWORD name_length in characters (excluding the null terminator); followed by null terminated text. 567 | if ((requestFlags & EverythingIPC.EVERYTHING_IPC_QUERY2_REQUEST_PATH) == EverythingIPC.EVERYTHING_IPC_QUERY2_REQUEST_PATH) 568 | { 569 | int len = Marshal.ReadInt32(mem + offset); 570 | offset += 4; 571 | path = Marshal.PtrToStringUni(mem + offset, len); 572 | offset += (len + 1) * 2; 573 | } 574 | // if EVERYTHING_IPC_QUERY2_REQUEST_FULL_PATH_AND_NAME was set in request_flags, DWORD name_length (excluding the null terminator); followed by null terminated text. 575 | if ((requestFlags & EverythingIPC.EVERYTHING_IPC_QUERY2_REQUEST_FULL_PATH_AND_NAME) == EverythingIPC.EVERYTHING_IPC_QUERY2_REQUEST_FULL_PATH_AND_NAME) 576 | { 577 | int len = Marshal.ReadInt32(mem + offset); 578 | offset += 4; 579 | offset += (len + 1) * 2; 580 | } 581 | // if EVERYTHING_IPC_QUERY2_REQUEST_SIZE was set in request_flags, LARGE_INTERGER size; 582 | if ((requestFlags & EverythingIPC.EVERYTHING_IPC_QUERY2_REQUEST_SIZE) == EverythingIPC.EVERYTHING_IPC_QUERY2_REQUEST_SIZE) 583 | { 584 | fileSize = (ulong)Marshal.ReadInt64(mem + offset); 585 | offset += 8; 586 | } 587 | // if EVERYTHING_IPC_QUERY2_REQUEST_EXTENSION was set in request_flags, DWORD name_length in characters (excluding the null terminator); followed by null terminated text; 588 | if ((requestFlags & EverythingIPC.EVERYTHING_IPC_QUERY2_REQUEST_EXTENSION) == EverythingIPC.EVERYTHING_IPC_QUERY2_REQUEST_EXTENSION) 589 | { 590 | int len = Marshal.ReadInt32(mem + offset); 591 | offset += 4; 592 | offset += (len + 1) * 2; 593 | } 594 | // if EVERYTHING_IPC_QUERY2_REQUEST_TYPE_NAME was set in request_flags, DWORD name_length in characters (excluding the null terminator); followed by null terminated text; 595 | // Docu outdated | does not exist 596 | 597 | // if EVERYTHING_IPC_QUERY2_REQUEST_DATE_CREATED was set in request_flags, FILETIME date; 598 | if ((requestFlags & EverythingIPC.EVERYTHING_IPC_QUERY2_REQUEST_DATE_CREATED) == EverythingIPC.EVERYTHING_IPC_QUERY2_REQUEST_DATE_CREATED) 599 | { 600 | long timecode = Marshal.ReadInt64(mem + offset); 601 | if (timecode > 0) 602 | { 603 | try 604 | { 605 | createDate = DateTime.FromFileTime(timecode); 606 | } 607 | catch 608 | { 609 | createDate = null; 610 | } 611 | } 612 | offset += 8; 613 | } 614 | // if EVERYTHING_IPC_QUERY2_REQUEST_DATE_MODIFIED was set in request_flags, FILETIME date; 615 | if ((requestFlags & EverythingIPC.EVERYTHING_IPC_QUERY2_REQUEST_DATE_MODIFIED) == EverythingIPC.EVERYTHING_IPC_QUERY2_REQUEST_DATE_MODIFIED) 616 | { 617 | long timecode = Marshal.ReadInt64(mem + offset); 618 | try 619 | { 620 | modDate = DateTime.FromFileTime(timecode); 621 | } 622 | catch 623 | { 624 | modDate = null; 625 | } 626 | offset += 8; 627 | } 628 | // if EVERYTHING_IPC_QUERY2_REQUEST_DATE_ACCESSED was set in request_flags, FILETIME date; 629 | if ((requestFlags & EverythingIPC.EVERYTHING_IPC_QUERY2_REQUEST_DATE_ACCESSED) == EverythingIPC.EVERYTHING_IPC_QUERY2_REQUEST_DATE_ACCESSED) 630 | { 631 | offset += 8; 632 | } 633 | // if EVERYTHING_IPC_QUERY2_REQUEST_ATTRIBUTES was set in request_flags, DWORD attributes; 634 | if ((requestFlags & EverythingIPC.EVERYTHING_IPC_QUERY2_REQUEST_ATTRIBUTES) == EverythingIPC.EVERYTHING_IPC_QUERY2_REQUEST_ATTRIBUTES) 635 | { 636 | fileAttributes = (uint)Marshal.ReadInt32(mem + offset); 637 | // offset += 4; 638 | } 639 | 640 | if (filename != null && path != null) 641 | { 642 | items.Add(new ResultItemImplementation(flags, filename, path, fileSize, createDate, modDate, fileAttributes)); 643 | } 644 | } 645 | 646 | Result = new ResultImplementation(TotalItems, Offset, items.ToArray()); 647 | 648 | } 649 | 650 | private Result.ItemFlags MapItemFlags(int v) 651 | { 652 | Result.ItemFlags f = Result.ItemFlags.None; 653 | if ((v & EverythingIPC.EVERYTHING_IPC_FOLDER) == EverythingIPC.EVERYTHING_IPC_FOLDER) 654 | { 655 | f |= Result.ItemFlags.Folder; 656 | } 657 | if ((v & EverythingIPC.EVERYTHING_IPC_DRIVE) == EverythingIPC.EVERYTHING_IPC_DRIVE) 658 | { 659 | f |= Result.ItemFlags.Drive; 660 | } 661 | if ((v & ~(EverythingIPC.EVERYTHING_IPC_FOLDER | EverythingIPC.EVERYTHING_IPC_DRIVE)) != 0) 662 | { 663 | f |= Result.ItemFlags.Unknown; 664 | } 665 | return f; 666 | } 667 | 668 | internal void SendClose() 669 | { 670 | // Potential race condition fixed: 671 | // Using PostMessage here, 672 | // since the message pump might already have been exited because the window is already closing 673 | // (because it might have received the results). 674 | PostMessage(hWnd, WM_USER, IntPtr.Zero, IntPtr.Zero); 675 | PostMessage(hWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero); 676 | } 677 | } 678 | 679 | } 680 | -------------------------------------------------------------------------------- /EverythingSearchClient/Result.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace EverythingSearchClient 8 | { 9 | 10 | /// 11 | /// Read-only results of a search run 12 | /// 13 | public class Result 14 | { 15 | 16 | /// 17 | /// Descriptive type flags for items 18 | /// 19 | [Flags] 20 | public enum ItemFlags 21 | { 22 | /// 23 | /// Item is a normal file 24 | /// 25 | None = 0, 26 | 27 | /// 28 | /// Item is a folder 29 | /// 30 | Folder = 1, 31 | 32 | /// 33 | /// Item is a drive or root 34 | /// 35 | Drive = 2, 36 | 37 | /// 38 | /// Something strange 39 | /// 40 | Unknown = 0x80 41 | 42 | } 43 | 44 | /// 45 | /// File attribute flags 46 | /// 47 | [Flags] 48 | public enum ItemFileAttributes 49 | { 50 | /// 51 | /// No file attributes are set 52 | /// 53 | None = 0, 54 | 55 | /// 56 | /// The file is read-only. 57 | /// 58 | ReadOnly = 1, 59 | 60 | /// 61 | /// The file is hidden, and thus is not included in an ordinary directory listing. 62 | /// 63 | Hidden = 2, 64 | 65 | /// 66 | /// The file is a system file. 67 | /// 68 | System = 4, 69 | 70 | /// 71 | /// The file is a directory. 72 | /// 73 | Directory = 16, 74 | 75 | /// 76 | /// This file is marked to be included in incremental backup operation. 77 | /// 78 | Archive = 32, 79 | 80 | /// 81 | /// The file is a standard file that has no special attributes. 82 | /// This attribute is valid only if it is used alone. 83 | /// 84 | Normal = 128 85 | 86 | } 87 | 88 | /// 89 | /// Description of one item 90 | /// 91 | public class Item 92 | { 93 | 94 | /// 95 | /// Gets the type flags 96 | /// 97 | public ItemFlags Flags { get; protected set; } = ItemFlags.None; 98 | 99 | /// 100 | /// Gets the name of the item, not including any path segment 101 | /// 102 | public string Name { get; protected set; } = string.Empty; 103 | 104 | /// 105 | /// Gets the path to the item, without the item's name 106 | /// 107 | public string Path { get; protected set; } = string.Empty; 108 | 109 | /// 110 | /// Gets the optional size of the file on disk in bytes 111 | /// 112 | public ulong? Size { get; protected set; } = null; 113 | 114 | /// 115 | /// Gets the optional creation date time 116 | /// 117 | public DateTime? CreationTime{ get; protected set; } = null; 118 | 119 | /// 120 | /// Gets the optional date time of the last file modification 121 | /// 122 | public DateTime? LastWriteTime { get; protected set; } = null; 123 | 124 | /// 125 | /// Gets the optional file attributes 126 | /// 127 | public ItemFileAttributes? FileAttributes { get; protected set; } = null; 128 | 129 | } 130 | 131 | /// 132 | /// Gets the total number of items found in the search run 133 | /// 134 | public UInt32 TotalItems { get; protected set; } = 0; 135 | 136 | /// 137 | /// Gets the number of items returned in this object 138 | /// 139 | public UInt32 NumItems { get => (UInt32)Items.Length; } 140 | 141 | /// 142 | /// Gets the offset of the results array of this object 143 | /// inside the total results list of the search run. 144 | /// 145 | public UInt32 Offset { get; protected set; } = 0; 146 | 147 | /// 148 | /// Gets the array of found items 149 | /// 150 | public Item[] Items {get; protected set; } = Array.Empty(); 151 | 152 | } 153 | 154 | } 155 | -------------------------------------------------------------------------------- /EverythingSearchClient/ResultsNotReceivedException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace EverythingSearchClient 8 | { 9 | public class ResultsNotReceivedException : Exception 10 | { 11 | public ResultsNotReceivedException() : base("Failed to receive results") { } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /EverythingSearchClient/SearchClient.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | using System.Runtime.Versioning; 4 | using System.Threading; 5 | 6 | namespace EverythingSearchClient 7 | { 8 | 9 | [SupportedOSPlatform("windows")] 10 | public class SearchClient 11 | { 12 | 13 | private static IpcWindow ipcWindow = new IpcWindow(); 14 | 15 | /// 16 | /// Predefined search filter string for audio files 17 | /// 18 | public const string FilterAudio = "nofiltercase:nofilterpath:nofilterwholeword:filterdiacritics:nofilterregex:"; 19 | 20 | /// 21 | /// Predefined search filter string for compressed archives files 22 | /// 23 | public const string FilterZipped = "nofiltercase:nofilterpath:nofilterwholeword:filterdiacritics:nofilterregex:"; 24 | 25 | /// 26 | /// Predefined search filter string for documents 27 | /// 28 | public const string FilterDocuments = "nofiltercase:nofilterpath:nofilterwholeword:filterdiacritics:nofilterregex:"; 29 | 30 | /// 31 | /// Predefined search filter string for executable files 32 | /// 33 | public const string FilterExecutables = "nofiltercase:nofilterpath:nofilterwholeword:filterdiacritics:nofilterregex:"; 34 | 35 | /// 36 | /// Predefined search filter string for picture files 37 | /// 38 | public const string FilterPictures = "nofiltercase:nofilterpath:nofilterwholeword:filterdiacritics:nofilterregex:"; 39 | 40 | /// 41 | /// Predefined search filter string for video files 42 | /// 43 | public const string FilterVideo = "nofiltercase:nofilterpath:nofilterwholeword:filterdiacritics:nofilterregex:"; 44 | 45 | /// 46 | /// Checks if the Everything service is available 47 | /// 48 | public static bool IsEverythingAvailable() 49 | { 50 | if (!ipcWindow.IsAvailable) 51 | { 52 | ipcWindow.Detect(); 53 | } 54 | return ipcWindow.IsAvailable; 55 | } 56 | 57 | /// 58 | /// Gets the version of the Everything service 59 | /// 60 | /// When Everything is not available 61 | public static Version GetEverythingVersion() 62 | { 63 | if (!IsEverythingAvailable()) 64 | { 65 | throw new InvalidOperationException("Everything service is not available"); 66 | } 67 | return ipcWindow.GetVersion(); 68 | } 69 | 70 | /// 71 | /// Checks whether the Everything service is currently busy with another query. 72 | /// 73 | /// When Everything is not available 74 | public static bool IsEverythingBusy() 75 | { 76 | if (!IsEverythingAvailable()) 77 | { 78 | throw new InvalidOperationException("Everything service is not available"); 79 | } 80 | return ipcWindow.IsBusy(); 81 | } 82 | 83 | [Flags] 84 | public enum SearchFlags 85 | { 86 | None = 0, 87 | MatchCase = 1, 88 | MatchWholeWord = 2, // match whole word 89 | MatchPath = 4, // include paths in search 90 | RegEx = 8 // enable regex 91 | } 92 | 93 | /// 94 | /// Sort results by one of these attributes 95 | /// 96 | public enum SortBy 97 | { 98 | None, 99 | Name, 100 | Path, 101 | Size, 102 | Extension, 103 | DateCreated, 104 | DateModified 105 | } 106 | 107 | /// 108 | /// Define results sort order direction 109 | /// 110 | public enum SortDirection 111 | { 112 | Ascending, 113 | Decending 114 | } 115 | 116 | /// 117 | /// Defines what the client should do when the Everything service is busy 118 | /// 119 | public enum BehaviorWhenBusy 120 | { 121 | /// 122 | /// Blockingly waits the specified timeout. 123 | /// If the service becomes free, the search query will be issued. 124 | /// Please, note that system-wide race conditions might still be possible. 125 | /// If the timeout triggers and the service is still blocked, an error is raised. 126 | /// 127 | WaitOrError, 128 | 129 | /// 130 | /// Blockingly waits the specified timeout. 131 | /// If the service becomes free, the search query will be issued. 132 | /// Please, note that system-wide race conditions might still be possible. 133 | /// If the timeout triggers and the service is still blocked, the query is issued anyway. 134 | /// This will abort the currently running query, 135 | /// which might lead to undefined behavior in other applications 136 | /// which might be waiting on their results. 137 | /// 138 | WaitOrContinue, 139 | 140 | /// 141 | /// Throws an exception if the service is busy. 142 | /// 143 | Error, 144 | 145 | /// 146 | /// Continue issuing the query. 147 | /// This will abort the currently running query, 148 | /// which might lead to undefined behavior in other applications 149 | /// which might be waiting on their results. 150 | /// 151 | Continue 152 | } 153 | 154 | /// 155 | /// Setting to restrict which version of the query API of Everything is to be used 156 | /// 157 | public enum QueryApi 158 | { 159 | /// 160 | /// Tries to call the best API first, and might fallback to other on the loss of functionality 161 | /// 162 | Any, 163 | 164 | /// 165 | /// Query API (first version) of Everything IPC 166 | /// 167 | Query1only, 168 | 169 | /// 170 | /// Query 2 API of Everything IPC offers access to file times and sizes 171 | /// This option does not fall back to Query1 172 | /// 173 | Query2only 174 | } 175 | 176 | /// 177 | /// When used for `maxResults`, indicates to return all items 178 | /// 179 | public const uint AllItems = 0xffffffff; 180 | 181 | /// 182 | /// The default timeout is 1 minute 183 | /// 184 | public const uint DefaultTimeoutMs = 60 * 1000; 185 | 186 | /// 187 | /// Specify which Query API version of Everything ICP to use 188 | /// 189 | public QueryApi UseQueryApi { get; set; } = QueryApi.Any; 190 | 191 | /// 192 | /// Specifies the timeout when trying to receive data from Everything IPC 193 | /// 194 | /// 195 | /// The timeout is only measured when Everything is not busy, to exclude the time needed to actually collect the result. 196 | /// 197 | public TimeSpan ReceiveTimeout { get; set; } = TimeSpan.FromSeconds(5); 198 | 199 | /// 200 | /// Issues a search query to the Everything service, waits and returns the Result. 201 | /// 202 | /// The Everything query string 203 | /// Wait timeout in milliseconds. Is only used when `whenBusy` is one of the `Wait*` options. 204 | /// When Everything is not available 205 | public Result Search( 206 | string query, 207 | SearchFlags flags = SearchFlags.None, 208 | uint maxResults = AllItems, 209 | uint offset = 0, 210 | BehaviorWhenBusy whenBusy = BehaviorWhenBusy.WaitOrError, 211 | uint timeoutMs = DefaultTimeoutMs, 212 | SortBy sortBy = SortBy.None, 213 | SortDirection sortDirection = SortDirection.Ascending) 214 | { 215 | if (!IsEverythingAvailable()) 216 | { 217 | throw new InvalidOperationException("Everything service is not available"); 218 | } 219 | 220 | QueryApi api = UseQueryApi; 221 | 222 | MessageReceiverWindow myWnd = new(); 223 | 224 | bool sent = false; 225 | // first, try send via ApiV2 226 | if (api == QueryApi.Any || api == QueryApi.Query2only) 227 | { 228 | if (myWnd.BuildQuery2(query, flags, maxResults, offset, sortBy, sortDirection)) 229 | { 230 | HandleBusyEverything(whenBusy, timeoutMs); 231 | if (myWnd.SendQuery(ipcWindow.HWnd)) 232 | { 233 | sent = true; 234 | } 235 | else 236 | { 237 | // if failing 238 | if (api == QueryApi.Query2only) 239 | { 240 | throw new Exception("Failed to send search query"); 241 | } 242 | // else, retry with lower api 243 | } 244 | } 245 | else 246 | { 247 | if (api == QueryApi.Query2only) 248 | { 249 | throw new Exception("Failed to build search query data structure"); 250 | } 251 | // else, fallback to query1 api when creating query2 failed, and any api version allowed 252 | } 253 | } 254 | if (!sent) 255 | { 256 | // second try: Query ApiV1 257 | if (api == QueryApi.Any || api == QueryApi.Query1only) 258 | { 259 | if (!myWnd.BuildQuery(query, flags, maxResults, offset)) 260 | { 261 | throw new Exception("Failed to build search query data structure"); 262 | } 263 | HandleBusyEverything(whenBusy, timeoutMs); 264 | if (myWnd.SendQuery(ipcWindow.HWnd)) 265 | { 266 | sent = true; 267 | } 268 | else 269 | { 270 | throw new Exception("Failed to send search query"); 271 | } 272 | } 273 | } 274 | 275 | if (sent) 276 | { 277 | // Implement timeout 278 | bool checkForTimeout = true; 279 | Thread checkTimeout = new Thread(() => 280 | { 281 | DateTime last = DateTime.Now; 282 | TimeSpan timeout = ReceiveTimeout; 283 | while (checkForTimeout) 284 | { 285 | Thread.Sleep(10); 286 | if (IsEverythingBusy()) 287 | { 288 | last = DateTime.Now; 289 | } 290 | else if ((DateTime.Now - last) > timeout) 291 | { 292 | myWnd.SendClose(); 293 | break; 294 | } 295 | } 296 | }); 297 | checkTimeout.Start(); 298 | 299 | myWnd.MessagePump(); 300 | 301 | checkForTimeout = false; 302 | checkTimeout.Join(); 303 | } 304 | 305 | if (myWnd.Result == null) 306 | { 307 | throw new ResultsNotReceivedException(); 308 | } 309 | 310 | return myWnd.Result; 311 | } 312 | 313 | private void HandleBusyEverything(BehaviorWhenBusy whenBusy, uint timeoutMs) 314 | { 315 | // Handle busy state of Everything 316 | if (IsEverythingBusy()) 317 | { 318 | switch (whenBusy) 319 | { 320 | case BehaviorWhenBusy.Continue: 321 | // just continue 322 | break; 323 | case BehaviorWhenBusy.Error: 324 | throw new EverythingBusyException(); 325 | case BehaviorWhenBusy.WaitOrContinue: 326 | if (!Wait(timeoutMs)) 327 | { 328 | goto case BehaviorWhenBusy.Continue; 329 | } 330 | break; 331 | case BehaviorWhenBusy.WaitOrError: 332 | if (!Wait(timeoutMs)) 333 | { 334 | goto case BehaviorWhenBusy.Error; 335 | } 336 | break; 337 | default: 338 | throw new ArgumentException("Unknown whenBusy behavior"); 339 | } 340 | } 341 | } 342 | 343 | /// 344 | /// Wait for `timeoutMs` milliseconds that the Everything service is no longer busy 345 | /// 346 | /// 0 means wait indefinitely. 347 | /// True if Everything service is ready, False if timeout reached 348 | private bool Wait(uint timeoutMs) 349 | { 350 | DateTime start = DateTime.Now; 351 | while (IsEverythingBusy()) 352 | { 353 | DateTime now = DateTime.Now; 354 | if (timeoutMs > 0 && (now - start).TotalMilliseconds > timeoutMs) 355 | { 356 | return false; 357 | } 358 | Thread.Sleep(10); 359 | } 360 | return true; 361 | } 362 | 363 | /// 364 | /// Issues a search query to the Everything service, waits and returns the Result. 365 | /// 366 | /// The Everything query string 367 | /// Wait timeout in milliseconds. Is only used when `whenBusy` is one of the `Wait*` options. 368 | /// When Everything is not available 369 | public Result Search(string query, SearchFlags flags, BehaviorWhenBusy whenBusy, uint timeoutMs = DefaultTimeoutMs) 370 | { 371 | return Search(query, flags, AllItems, 0, whenBusy, timeoutMs); 372 | } 373 | 374 | /// 375 | /// Issues a search query to the Everything service, waits and returns the Result. 376 | /// 377 | /// The Everything query string 378 | /// Wait timeout in milliseconds. Is only used when `whenBusy` is one of the `Wait*` options. 379 | /// When Everything is not available 380 | public Result Search(string query, BehaviorWhenBusy whenBusy, uint timeoutMs = DefaultTimeoutMs) 381 | { 382 | return Search(query, SearchFlags.None, AllItems, 0, whenBusy, timeoutMs); 383 | } 384 | 385 | /// 386 | /// Issues a search query to the Everything service, waits and returns the Result. 387 | /// 388 | /// The Everything query string 389 | /// Wait timeout in milliseconds. Is only used when `whenBusy` is one of the `Wait*` options. 390 | /// When Everything is not available 391 | public Result Search(string query, uint maxResults, uint offset = 0, BehaviorWhenBusy whenBusy = BehaviorWhenBusy.WaitOrError, uint timeoutMs = DefaultTimeoutMs) 392 | { 393 | return Search(query, SearchFlags.None, maxResults, offset, whenBusy, timeoutMs); 394 | } 395 | 396 | /// 397 | /// Issues a search query to the Everything service, waits and returns the Result. 398 | /// 399 | /// The Everything query string 400 | /// Wait timeout in milliseconds. Is only used when `whenBusy` is one of the `Wait*` options. 401 | /// When Everything is not available 402 | public Result Search(string query, uint maxResults, BehaviorWhenBusy whenBusy, uint timeoutMs = DefaultTimeoutMs) 403 | { 404 | return Search(query, SearchFlags.None, maxResults, 0, whenBusy, timeoutMs); 405 | } 406 | 407 | } 408 | } 409 | -------------------------------------------------------------------------------- /EverythingSearchClient/ServiceControl.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Runtime.InteropServices; 5 | using System.Runtime.Versioning; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace EverythingSearchClient 10 | { 11 | /// 12 | /// Utility class to control the Everything service, if installed 13 | /// 14 | [SupportedOSPlatform("windows")] 15 | public static class ServiceControl 16 | { 17 | 18 | /// 19 | /// Checks whether or not the Everything service is installed. 20 | /// 21 | /// 22 | /// If 23 | /// SearchClient.IsEverythingAvailable() == true 24 | /// and 25 | /// ServiceControl.IsServiceInstalled() == false 26 | /// or 27 | /// ServiceControl.IsServiceRunning() == false 28 | /// then, the everything functions are served by a non-daemon process started by the user. 29 | /// 30 | public static bool IsServiceInstalled() 31 | { 32 | bool isInstalled = false; 33 | 34 | (IntPtr hSCM, IntPtr hService) = OpenService(false); 35 | 36 | if (hService != IntPtr.Zero) 37 | { 38 | isInstalled = true; 39 | CloseServiceHandle(hService); 40 | } 41 | CloseServiceHandle(hSCM); 42 | 43 | return isInstalled; 44 | } 45 | 46 | /// 47 | /// Checks whether or not the Everything service is installed and running. 48 | /// 49 | /// 50 | /// If 51 | /// SearchClient.IsEverythingAvailable() == true 52 | /// and 53 | /// ServiceControl.IsServiceInstalled() == false 54 | /// or 55 | /// ServiceControl.IsServiceRunning() == false 56 | /// then, the everything functions are served by a non-daemon process started by the user. 57 | /// 58 | public static bool IsServiceRunning() 59 | { 60 | bool isRunning = false; 61 | 62 | (IntPtr hSCM, IntPtr hService) = OpenService(false); 63 | 64 | if (hService != IntPtr.Zero) 65 | { 66 | isRunning = QueryIsServiceRunning(hService); 67 | CloseServiceHandle(hService); 68 | } 69 | 70 | CloseServiceHandle(hSCM); 71 | 72 | return isRunning; 73 | } 74 | 75 | /// 76 | /// Starts the Everything service if stopped. 77 | /// 78 | /// If the Everything service is not installed. 79 | /// Cannot change service state, because OS denied access. 80 | /// You likely need to run the process calling this function with elevated user rights. 81 | public static void Start() 82 | { 83 | (IntPtr hSCM, IntPtr hService) = OpenService(true); 84 | try 85 | { 86 | if (hService == IntPtr.Zero) throw new InvalidOperationException("Service is not installed"); 87 | bool isRunning = QueryIsServiceRunning(hService); 88 | if (isRunning) return; 89 | 90 | if (!StartService(hService, 0, Array.Empty())) 91 | { 92 | int lastError = Marshal.GetLastPInvokeError(); 93 | if (lastError == ERROR_ACCESS_DENIED) throw new UnauthorizedAccessException($"Cannot start service: {lastError}"); 94 | throw new Exception($"Cannot start service: {lastError}"); 95 | } 96 | } 97 | finally 98 | { 99 | if (hService != IntPtr.Zero) CloseServiceHandle(hService); 100 | if (hSCM != IntPtr.Zero) CloseServiceHandle(hSCM); 101 | } 102 | } 103 | 104 | /// 105 | /// Stops the Everything service if running. 106 | /// 107 | /// If the Everything service is not installed. 108 | /// Cannot change service state, because OS denied access. 109 | /// You likely need to run the process calling this function with elevated user rights. 110 | public static void Stop() 111 | { 112 | (IntPtr hSCM, IntPtr hService) = OpenService(true); 113 | try 114 | { 115 | if (hService == IntPtr.Zero) throw new InvalidOperationException("Service is not installed"); 116 | bool isRunning = QueryIsServiceRunning(hService); 117 | if (!isRunning) return; 118 | 119 | SERVICE_STATUS status = new SERVICE_STATUS(); 120 | if (!ControlService(hService, SERVICE_CONTROL_STOP, ref status)) 121 | { 122 | int lastError = Marshal.GetLastPInvokeError(); 123 | if (lastError == ERROR_ACCESS_DENIED) throw new UnauthorizedAccessException($"Cannot stop service: {lastError}"); 124 | throw new Exception($"Cannot stop service: {lastError}"); 125 | } 126 | 127 | } 128 | finally 129 | { 130 | if (hService != IntPtr.Zero) CloseServiceHandle(hService); 131 | if (hSCM != IntPtr.Zero) CloseServiceHandle(hSCM); 132 | } 133 | } 134 | 135 | private static (IntPtr, IntPtr) OpenService(bool change) 136 | { 137 | IntPtr hSCM = OpenSCManager(null, null, SC_MANAGER_CONNECT); 138 | if (hSCM == IntPtr.Zero) throw new Exception("Cannot access service control manager"); 139 | 140 | IntPtr hService = OpenService(hSCM, 141 | "Everything", 142 | change 143 | ? (SERVICE_START | SERVICE_STOP | SERVICE_QUERY_STATUS) 144 | : SERVICE_QUERY_STATUS); 145 | if (hService == IntPtr.Zero) 146 | { 147 | uint lastError = (uint)Marshal.GetLastPInvokeError(); 148 | if (ERROR_SERVICE_DOES_NOT_EXIST != lastError) 149 | { 150 | CloseServiceHandle(hSCM); 151 | throw new Exception($"Cannot open service handle: {lastError}"); 152 | } 153 | } 154 | 155 | return (hSCM, hService); 156 | } 157 | 158 | private static bool QueryIsServiceRunning(IntPtr hService) 159 | { 160 | SERVICE_STATUS_PROCESS status = new SERVICE_STATUS_PROCESS(); 161 | if (QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, ref status, Marshal.SizeOf(), out _)) 162 | { 163 | return (status.currentState & SERVICE_RUNNING) == SERVICE_RUNNING; 164 | } 165 | return false; 166 | } 167 | 168 | private const uint SC_MANAGER_CONNECT = 0x0001; 169 | private const uint SERVICE_QUERY_STATUS = 0x0004; 170 | private const uint SERVICE_START = 0x0010; 171 | private const uint SERVICE_STOP = 0x0020; 172 | private const uint ERROR_SERVICE_DOES_NOT_EXIST = 1060; 173 | private const uint SC_STATUS_PROCESS_INFO = 0; 174 | private const uint SERVICE_RUNNING = 0x00000004; 175 | private const uint SERVICE_CONTROL_STOP = 0x00000001; 176 | private const int ERROR_ACCESS_DENIED = 0x5; 177 | 178 | [DllImport("advapi32.dll", EntryPoint = "OpenSCManagerW", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] 179 | private static extern IntPtr OpenSCManager(string? machineName, string? databaseName, uint dwAccess); 180 | 181 | [DllImport("advapi32.dll", SetLastError = true)] 182 | [return: MarshalAs(UnmanagedType.Bool)] 183 | private static extern bool CloseServiceHandle(IntPtr hSCObject); 184 | 185 | [DllImport("advapi32.dll", EntryPoint = "OpenServiceA", SetLastError = true, CharSet = CharSet.Ansi)] 186 | private static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess); 187 | 188 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 189 | private struct SERVICE_STATUS 190 | { 191 | public int serviceType; 192 | public int currentState; 193 | public int controlsAccepted; 194 | public int win32ExitCode; 195 | public int serviceSpecificExitCode; 196 | public int checkPoint; 197 | public int waitHint; 198 | } 199 | 200 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 201 | private struct SERVICE_STATUS_PROCESS 202 | { 203 | public int serviceType; 204 | public int currentState; 205 | public int controlsAccepted; 206 | public int win32ExitCode; 207 | public int serviceSpecificExitCode; 208 | public int checkPoint; 209 | public int waitHint; 210 | public int processID; 211 | public int serviceFlags; 212 | } 213 | 214 | [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 215 | [return: MarshalAs(UnmanagedType.Bool)] 216 | private static extern bool QueryServiceStatusEx(IntPtr serviceHandle, uint infoLevel, ref SERVICE_STATUS_PROCESS buffer, int bufferSize, out uint bytesNeeded); 217 | 218 | [DllImport("advapi32.dll", SetLastError = true)] 219 | [return: MarshalAs(UnmanagedType.Bool)] 220 | private static extern bool ControlService(IntPtr hService, uint dwControl, ref SERVICE_STATUS lpServiceStatus); 221 | 222 | [DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true)] 223 | [return: MarshalAs(UnmanagedType.Bool)] 224 | private static extern bool StartService(IntPtr hService, int dwNumServiceArgs, string[] lpServiceArgVectors); 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /ExampleApp/ExampleApp.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net6.0-windows 6 | enable 7 | enable 8 | ..\Images\MagnifyingGlass.ico 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /ExampleApp/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace EverythingSearchClient.Example 4 | { 5 | 6 | internal class Program 7 | { 8 | private static void Main(string[] args) 9 | { 10 | try 11 | { 12 | Console.OutputEncoding = Encoding.Unicode; 13 | 14 | if (!SearchClient.IsEverythingAvailable()) 15 | { 16 | throw new Exception("Everything service seems unavailable"); 17 | } 18 | Console.WriteLine("Everything v{0}", SearchClient.GetEverythingVersion()); 19 | if (SearchClient.IsEverythingBusy()) 20 | { 21 | Console.WriteLine("\tBusy! Issuing a search query might abort the currently running query."); 22 | } 23 | 24 | Console.WriteLine("\trunning as {0}", 25 | (ServiceControl.IsServiceInstalled() && ServiceControl.IsServiceRunning()) 26 | ? "Service" 27 | : "User Process"); 28 | 29 | // TryServiceRestart(); 30 | 31 | SearchClient search = new(); 32 | Result res; 33 | 34 | // Be aware, there is somewhere a race condition with the on-demand created messages windows receiving the search result. 35 | // This means, sometimes `Search` will not receive it's results, and can run into a timeout. 36 | // You should ALWAYS set a time out: a software displaying an error is better, than a software freezing up. 37 | // Combine a timeout with some retries in hope of recovery. 38 | // The following code works on one of my horribly slow legacy drives: (change "C:\" to your slow drive) 39 | 40 | var d = DriveInfo.GetDrives().Where((d) => { return d.IsReady && d.DriveType == DriveType.Fixed; }).ToList(); 41 | d.Sort((a, b) => { return a.Name.CompareTo(b.Name); }); 42 | string slowHDDisk = d.Last().Name; 43 | 44 | uint offset = 0; 45 | uint pageSize = 10000; // Try to receive 10k files per query. 46 | uint timeoutMs = 2000; // Give the query a 2sec timeout, which is ok most of the time. 47 | // You could measure the timeout based on successful queries. 48 | const int numTries = 10; // If a query fails, retry. But keep track and only try so often, then break with an error message 49 | int retry = numTries; 50 | 51 | while(true) 52 | { 53 | try 54 | { 55 | res = search.Search( 56 | $"{slowHDDisk} files:", 57 | maxResults: pageSize, 58 | offset: offset, 59 | whenBusy: SearchClient.BehaviorWhenBusy.WaitOrError, 60 | timeoutMs: timeoutMs); // Note: the timeout is used multiple times: 61 | // 1) when waiting for a busy Everything service to become ready, and 62 | // 2) when waiting for the results of a sent query. 63 | } 64 | catch (ResultsNotReceivedException) 65 | { 66 | if (retry > 0) 67 | { 68 | Console.WriteLine("ResultsNotReceivedException - Retry!"); 69 | Thread.Sleep(1); // give Everything some additional time to recover. 70 | retry--; 71 | continue; 72 | } 73 | else 74 | { 75 | throw; 76 | } 77 | } 78 | retry = numTries; 79 | Console.WriteLine($"{res.NumItems} ({pageSize}) + o:{res.Offset} ({offset}) / {res.TotalItems}"); 80 | offset += res.NumItems; 81 | if (offset >= res.TotalItems) break; 82 | } 83 | Console.WriteLine("done."); 84 | 85 | 86 | res = search.Search("^\\.git$", SearchClient.SearchFlags.RegEx); 87 | Console.WriteLine("\nFound {0} items:", res.NumItems); 88 | foreach (Result.Item item in res.Items) 89 | { 90 | Console.WriteLine("\t{0}", item.Name); 91 | Console.WriteLine("\t\t{0} | {1}", item.Flags, item.Path); 92 | } 93 | 94 | 95 | res = search.Search("C:\\Windows file: " + SearchClient.FilterAudio); 96 | Console.WriteLine("\nFound {0} Windows sound files", res.NumItems); 97 | 98 | 99 | } 100 | catch (Exception ex) 101 | { 102 | Console.WriteLine("\nEXCEPTION: {0}", ex); 103 | } 104 | } 105 | 106 | private static void TryServiceRestart() 107 | { 108 | try 109 | { 110 | if (ServiceControl.IsServiceRunning()) 111 | { 112 | Console.Write("Stopping service ..."); 113 | ServiceControl.Stop(); 114 | while (ServiceControl.IsServiceRunning()) Thread.Sleep(100); 115 | Console.WriteLine(" done"); 116 | } 117 | if (ServiceControl.IsServiceInstalled() && !ServiceControl.IsServiceRunning()) 118 | { 119 | Console.Write("Starting service ..."); 120 | ServiceControl.Start(); 121 | while (!ServiceControl.IsServiceRunning()) Thread.Sleep(100); 122 | Console.WriteLine(" done"); 123 | } 124 | } 125 | catch (Exception ex2) 126 | { 127 | Console.WriteLine("Exception controlling Everything service: {0}", ex2); 128 | } 129 | } 130 | 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /Images/MagnifyingGlass.afdesign: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sgrottel/EverythingSearchClient/12b21a445cead2a3ee598ae302fed6c62a14a0cb/Images/MagnifyingGlass.afdesign -------------------------------------------------------------------------------- /Images/MagnifyingGlass.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sgrottel/EverythingSearchClient/12b21a445cead2a3ee598ae302fed6c62a14a0cb/Images/MagnifyingGlass.ico -------------------------------------------------------------------------------- /Images/MagnifyingGlass_x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sgrottel/EverythingSearchClient/12b21a445cead2a3ee598ae302fed6c62a14a0cb/Images/MagnifyingGlass_x128.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🔎 EverythingSearchClient 2 | A .NET client library for [Voidtools' Everything](https://www.voidtools.com/) search engine, without the native Everything SDK dll. 3 | 4 | [![Build & Test](https://github.com/sgrottel/EverythingSearchClient/actions/workflows/dotnet-desktop.yml/badge.svg)](https://github.com/sgrottel/EverythingSearchClient/actions/workflows/dotnet-desktop.yml) 5 | [![Nuget](https://img.shields.io/nuget/v/EverythingSearchClient)](https://www.nuget.org/packages/EverythingSearchClient) 6 | [![GitHub](https://img.shields.io/github/license/sgrottel/EverythingSearchClient)](./LICENSE) 7 | 8 | I wrote this library, because I wanted a managed .NET solution with a simple interface, which would not depend on the [native code SDK by Voidtools](https://www.voidtools.com/support/everything/sdk/). 9 | I wanted to have _**one AnyCpu Dll**_ to do the job. 10 | 11 | So, this library uses a message-only window and the [IPC mechanism](https://www.voidtools.com/support/everything/sdk/ipc/) to communicate between your application and the Everything service. 12 | This way, the dependencies and P/Invoke class are limited to functions of the Windows OS and the official .NET runtime. 13 | 14 | Everything service must be running on your machine. 15 | 16 | ## Usage 17 | The primary interface is: 18 | ```csharp 19 | SearchClient everything = new(); 20 | 21 | Result res = everything.Search(".txt"); 22 | // search all files/folders with '.txt' in their name (not just as extension) 23 | 24 | Console.WriteLine("Found {0} items:", res.NumItems); 25 | foreach (Result.Item item in res.Items) 26 | { 27 | Console.WriteLine(item.Name); 28 | } 29 | ``` 30 | 31 | There are multiple additional, optional parameters and overload variants of that function. 32 | The full signature reads: 33 | ```csharp 34 | Result Search( 35 | string query, 36 | SearchFlags flags = SearchFlags.None, 37 | uint maxResults = AllItems, 38 | uint offset = 0, 39 | BehaviorWhenBusy whenBusy = BehaviorWhenBusy.WaitOrError, 40 | uint timeoutMs = 0) 41 | ``` 42 | 43 | The program [`ExampleApp/Program.cs`](./ExampleApp/Program.cs) offers a simple *playground*, to try out the function. 44 | 45 | This interface does not provide the full feature set of Everything on purpose. 46 | The idea is to focus on the most importantly functionality only. 47 | More features might be added to the interface in the future, when needed. 48 | 49 | ### Results 50 | The `Result` type provides information about the number of found items, and the array containing the items: 51 | ```csharp 52 | class Result 53 | { 54 | [Flags] enum ItemFlags 55 | { 56 | None, // aka normal file 57 | Folder, 58 | Drive, 59 | Unknown // Something strange was reported by Everything 60 | } 61 | 62 | class Item 63 | { 64 | ItemFlags Flags; 65 | string Name; 66 | string Path; 67 | } 68 | 69 | UInt32 TotalItems; 70 | UInt32 NumItems; 71 | UInt32 Offset; 72 | Item[] Items; 73 | } 74 | ``` 75 | 76 | ### Search Flags 77 | Search flags allow to enable some optional features: 78 | ```csharp 79 | [Flags] enum SearchFlags 80 | { 81 | None, 82 | MatchCase, 83 | MatchWholeWord, // match whole word 84 | MatchPath, // include paths in search 85 | RegEx // enable regex 86 | } 87 | ``` 88 | 89 | For example, you can use a more precise RegEx to find all `.git` directories (and files): 90 | ```csharp 91 | Result res = everything.Search("^\\.git$", SearchClient.SearchFlags.RegEx); 92 | ``` 93 | Consult the [Everything documenntation](https://www.voidtools.com/support/everything/sdk/) for more info. 94 | 95 | 96 | ### Limit Results 97 | Keep in mind, that your whole result set is first collected in memory by Everything, and then copied into this library. 98 | This is by design of the Everything IPC API. 99 | 100 | So, if you expect a very large number of results, it might be a good idea to limit the number of files in each result set. 101 | Use `maxResults` and `offset` for that. 102 | For example: 103 | ```csharp 104 | Result res = search.Search("draft", SearchClient.SearchFlags.MatchWholeWord, 100, 0); 105 | Console.WriteLine("Found {0} items:", res.TotalItems); 106 | Console.WriteLine("Items {0}-{1}:", res.Offset, res.Offset + res.NumItems - 1); 107 | foreach (Result.Item item in res.Items) 108 | { 109 | Console.WriteLine("{0}", item.Name); 110 | } 111 | ``` 112 | This example fetches the first 100 result entries of the search for items with the word 'draft' in their name. 113 | 114 | `res.TotalItems` will be the total number of entries which were found and which could have been returned. 115 | 116 | `res.NumItems` on the other hand will have a maximum value of 100 here. 117 | 118 | If you want to receive the more results, just repeat the search with adjusted `offset`: 119 | ```csharp 120 | // ... 121 | res = search.Search("draft", SearchClient.SearchFlags.MatchWholeWord, 100, 100); 122 | /// ... 123 | res = search.Search("draft", SearchClient.SearchFlags.MatchWholeWord, 100, 200); 124 | /// ... 125 | ``` 126 | You will likely want to do that within a loop. 127 | 128 | ### Wait for Everything to be Ready 129 | One particularity of the Everything service is that it can only work on one search query at any time. 130 | If one query is running, and a new query is submitted, the first query will be aborted. 131 | 132 | This client library uses `BehaviorWhenBusy` to handle such cases. 133 | When the Everything service is busy working on one query, you can automatically wait until it's ready, to not interfere with queries from other applications. 134 | 135 | **A word of warning:** this mechanism is not 100% secure. 136 | There is still a chance of race conditions. 137 | But, since Everything is usually only used on the local machine, only by processes the current user triggered, the risk should be small. 138 | 139 | ```csharp 140 | enum BehaviorWhenBusy 141 | { 142 | WaitOrError, 143 | WaitOrContinue, 144 | Error, 145 | Continue 146 | } 147 | ``` 148 | 149 | You can specify a `timeoutMs` in milliseconds. 150 | When you use `WaitOrError` or `WaitOrContinue` the `Search` function will wait for at most `timeoutMs` milliseconds for the Everything service to become ready, and will the either throw an error `Exception` or will continue and submit it's search query. 151 | A `timeoutMs = 0` means that the function will wait indefinitely (not recommended). 152 | 153 | ## Everything Service Information 154 | This library requires Everything to be running on your machine. 155 | You can use these static functions to query some status information about the Everything process: 156 | ```csharp 157 | class SearchClient 158 | { 159 | // ... 160 | static bool IsEverythingAvailable(); 161 | 162 | static Version GetEverythingVersion(); 163 | 164 | static bool IsEverythingBusy(); 165 | // ... 166 | } 167 | ``` 168 | Your application should first check if Everything is generally `Available`, and should check if it's `Busy` before trying to submit a search query (to avoid unexpected wait times). 169 | 170 | In addition, you can use: 171 | ```csharp 172 | class ServiceControl 173 | { 174 | // ... 175 | static bool IsServiceInstalled() 176 | 177 | static bool IsServiceRunning() 178 | // ... 179 | } 180 | ``` 181 | to check if the system service of Everything is installed and available. 182 | 183 | ## How to Build 184 | There are several projects in this repository. 185 | All use Visual Studio solutions. 186 | I recommend Visual Studio 2022 Community Edition or newer. 187 | 188 | * [EverythingSearchClient.sln](EverythingSearchClient.sln) -- Main solution 189 | * EverythingSearchClient/[EverythingSearchClient.csproj](EverythingSearchClient/EverythingSearchClient.csproj) -- Main library project; 190 | This project also builds the nuget package of the library. 191 | * ExampleApp/[ExampleApp.csproj](ExampleApp/ExampleApp.csproj) -- Console application showing a simple way of how to use this library 192 | * TestProject/[TestProject.csproj](TestProject/TestProject.csproj) -- The MSTest project to run automated tests of the EverythingSearchClient library 193 | * TestNugetConsoleApp/[TestNugetConsoleApp.sln](TestNugetConsoleApp/TestNugetConsoleApp.sln) -- Secondary solution to run a simple smoke test console application testing the generated nuget package. 194 | See it's dedicated [TestNugetConsoleApp/README.md](TestNugetConsoleApp/README.md) for more details. 195 | 196 | The main library project does not have build dependencies other than the DotNet SDK. 197 | 198 | The test application have additional dependencies on the test runtime environment, which need to be restored using Nuget. 199 | This should run automatically during the build process, unless you deactivated this feature. 200 | 201 | ## Used By 202 | If you want to get your application into this list, I am happy to accept pull requests extending this README.md, or send me the info via e-mail. 203 | 204 | * [Checkouts Overview (https://github.com/sgrottel/checkouts-overview)](https://github.com/sgrottel/checkouts-overview) 205 | > Overview dashboard app for source code repository checkouts. 206 | * [FolderSummary in Tiny Tools Collection (https://github.com/sgrottel/tiny-tools-collection)](https://github.com/sgrottel/tiny-tools-collection) 207 | > Simple C# app to summarize the content of a folder (recursively) into a Json file. 208 | * 🚧 TODO: List my apps using the lib in alphabetic order 209 | 210 | ## Alternatives 211 | ### Everything SDK 212 | https://www.voidtools.com/support/everything/sdk/ 213 | 214 | The [official Everything SDK](https://www.voidtools.com/support/everything/sdk/) is written in native C. 215 | There are several code examples included in the provided archive, including C# examples based on using the native Everything SDK dlls via P/Invoke. 216 | 217 | ### EverythingNET 218 | https://github.com/ju2pom/EverythingNet 219 | 220 | > EverythingNet is a C# library that wraps the great library from voidtools named Everything. 221 | 222 | This managed library wraps around Everything's native C SDK dll. 223 | 224 | ### Everything (.NET Client) 225 | https://github.com/pardahlman/everything 226 | 227 | > .NET Core library for searching through Voidtool's Everything 228 | 229 | This managed library wraps around the x64 bit version of Everything's native C SDK dll. 230 | 231 | ## How to Contribute 232 | Contributions of any kind are welcome to this project! 233 | 234 | Feel free to fork the repository, make your change, and then create a pull request. 235 | There is no official style guide. 236 | Just try to stick to what you see. 237 | 238 | If you are unsure, feel free to create issue tickets with your questions. 239 | Please note, the issue tickets are meant to evolve and fix the library, not as a general communication channel. 240 | If you want to ask me something, feel free to reach out to me via e-mail. 241 | 242 | ## License 243 | This project is freely available under the terms of the [Apache License v.2.0](./LICENSE): 244 | 245 | > Copyright 2022-2024 SGrottel 246 | > 247 | > Licensed under the Apache License, Version 2.0 (the "License"); 248 | > you may not use this file except in compliance with the License. 249 | > You may obtain a copy of the License at 250 | > 251 | > http://www.apache.org/licenses/LICENSE-2.0 252 | > 253 | > Unless required by applicable law or agreed to in writing, software 254 | > distributed under the License is distributed on an "AS IS" BASIS, 255 | > WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 256 | > See the License for the specific language governing permissions and 257 | > limitations under the License. 258 | -------------------------------------------------------------------------------- /README_nuget.md: -------------------------------------------------------------------------------- 1 | # 🔎 EverythingSearchClient 2 | A .NET client library for [Voidtools' Everything](https://www.voidtools.com/) search engine, without the native Everything SDK dll. 3 | 4 | I wrote this library, because I wanted a managed .NET solution with a simple interface, which would not depend on the [native code SDK by Voidtools](https://www.voidtools.com/support/everything/sdk/). 5 | I wanted to have _**one AnyCpu Dll**_ to do the job. 6 | 7 | So, this library uses a message-only window and the [IPC mechanism](https://www.voidtools.com/support/everything/sdk/ipc/) to communicate between your application and the Everything service. 8 | This way, the dependencies and P/Invoke class are limited to functions of the Windows OS and the official .NET runtime. 9 | 10 | Everything service must be running on your machine. 11 | 12 | ## Usage 13 | The primary interface is: 14 | ```csharp 15 | SearchClient everything = new(); 16 | 17 | Result res = everything.Search(".txt"); 18 | // search all files/folders with '.txt' in their name (not just as extension) 19 | 20 | Console.WriteLine("Found {0} items:", res.NumItems); 21 | foreach (Result.Item item in res.Items) 22 | { 23 | Console.WriteLine(item.Name); 24 | } 25 | ``` 26 | 27 | There are multiple additional, optional parameters and overload variants of that function. 28 | 29 | ## License 30 | [This project](https://go.grottel.net/EverythingSearchClient) is freely available under the terms of the Apache License v.2.0. 31 | -------------------------------------------------------------------------------- /Reference/Everything-SDK-ipc/everything_ipc.h: -------------------------------------------------------------------------------- 1 | 2 | // Everything IPC 3 | 4 | #ifndef _EVERYTHING_IPC_H_ 5 | #define _EVERYTHING_IPC_H_ 6 | 7 | // C 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | #define EVERYTHING_WM_IPC (WM_USER) 13 | 14 | #define EVERYTHING_IPC_TARGET_MACHINE_X86 1 15 | #define EVERYTHING_IPC_TARGET_MACHINE_X64 2 16 | #define EVERYTHING_IPC_TARGET_MACHINE_ARM 3 17 | #define EVERYTHING_IPC_TARGET_MACHINE_ARM64 4 18 | 19 | // built in filters 20 | #define EVERYTHING_IPC_FILTER_EVERYTHING 0 21 | #define EVERYTHING_IPC_FILTER_AUDIO 1 22 | #define EVERYTHING_IPC_FILTER_COMPRESSED 2 23 | #define EVERYTHING_IPC_FILTER_DOCUMENT 3 24 | #define EVERYTHING_IPC_FILTER_EXECUTABLE 4 25 | #define EVERYTHING_IPC_FILTER_FOLDER 5 26 | #define EVERYTHING_IPC_FILTER_PICTURE 6 27 | #define EVERYTHING_IPC_FILTER_VIDEO 7 28 | #define EVERYTHING_IPC_FILTER_CUSTOM 8 29 | 30 | // EVERYTHING_WM_IPC (send to the Everything taskbar notification window) 31 | // the Everything taskbar notification window is always created when Everything is running. (even when the taskbar notification icon is hidden) 32 | // HWND everything_taskbar_notification_hwnd = FindWindow(EVERYTHING_IPC_WNDCLASS,0); 33 | // SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_*,lParam) 34 | 35 | // version format: major.minor.revision.build 36 | // example: 1.4.1.877 37 | #define EVERYTHING_IPC_GET_MAJOR_VERSION 0 // int major_version = (int)SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_GET_MAJOR_VERSION,0); 38 | #define EVERYTHING_IPC_GET_MINOR_VERSION 1 // int minor_version = (int)SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_GET_MINOR_VERSION,0); 39 | #define EVERYTHING_IPC_GET_REVISION 2 // int revision = (int)SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_GET_REVISION,0); 40 | #define EVERYTHING_IPC_GET_BUILD_NUMBER 3 // int build = (int)SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_GET_BUILD,0); 41 | #define EVERYTHING_IPC_EXIT 4 // returns 1 if the program closes. 42 | #define EVERYTHING_IPC_GET_TARGET_MACHINE 5 // int target_machine = (int)SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_GET_TARGET_MACHINE,0); returns 0 if not supported. returns a EVERYTHING_IPC_TARGET_MACHINE_* value. requires Everything 1.4.1 43 | 44 | // uninstall options 45 | #define EVERYTHING_IPC_DELETE_START_MENU_SHORTCUTS 100 // SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_DELETE_START_MENU_SHORTCUTS,0); 46 | #define EVERYTHING_IPC_DELETE_QUICK_LAUNCH_SHORTCUT 101 // SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_DELETE_QUICK_LAUNCH_SHORTCUT,0); 47 | #define EVERYTHING_IPC_DELETE_DESKTOP_SHORTCUT 102 // SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_DELETE_DESKTOP_SHORTCUT,0); 48 | #define EVERYTHING_IPC_DELETE_FOLDER_CONTEXT_MENU 103 // SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_DELETE_FOLDER_CONTEXT_MENU,0); 49 | #define EVERYTHING_IPC_DELETE_RUN_ON_SYSTEM_STARTUP 104 // SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_DELETE_RUN_ON_SYSTEM_STARTUP,0); 50 | #define EVERYTHING_IPC_DELETE_URL_PROTOCOL 105 // SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_DELETE_URL_PROTOCOL,0); 51 | 52 | // install options 53 | #define EVERYTHING_IPC_CREATE_START_MENU_SHORTCUTS 200 // SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_CREATE_START_MENU_SHORTCUTS,0); 54 | #define EVERYTHING_IPC_CREATE_QUICK_LAUNCH_SHORTCUT 201 // SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_CREATE_QUICK_LAUNCH_SHORTCUT,0); 55 | #define EVERYTHING_IPC_CREATE_DESKTOP_SHORTCUT 202 // SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_CREATE_DESKTOP_SHORTCUT,0); 56 | #define EVERYTHING_IPC_CREATE_FOLDER_CONTEXT_MENU 203 // SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_CREATE_FOLDER_CONTEXT_MENU,0); 57 | #define EVERYTHING_IPC_CREATE_RUN_ON_SYSTEM_STARTUP 204 // SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_CREATE_RUN_ON_SYSTEM_STARTUP,0); 58 | #define EVERYTHING_IPC_CREATE_URL_PROTOCOL 205 // SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_CREATE_URL_PROTOCOL,0); 59 | 60 | // get option status; 0 = no, 1 = yes, 2 = indeterminate (partially installed) 61 | #define EVERYTHING_IPC_IS_START_MENU_SHORTCUTS 300 // int ret = (int)SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_START_MENU_SHORTCUTS,0); 62 | #define EVERYTHING_IPC_IS_QUICK_LAUNCH_SHORTCUT 301 // int ret = (int)SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_QUICK_LAUNCH_SHORTCUT,0); 63 | #define EVERYTHING_IPC_IS_DESKTOP_SHORTCUT 302 // int ret = (int)SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_DESKTOP_SHORTCUT,0); 64 | #define EVERYTHING_IPC_IS_FOLDER_CONTEXT_MENU 303 // int ret = (int)SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_FOLDER_CONTEXT_MENU,0); 65 | #define EVERYTHING_IPC_IS_RUN_ON_SYSTEM_STARTUP 304 // int ret = (int)SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_RUN_ON_SYSTEM_STARTUP,0); 66 | #define EVERYTHING_IPC_IS_URL_PROTOCOL 305 // int ret = (int)SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_URL_PROTOCOL,0); 67 | #define EVERYTHING_IPC_IS_SERVICE 306 // int ret = (int)SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_SERVICE,0); 68 | 69 | // indexing 70 | #define EVERYTHING_IPC_IS_NTFS_DRIVE_INDEXED 400 // int is_indexed = (int)SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_NTFS_DRIVE_INDEXED,drive_index); drive_index: 0-25 = 0=A:, 1=B:, 2=C:... 71 | 72 | // requires Everything 1.4: 73 | #define EVERYTHING_IPC_IS_DB_LOADED 401 // int is_db_loaded = (int)SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_DB_LOADED,0); 74 | #define EVERYTHING_IPC_IS_DB_BUSY 402 // int is_db_busy = (int)SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_DB_BUSY,0); // db is busy, issueing another action will cancel the current one (if possible). 75 | #define EVERYTHING_IPC_IS_ADMIN 403 // int is_admin = (int)SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_ADMIN,0); 76 | #define EVERYTHING_IPC_IS_APPDATA 404 // int is_appdata = (int)SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_APPDATA,0); 77 | #define EVERYTHING_IPC_REBUILD_DB 405 // SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_REBUILD,0); // forces all indexes to be rescanned. 78 | #define EVERYTHING_IPC_UPDATE_ALL_FOLDER_INDEXES 406 // SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_UPDATE_ALL_FOLDER_INDEXES,0); // rescan all folder indexes. 79 | #define EVERYTHING_IPC_SAVE_DB 407 // SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_SAVE_DB,0); // save the db to disk. 80 | #define EVERYTHING_IPC_SAVE_RUN_HISTORY 408 // SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_SAVE_RUN_HISTORY,0); // save run history to disk. 81 | #define EVERYTHING_IPC_DELETE_RUN_HISTORY 409 // SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_DELETE_RUN_HISTORY,0); // deletes all run history from memory and disk. 82 | #define EVERYTHING_IPC_IS_FAST_SORT 410 // SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_FAST_SORT,EVERYTHING_IPC_SORT_*); // is the sort information indexed? 83 | #define EVERYTHING_IPC_IS_FILE_INFO_INDEXED 411 // SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_FILE_INFO_INDEXED,EVERYTHING_IPC_FILE_INFO_*); // is the file/folder info indexed? 84 | 85 | // Everything 1.5 86 | #define EVERYTHING_IPC_QUEUE_REBUILD_DB 412 // SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_QUEUE_REBUILD_DB,0); // forces all indexes to be rescanned when the db is ready. 87 | 88 | // send the following to an existing Everything search window (requires Everything 1.4.1) 89 | // SendMessage(FindWindow(EVERYTHING_IPC_SEARCH_CLIENT_WNDCLASS,0),EVERYTHING_WM_IPC,EVERYTHING_IPC_*,0); 90 | #define EVERYTHING_IPC_IS_MATCH_CASE 500 // int is_match_case = (int)SendMessage(FindWindow(EVERYTHING_IPC_SEARCH_CLIENT_WNDCLASS,0),EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_MATCH_CASE,0); 91 | #define EVERYTHING_IPC_IS_MATCH_WHOLE_WORD 501 // int is_match_whole_words = (int)SendMessage(FindWindow(EVERYTHING_IPC_SEARCH_CLIENT_WNDCLASS,0),EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_MATCH_WHOLE_WORD,0); 92 | #define EVERYTHING_IPC_IS_MATCH_PATH 502 // int is_match_path = (int)SendMessage(FindWindow(EVERYTHING_IPC_SEARCH_CLIENT_WNDCLASS,0),EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_MATCH_PATH,0); 93 | #define EVERYTHING_IPC_IS_MATCH_DIACRITICS 503 // int is_match_diacritics = (int)SendMessage(FindWindow(EVERYTHING_IPC_SEARCH_CLIENT_WNDCLASS,0),EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_MATCH_DIACRITICS,0); 94 | #define EVERYTHING_IPC_IS_REGEX 504 // int is_regex = (int)SendMessage(FindWindow(EVERYTHING_IPC_SEARCH_CLIENT_WNDCLASS,0),EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_REGEX,0); 95 | #define EVERYTHING_IPC_IS_FILTERS 505 // int is_filters = (int)SendMessage(FindWindow(EVERYTHING_IPC_SEARCH_CLIENT_WNDCLASS,0),EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_FILTERS,0); 96 | #define EVERYTHING_IPC_IS_PREVIEW 506 // int is_preview = (int)SendMessage(FindWindow(EVERYTHING_IPC_SEARCH_CLIENT_WNDCLASS,0),EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_PREVIEW,0); 97 | #define EVERYTHING_IPC_IS_STATUS_BAR 507 // int is_status_bar = (int)SendMessage(FindWindow(EVERYTHING_IPC_SEARCH_CLIENT_WNDCLASS,0),EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_STATUS_BAR,0); 98 | #define EVERYTHING_IPC_IS_DETAILS 508 // int is_details = (int)SendMessage(FindWindow(EVERYTHING_IPC_SEARCH_CLIENT_WNDCLASS,0),EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_DETAILS,0); 99 | #define EVERYTHING_IPC_GET_THUMBNAIL_SIZE 509 // int thumbnail_size = (int)SendMessage(FindWindow(EVERYTHING_IPC_SEARCH_CLIENT_WNDCLASS,0),EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_GET_THUMBNAIL_SIZE,0); 0 = details 100 | #define EVERYTHING_IPC_GET_SORT 510 // int sort = (int)SendMessage(FindWindow(EVERYTHING_IPC_SEARCH_CLIENT_WNDCLASS,0),EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_GET_SORT,0); sort can be one of EVERYTHING_IPC_SORT_* types. 101 | #define EVERYTHING_IPC_GET_ON_TOP 511 // int on_top = (int)SendMessage(FindWindow(EVERYTHING_IPC_SEARCH_CLIENT_WNDCLASS,0),EVERYTHING_WM_IPC,EVERYTHING_IPC_GET_ON_TOP,0); 0=never, 1=always, 2=while searching. 102 | #define EVERYTHING_IPC_GET_FILTER 512 // int filter = (int)SendMessage(FindWindow(EVERYTHING_IPC_SEARCH_CLIENT_WNDCLASS,0),EVERYTHING_WM_IPC,EVERYTHING_IPC_GET_FILTER,0); filter can be one of EVERYTHING_IPC_FILTER_* types. 103 | #define EVERYTHING_IPC_GET_FILTER_INDEX 513 // int filter_index = (int)SendMessage(FindWindow(EVERYTHING_IPC_SEARCH_CLIENT_WNDCLASS,0),EVERYTHING_WM_IPC,EVERYTHING_IPC_GET_FILTER_INDEX,0); 104 | 105 | // Everything 1.5 106 | #define EVERYTHING_IPC_IS_MATCH_PREFIX 514 // int is_match_prefix = (int)SendMessage(FindWindow(EVERYTHING_IPC_SEARCH_CLIENT_WNDCLASS,0),EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_MATCH_PREFIX,0); 107 | #define EVERYTHING_IPC_IS_MATCH_SUFFIX 515 // int is_match_suffix = (int)SendMessage(FindWindow(EVERYTHING_IPC_SEARCH_CLIENT_WNDCLASS,0),EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_MATCH_SUFFIX,0); 108 | #define EVERYTHING_IPC_IS_IGNORE_PUNCTUATION 516 // int is_ignore_punctuation = (int)SendMessage(FindWindow(EVERYTHING_IPC_SEARCH_CLIENT_WNDCLASS,0),EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_IGNORE_PUNCTUATION,0); 109 | #define EVERYTHING_IPC_IS_IGNORE_WHITESPACE 517 // int is_ignore_whitespace = (int)SendMessage(FindWindow(EVERYTHING_IPC_SEARCH_CLIENT_WNDCLASS,0),EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_IGNORE_WHITESPACE,0); 110 | #define EVERYTHING_IPC_IS_SEARCH_AS_YOU_TYPE 518 // int is_search_as_you_type = (int)SendMessage(FindWindow(EVERYTHING_IPC_SEARCH_CLIENT_WNDCLASS,0),EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_SEARCH_AS_YOU_TYPE,0); 111 | 112 | // command IDs to send to an Everything search window. 113 | // SendMessage(FindWindow(EVERYTHING_IPC_SEARCH_CLIENT_WNDCLASS,0),WM_COMMAND,MAKEWPARAM(EVERYTHING_IPC_ID_*,0),0); 114 | 115 | // main menus 116 | 117 | #define EVERYTHING_IPC_ID_FILE_MENU 10001 118 | #define EVERYTHING_IPC_ID_EDIT_MENU 10002 119 | #define EVERYTHING_IPC_ID_SEARCH_MENU 10003 120 | #define EVERYTHING_IPC_ID_TOOLS_MENU 10004 121 | #define EVERYTHING_IPC_ID_HELP_MENU 10005 122 | #define EVERYTHING_IPC_ID_TOOLBAR 10006 123 | #define EVERYTHING_IPC_ID_SEARCH_EDIT 10007 124 | #define EVERYTHING_IPC_ID_FILTER 10008 125 | #define EVERYTHING_IPC_ID_RESULTS_HEADER 10009 126 | #define EVERYTHING_IPC_ID_STATUS 10010 127 | #define EVERYTHING_IPC_ID_VIEW_ZOOM_MENU 10012 128 | #define EVERYTHING_IPC_ID_VIEW_MENU 10013 129 | #define EVERYTHING_IPC_ID_VIEW_WINDOW_SIZE_MENU 10019 130 | #define EVERYTHING_IPC_ID_RESULT_LIST 10020 131 | #define EVERYTHING_IPC_ID_BOOKMARKS_MENU 10021 132 | #define EVERYTHING_IPC_ID_VIEW_SORT_BY_MENU 10022 133 | #define EVERYTHING_IPC_ID_VIEW_GOTO_MENU 10024 134 | #define EVERYTHING_IPC_ID_VIEW_ONTOP_MENU 10025 135 | #define EVERYTHING_IPC_ID_PREVIEW 10026 136 | 137 | // TRAY 138 | #define EVERYTHING_IPC_ID_TRAY_NEW_SEARCH_WINDOW 40001 139 | #define EVERYTHING_IPC_ID_TRAY_CONNECT_TO_ETP_SERVER 40004 140 | #define EVERYTHING_IPC_ID_TRAY_OPTIONS 40005 141 | #define EVERYTHING_IPC_ID_TRAY_EXIT 40006 142 | #define EVERYTHING_IPC_ID_TRAY_SHOW_SEARCH_WINDOW 40007 143 | #define EVERYTHING_IPC_ID_TRAY_TOGGLE_SEARCH_WINDOW 40008 144 | 145 | // FILE 146 | #define EVERYTHING_IPC_ID_FILE_NEW_WINDOW 40010 147 | #define EVERYTHING_IPC_ID_FILE_CLOSE 40011 148 | #define EVERYTHING_IPC_ID_FILE_EXPORT 40012 149 | #define EVERYTHING_IPC_ID_FILE_EXIT 40013 150 | #define EVERYTHING_IPC_ID_FILE_OPEN_FILELIST 40014 151 | #define EVERYTHING_IPC_ID_FILE_CLOSE_FILELIST 40015 152 | 153 | // EDIT 154 | #define EVERYTHING_IPC_ID_EDIT_CUT 40020 155 | #define EVERYTHING_IPC_ID_EDIT_COPY 40021 156 | #define EVERYTHING_IPC_ID_EDIT_PASTE 40022 157 | #define EVERYTHING_IPC_ID_EDIT_SELECT_ALL 40023 158 | #define EVERYTHING_IPC_ID_EDIT_INVERT_SELECTION 40029 159 | 160 | // VIEW 161 | #define EVERYTHING_IPC_ID_VIEW_ZOOM_IN 40030 162 | #define EVERYTHING_IPC_ID_VIEW_ZOOM_OUT 40031 163 | #define EVERYTHING_IPC_ID_VIEW_ZOOM_RESET 40032 164 | #define EVERYTHING_IPC_ID_VIEW_TOGGLE_FULLSCREEN 40034 165 | #define EVERYTHING_IPC_ID_VIEW_AUTO_FIT 40044 166 | #define EVERYTHING_IPC_ID_VIEW_AUTO_SIZE_1 40045 167 | #define EVERYTHING_IPC_ID_VIEW_AUTO_SIZE_2 40046 168 | #define EVERYTHING_IPC_ID_VIEW_AUTO_SIZE_3 40047 169 | #define EVERYTHING_IPC_ID_VIEW_REFRESH 40036 170 | #define EVERYTHING_IPC_ID_VIEW_FILTERS 40035 171 | #define EVERYTHING_IPC_ID_VIEW_SORT_BY_ASCENDING 40037 172 | #define EVERYTHING_IPC_ID_VIEW_SORT_BY_DESCENDING 40038 173 | #define EVERYTHING_IPC_ID_VIEW_STATUS_BAR 40039 174 | #define EVERYTHING_IPC_ID_VIEW_GOTO_BACK 40040 175 | #define EVERYTHING_IPC_ID_VIEW_GOTO_FORWARD 40041 176 | #define EVERYTHING_IPC_ID_VIEW_ONTOP_NEVER 40042 177 | #define EVERYTHING_IPC_ID_VIEW_ONTOP_ALWAYS 40043 178 | #define EVERYTHING_IPC_ID_VIEW_ONTOP_WHILE_SEARCHING 40048 179 | #define EVERYTHING_IPC_ID_VIEW_GOTO_HOME 40049 180 | #define EVERYTHING_IPC_ID_VIEW_TOGGLE_LTR_RTL 40050 181 | #define EVERYTHING_IPC_ID_VIEW_DETAILS 40051 182 | #define EVERYTHING_IPC_ID_VIEW_MEDIUM_ICONS 40052 183 | #define EVERYTHING_IPC_ID_VIEW_LARGE_ICONS 40053 184 | #define EVERYTHING_IPC_ID_VIEW_EXTRA_LARGE_ICONS 40054 185 | #define EVERYTHING_IPC_ID_VIEW_PREVIEW 40055 186 | #define EVERYTHING_IPC_ID_VIEW_GOTO_SHOW_ALL_HISTORY 40056 187 | #define EVERYTHING_IPC_ID_VIEW_INCREASE_THUMBNAIL_SIZE 40057 188 | #define EVERYTHING_IPC_ID_VIEW_DECREASE_THUMBNAIL_SIZE 40058 189 | #define EVERYTHING_IPC_ID_VIEW_SHOW_FILTERS 40096 // Everything 1.4.1 190 | #define EVERYTHING_IPC_ID_VIEW_HIDE_FILTERS 40097 // Everything 1.4.1 191 | #define EVERYTHING_IPC_ID_VIEW_SHOW_PREVIEW 40098 // Everything 1.4.1 192 | #define EVERYTHING_IPC_ID_VIEW_HIDE_PREVIEW 40099 // Everything 1.4.1 193 | #define EVERYTHING_IPC_ID_VIEW_SHOW_STATUS_BAR 40100 // Everything 1.4.1 194 | #define EVERYTHING_IPC_ID_VIEW_HIDE_STATUS_BAR 40101 // Everything 1.4.1 195 | #define EVERYTHING_IPC_ID_VIEW_DETAILS_NO_TOGGLE 40102 // Everything 1.4.1 196 | #define EVERYTHING_IPC_ID_VIEW_MEDIUM_ICONS_NO_TOGGLE 40103 // Everything 1.4.1 197 | #define EVERYTHING_IPC_ID_VIEW_LARGE_ICONS_NO_TOGGLE 40104 // Everything 1.4.1 198 | #define EVERYTHING_IPC_ID_VIEW_EXTRA_LARGE_ICONS_NO_TOGGLE 40105 // Everything 1.4.1 199 | 200 | // SEARCH 201 | #define EVERYTHING_IPC_ID_SEARCH_TOGGLE_MATCH_CASE 40060 202 | #define EVERYTHING_IPC_ID_SEARCH_TOGGLE_MATCH_WHOLE_WORD 40061 203 | #define EVERYTHING_IPC_ID_SEARCH_TOGGLE_MATCH_PATH 40062 204 | #define EVERYTHING_IPC_ID_SEARCH_TOGGLE_REGEX 40063 205 | #define EVERYTHING_IPC_ID_SEARCH_TOGGLE_MATCH_DIACRITICS 40066 206 | #define EVERYTHING_IPC_ID_SEARCH_FILTER_ADD 40067 207 | #define EVERYTHING_IPC_ID_SEARCH_FILTER_ORGANIZE 40068 208 | #define EVERYTHING_IPC_ID_SEARCH_ADVANCED_SEARCH 40069 209 | #define EVERYTHING_IPC_ID_SEARCH_ENABLE_MATCH_CASE 40106 // Everything 1.4.1 210 | #define EVERYTHING_IPC_ID_SEARCH_ENABLE_MATCH_WHOLE_WORD 40107 // Everything 1.4.1 211 | #define EVERYTHING_IPC_ID_SEARCH_ENABLE_MATCH_PATH 40108 // Everything 1.4.1 212 | #define EVERYTHING_IPC_ID_SEARCH_ENABLE_REGEX 40109 // Everything 1.4.1 213 | #define EVERYTHING_IPC_ID_SEARCH_ENABLE_MATCH_DIACRITICS 40110 // Everything 1.4.1 214 | #define EVERYTHING_IPC_ID_SEARCH_DISABLE_MATCH_CASE 40111 // Everything 1.4.1 215 | #define EVERYTHING_IPC_ID_SEARCH_DISABLE_MATCH_WHOLE_WORD 40112 // Everything 1.4.1 216 | #define EVERYTHING_IPC_ID_SEARCH_DISABLE_MATCH_PATH 40113 // Everything 1.4.1 217 | #define EVERYTHING_IPC_ID_SEARCH_DISABLE_REGEX 40114 // Everything 1.4.1 218 | #define EVERYTHING_IPC_ID_SEARCH_DISABLE_MATCH_DIACRITICS 40115 // Everything 1.4.1 219 | #define EVERYTHING_IPC_ID_SEARCH_FILTER_EVERYTHING 40116 // Everything 1.4.1 220 | #define EVERYTHING_IPC_ID_SEARCH_FILTER_AUDIO 40117 // Everything 1.4.1 221 | #define EVERYTHING_IPC_ID_SEARCH_FILTER_COMPRESSED 40118 // Everything 1.4.1 222 | #define EVERYTHING_IPC_ID_SEARCH_FILTER_DOCUMENT 40119 // Everything 1.4.1 223 | #define EVERYTHING_IPC_ID_SEARCH_FILTER_EXECUTABLE 40120 // Everything 1.4.1 224 | #define EVERYTHING_IPC_ID_SEARCH_FILTER_FOLDER 40121 // Everything 1.4.1 225 | #define EVERYTHING_IPC_ID_SEARCH_FILTER_PICTURE 40122 // Everything 1.4.1 226 | #define EVERYTHING_IPC_ID_SEARCH_FILTER_VIDEO 40123 // Everything 1.4.1 227 | #define EVERYTHING_IPC_ID_SEARCH_FILTER_AUDIO_NO_TOGGLE 40124 // Everything 1.4.1 228 | #define EVERYTHING_IPC_ID_SEARCH_FILTER_COMPRESSED_NO_TOGGLE 40125 // Everything 1.4.1 229 | #define EVERYTHING_IPC_ID_SEARCH_FILTER_DOCUMENT_NO_TOGGLE 40126 // Everything 1.4.1 230 | #define EVERYTHING_IPC_ID_SEARCH_FILTER_EXECUTABLE_NO_TOGGLE 40127 // Everything 1.4.1 231 | #define EVERYTHING_IPC_ID_SEARCH_FILTER_FOLDER_NO_TOGGLE 40128 // Everything 1.4.1 232 | #define EVERYTHING_IPC_ID_SEARCH_FILTER_PICTURE_NO_TOGGLE 40129 // Everything 1.4.1 233 | #define EVERYTHING_IPC_ID_SEARCH_FILTER_VIDEO_NO_TOGGLE 40130 // Everything 1.4.1 234 | 235 | // TOOLS 236 | #define EVERYTHING_IPC_ID_TOOLS_CONNECT_TO_ETP_SERVER 40072 237 | #define EVERYTHING_IPC_ID_TOOLS_DISCONNECT_FROM_ETP_SERVER 40073 238 | #define EVERYTHING_IPC_ID_TOOLS_OPTIONS 40074 239 | #define EVERYTHING_IPC_ID_TOOLS_CONSOLE 40075 240 | #define EVERYTHING_IPC_ID_TOOLS_EDITOR 40076 241 | 242 | // HELP 243 | #define EVERYTHING_IPC_ID_HELP_VIEW_HELP_TOPICS 40080 244 | #define EVERYTHING_IPC_ID_HELP_OPEN_EVERYTHING_WEBSITE 40081 245 | #define EVERYTHING_IPC_ID_HELP_CHECK_FOR_UPDATES 40082 246 | #define EVERYTHING_IPC_ID_HELP_ABOUT_EVERYTHING 40083 247 | #define EVERYTHING_IPC_ID_HELP_SEARCH_SYNTAX 40084 248 | #define EVERYTHING_IPC_ID_HELP_COMMAND_LINE_OPTIONS 40085 249 | #define EVERYTHING_IPC_ID_HELP_REGEX_SYNTAX 40086 250 | #define EVERYTHING_IPC_ID_HELP_DONATE 40087 251 | 252 | // bookmarks 253 | #define EVERYTHING_IPC_ID_BOOKMARK_ADD 40090 254 | #define EVERYTHING_IPC_ID_BOOKMARK_ORGANIZE 40091 255 | #define EVERYTHING_IPC_ID_BOOKMARK_START 44000 256 | #define EVERYTHING_IPC_ID_BOOKMARK_END 45000 // exclusive 257 | 258 | #define EVERYTHING_IPC_ID_FILTER_START 45000 259 | #define EVERYTHING_IPC_ID_FILTER_END 46000 // exclusive 260 | 261 | #define EVERYTHING_IPC_ID_VIEW_GOTO_START 46000 262 | #define EVERYTHING_IPC_ID_VIEW_GOTO_END 47000 // exclusive 263 | 264 | // files 265 | #define EVERYTHING_IPC_ID_FILE_OPEN 41000 266 | #define EVERYTHING_IPC_ID_FILE_OPEN_NEW 41048 267 | #define EVERYTHING_IPC_ID_FILE_OPEN_WITH 41049 268 | #define EVERYTHING_IPC_ID_FILE_EDIT 41050 269 | #define EVERYTHING_IPC_ID_FILE_PLAY 41051 270 | #define EVERYTHING_IPC_ID_FILE_PRINT 41052 271 | #define EVERYTHING_IPC_ID_FILE_PREVIEW 41053 272 | #define EVERYTHING_IPC_ID_FILE_PRINT_TO 41054 273 | #define EVERYTHING_IPC_ID_FILE_RUN_AS 41055 274 | #define EVERYTHING_IPC_ID_FILE_OPEN_WITH_DEFAULT_VERB 41056 275 | #define EVERYTHING_IPC_ID_FILE_OPEN_AND_CLOSE 41057 276 | #define EVERYTHING_IPC_ID_FILE_EXPLORE_PATH 41002 277 | #define EVERYTHING_IPC_ID_FILE_OPEN_PATH 41003 278 | #define EVERYTHING_IPC_ID_FILE_DELETE 41004 279 | #define EVERYTHING_IPC_ID_FILE_PERMANENTLY_DELETE 41005 280 | #define EVERYTHING_IPC_ID_FILE_RENAME 41006 281 | #define EVERYTHING_IPC_ID_FILE_COPY_FULL_PATH_AND_NAME 41007 282 | #define EVERYTHING_IPC_ID_FILE_COPY_PATH 41008 283 | #define EVERYTHING_IPC_ID_FILE_PROPERTIES 41009 284 | #define EVERYTHING_IPC_ID_FILE_READ_EXTENDED_INFORMATION 41064 285 | #define EVERYTHING_IPC_ID_FILE_CREATE_SHORTCUT 41065 286 | #define EVERYTHING_IPC_ID_FILE_SET_RUN_COUNT 41068 287 | #define EVERYTHING_IPC_ID_FILE_COPY_NAME 41011 288 | #define EVERYTHING_IPC_ID_FILE_OPEN_AND_DO_NOT_CLOSE 41076 289 | 290 | // result list 291 | #define EVERYTHING_IPC_ID_RESULT_LIST_EXPLORE 41001 292 | #define EVERYTHING_IPC_ID_RESULT_LIST_FOCUS 41010 293 | #define EVERYTHING_IPC_ID_RESULT_LIST_AUTOFIT_COLUMNS 41012 294 | #define EVERYTHING_IPC_ID_RESULT_LIST_DOWN 41018 295 | #define EVERYTHING_IPC_ID_RESULT_LIST_UP 41019 296 | #define EVERYTHING_IPC_ID_RESULT_LIST_PAGE_UP 41020 297 | #define EVERYTHING_IPC_ID_RESULT_LIST_PAGE_DOWN 41021 298 | #define EVERYTHING_IPC_ID_RESULT_LIST_START 41022 299 | #define EVERYTHING_IPC_ID_RESULT_LIST_END 41023 300 | #define EVERYTHING_IPC_ID_RESULT_LIST_DOWN_EXTEND 41024 301 | #define EVERYTHING_IPC_ID_RESULT_LIST_UP_EXTEND 41025 302 | #define EVERYTHING_IPC_ID_RESULT_LIST_PAGE_UP_EXTEND 41026 303 | #define EVERYTHING_IPC_ID_RESULT_LIST_PAGE_DOWN_EXTEND 41027 304 | #define EVERYTHING_IPC_ID_RESULT_LIST_START_EXTEND 41028 305 | #define EVERYTHING_IPC_ID_RESULT_LIST_END_EXTEND 41029 306 | #define EVERYTHING_IPC_ID_RESULT_LIST_FOCUS_DOWN 41030 307 | #define EVERYTHING_IPC_ID_RESULT_LIST_FOCUS_UP 41031 308 | #define EVERYTHING_IPC_ID_RESULT_LIST_FOCUS_PAGE_UP 41032 309 | #define EVERYTHING_IPC_ID_RESULT_LIST_FOCUS_PAGE_DOWN 41033 310 | #define EVERYTHING_IPC_ID_RESULT_LIST_FOCUS_START 41034 311 | #define EVERYTHING_IPC_ID_RESULT_LIST_FOCUS_END 41035 312 | #define EVERYTHING_IPC_ID_RESULT_LIST_SCROLL_LEFT 41036 313 | #define EVERYTHING_IPC_ID_RESULT_LIST_SCROLL_RIGHT 41037 314 | #define EVERYTHING_IPC_ID_RESULT_LIST_SCROLL_PAGE_LEFT 41038 315 | #define EVERYTHING_IPC_ID_RESULT_LIST_SCROLL_PAGE_RIGHT 41039 316 | #define EVERYTHING_IPC_ID_RESULT_LIST_SELECT_FOCUS 41040 317 | #define EVERYTHING_IPC_ID_RESULT_LIST_TOGGLE_FOCUS_SELECTION 41041 318 | #define EVERYTHING_IPC_ID_RESULT_LIST_CONTEXT_MENU 41046 319 | #define EVERYTHING_IPC_ID_RESULT_LIST_FOCUS_DOWN_EXTEND 41058 320 | #define EVERYTHING_IPC_ID_RESULT_LIST_FOCUS_UP_EXTEND 41059 321 | #define EVERYTHING_IPC_ID_RESULT_LIST_FOCUS_PAGE_UP_EXTEND 41060 322 | #define EVERYTHING_IPC_ID_RESULT_LIST_FOCUS_PAGE_DOWN_EXTEND 41061 323 | #define EVERYTHING_IPC_ID_RESULT_LIST_FOCUS_START_EXTEND 41062 324 | #define EVERYTHING_IPC_ID_RESULT_LIST_FOCUS_END_EXTEND 41063 325 | #define EVERYTHING_IPC_ID_RESULT_LIST_AUTOFIT 41066 326 | #define EVERYTHING_IPC_ID_RESULT_LIST_COPY_CSV 41067 327 | #define EVERYTHING_IPC_ID_RESULT_LIST_LEFT_EXTEND 41070 328 | #define EVERYTHING_IPC_ID_RESULT_LIST_RIGHT_EXTEND 41071 329 | #define EVERYTHING_IPC_ID_RESULT_LIST_FOCUS_LEFT_EXTEND 41072 330 | #define EVERYTHING_IPC_ID_RESULT_LIST_FOCUS_RIGHT_EXTEND 41073 331 | #define EVERYTHING_IPC_ID_RESULT_LIST_FOCUS_MOST_RUN 41074 332 | #define EVERYTHING_IPC_ID_RESULT_LIST_FOCUS_LAST_RUN 41075 333 | #define EVERYTHING_IPC_ID_RESULT_LIST_LEFT 41079 // Everything 1.4.1 334 | #define EVERYTHING_IPC_ID_RESULT_LIST_RIGHT 41080 // Everything 1.4.1 335 | #define EVERYTHING_IPC_ID_RESULT_LIST_FOCUS_LEFT 41081 // Everything 1.4.1 336 | #define EVERYTHING_IPC_ID_RESULT_LIST_FOCUS_RIGHT 41082 // Everything 1.4.1 337 | #define EVERYTHING_IPC_ID_RESULT_LIST_SCROLL_LEFT_SCROLL_ONLY 41083 // Everything 1.4.1 338 | #define EVERYTHING_IPC_ID_RESULT_LIST_SCROLL_RIGHT_SCROLL_ONLY 41084 // Everything 1.4.1 339 | #define EVERYTHING_IPC_ID_RESULT_LIST_SCROLL_PAGE_LEFT_SCROLL_ONLY 41085 // Everything 1.4.1 340 | #define EVERYTHING_IPC_ID_RESULT_LIST_SCROLL_PAGE_RIGHT_SCROLL_ONLY 41086 // Everything 1.4.1 341 | 342 | #define EVERYTHING_IPC_ID_RESULT_LIST_SORT_BY_NAME 41300 343 | #define EVERYTHING_IPC_ID_RESULT_LIST_SORT_BY_PATH 41301 344 | #define EVERYTHING_IPC_ID_RESULT_LIST_SORT_BY_SIZE 41302 345 | #define EVERYTHING_IPC_ID_RESULT_LIST_SORT_BY_EXTENSION 41303 346 | #define EVERYTHING_IPC_ID_RESULT_LIST_SORT_BY_TYPE 41304 347 | #define EVERYTHING_IPC_ID_RESULT_LIST_SORT_BY_DATE_MODIFIED 41305 348 | #define EVERYTHING_IPC_ID_RESULT_LIST_SORT_BY_DATE_CREATED 41306 349 | #define EVERYTHING_IPC_ID_RESULT_LIST_SORT_BY_ATTRIBUTES 41307 350 | #define EVERYTHING_IPC_ID_RESULT_LIST_SORT_BY_FILE_LIST_FILENAME 41308 351 | #define EVERYTHING_IPC_ID_RESULT_LIST_SORT_BY_RUN_COUNT 41309 352 | #define EVERYTHING_IPC_ID_RESULT_LIST_SORT_BY_DATE_RECENTLY_CHANGED 41310 353 | #define EVERYTHING_IPC_ID_RESULT_LIST_SORT_BY_DATE_ACCESSED 41311 354 | #define EVERYTHING_IPC_ID_RESULT_LIST_SORT_BY_DATE_RUN 41312 355 | 356 | #define EVERYTHING_IPC_ID_RESULT_LIST_TOGGLE_NAME_COLUMN 41400 357 | #define EVERYTHING_IPC_ID_RESULT_LIST_TOGGLE_PATH_COLUMN 41401 358 | #define EVERYTHING_IPC_ID_RESULT_LIST_TOGGLE_SIZE_COLUMN 41402 359 | #define EVERYTHING_IPC_ID_RESULT_LIST_TOGGLE_EXTENSION_COLUMN 41403 360 | #define EVERYTHING_IPC_ID_RESULT_LIST_TOGGLE_TYPE_COLUMN 41404 361 | #define EVERYTHING_IPC_ID_RESULT_LIST_TOGGLE_DATE_MODIFIED_COLUMN 41405 362 | #define EVERYTHING_IPC_ID_RESULT_LIST_TOGGLE_DATE_CREATED_COLUMN 41406 363 | #define EVERYTHING_IPC_ID_RESULT_LIST_TOGGLE_ATTRIBUTES_COLUMN 41407 364 | #define EVERYTHING_IPC_ID_RESULT_LIST_TOGGLE_FILE_LIST_FILENAME_COLUMN 41408 365 | #define EVERYTHING_IPC_ID_RESULT_LIST_TOGGLE_RUN_COUNT_COLUMN 41409 366 | #define EVERYTHING_IPC_ID_RESULT_LIST_TOGGLE_DATE_RECENTLY_CHANGED_COLUMN 41410 367 | #define EVERYTHING_IPC_ID_RESULT_LIST_TOGGLE_DATE_ACCESSED_COLUMN 41411 368 | #define EVERYTHING_IPC_ID_RESULT_LIST_TOGGLE_DATE_RUN_COLUMN 41412 369 | 370 | #define EVERYTHING_IPC_ID_RESULT_LIST_SIZE_NAME_COLUMN_TO_FIT 41600 371 | #define EVERYTHING_IPC_ID_RESULT_LIST_SIZE_PATH_COLUMN_TO_FIT 41601 372 | #define EVERYTHING_IPC_ID_RESULT_LIST_SIZE_SIZE_COLUMN_TO_FIT 41602 373 | #define EVERYTHING_IPC_ID_RESULT_LIST_SIZE_EXTENSION_COLUMN_TO_FIT 41603 374 | #define EVERYTHING_IPC_ID_RESULT_LIST_SIZE_TYPE_COLUMN_TO_FIT 41604 375 | #define EVERYTHING_IPC_ID_RESULT_LIST_SIZE_DATE_MODIFIED_COLUMN_TO_FIT 41605 376 | #define EVERYTHING_IPC_ID_RESULT_LIST_SIZE_DATE_CREATED_COLUMN_TO_FIT 41606 377 | #define EVERYTHING_IPC_ID_RESULT_LIST_SIZE_ATTRIBUTES_COLUMN_TO_FIT 41607 378 | #define EVERYTHING_IPC_ID_RESULT_LIST_SIZE_FILE_LIST_FILENAME_COLUMN_TO_FIT 41608 379 | #define EVERYTHING_IPC_ID_RESULT_LIST_SIZE_RUN_COUNT_COLUMN_TO_FIT 41609 380 | #define EVERYTHING_IPC_ID_RESULT_LIST_SIZE_DATE_RECENTLY_CHANGED_COLUMN_TO_FIT 41610 381 | #define EVERYTHING_IPC_ID_RESULT_LIST_SIZE_DATE_ACCESSED_COLUMN_TO_FIT 41611 382 | #define EVERYTHING_IPC_ID_RESULT_LIST_SIZE_DATE_RUN_COLUMN_TO_FIT 41612 383 | 384 | #define EVERYTHING_IPC_ID_FILE_CUSTOM_VERB01 41500 385 | #define EVERYTHING_IPC_ID_FILE_CUSTOM_VERB02 41501 386 | #define EVERYTHING_IPC_ID_FILE_CUSTOM_VERB03 41502 387 | #define EVERYTHING_IPC_ID_FILE_CUSTOM_VERB04 41503 388 | #define EVERYTHING_IPC_ID_FILE_CUSTOM_VERB05 41504 389 | #define EVERYTHING_IPC_ID_FILE_CUSTOM_VERB06 41505 390 | #define EVERYTHING_IPC_ID_FILE_CUSTOM_VERB07 41506 391 | #define EVERYTHING_IPC_ID_FILE_CUSTOM_VERB08 41507 392 | #define EVERYTHING_IPC_ID_FILE_CUSTOM_VERB09 41508 393 | #define EVERYTHING_IPC_ID_FILE_CUSTOM_VERB10 41509 394 | #define EVERYTHING_IPC_ID_FILE_CUSTOM_VERB11 41510 395 | #define EVERYTHING_IPC_ID_FILE_CUSTOM_VERB12 41511 396 | 397 | // search 398 | #define EVERYTHING_IPC_ID_SEARCH_EDIT_FOCUS 42000 399 | #define EVERYTHING_IPC_ID_SEARCH_EDIT_WORD_DELETE_TO_START 42019 400 | #define EVERYTHING_IPC_ID_SEARCH_EDIT_AUTO_COMPLETE 42020 401 | #define EVERYTHING_IPC_ID_SEARCH_EDIT_SHOW_SEARCH_HISTORY 42021 402 | #define EVERYTHING_IPC_ID_SEARCH_EDIT_SHOW_ALL_SEARCH_HISTORY 42022 403 | 404 | #define EVERYTHING_IPC_ID_TRAY_EDITOR 41700 405 | #define EVERYTHING_IPC_ID_TRAY_OPEN_FILELIST 41701 406 | 407 | #define EVERYTHING_IPC_ID_INDEX_UPDATE_ALL_FOLDERS_NOW 41800 408 | #define EVERYTHING_IPC_ID_INDEX_FORCE_REBUILD 41801 409 | 410 | // find the everything IPC window 411 | #define EVERYTHING_IPC_WNDCLASSW L"EVERYTHING_TASKBAR_NOTIFICATION" 412 | #define EVERYTHING_IPC_WNDCLASSA "EVERYTHING_TASKBAR_NOTIFICATION" 413 | 414 | // an Everything search window 415 | #define EVERYTHING_IPC_SEARCH_CLIENT_WNDCLASSW L"EVERYTHING" 416 | #define EVERYTHING_IPC_SEARCH_CLIENT_WNDCLASSA "EVERYTHING" 417 | 418 | // this global window message is sent to all top level windows when everything starts. 419 | #define EVERYTHING_IPC_CREATEDW L"EVERYTHING_IPC_CREATED" 420 | #define EVERYTHING_IPC_CREATEDA "EVERYTHING_IPC_CREATED" 421 | 422 | // search flags for querys 423 | #define EVERYTHING_IPC_MATCHCASE 0x00000001 // match case 424 | #define EVERYTHING_IPC_MATCHWHOLEWORD 0x00000002 // match whole word 425 | #define EVERYTHING_IPC_MATCHPATH 0x00000004 // include paths in search 426 | #define EVERYTHING_IPC_REGEX 0x00000008 // enable regex 427 | #define EVERYTHING_IPC_MATCHACCENTS 0x00000010 // match diacritic marks 428 | #define EVERYTHING_IPC_MATCHDIACRITICS 0x00000010 // match diacritic marks 429 | #define EVERYTHING_IPC_MATCHPREFIX 0x00000020 // match prefix (Everything 1.5) 430 | #define EVERYTHING_IPC_MATCHSUFFIX 0x00000040 // match suffix (Everything 1.5) 431 | #define EVERYTHING_IPC_IGNOREPUNCTUATION 0x00000080 // ignore punctuation (Everything 1.5) 432 | #define EVERYTHING_IPC_IGNOREWHITESPACE 0x00000100 // ignore white-space (Everything 1.5) 433 | 434 | // item flags 435 | #define EVERYTHING_IPC_FOLDER 0x00000001 // The item is a folder. (it's a file if not set) 436 | #define EVERYTHING_IPC_DRIVE 0x00000002 // the file or folder is a drive/root. 437 | #define EVERYTHING_IPC_ROOT 0x00000002 // the file or folder is a root. 438 | 439 | typedef struct EVERYTHING_IPC_COMMAND_LINE 440 | { 441 | DWORD show_command; // MUST be one of the SW_* ShowWindow() commands 442 | 443 | // null terminated variable sized command line text in UTF-8. 444 | BYTE command_line_text[1]; 445 | 446 | }EVERYTHING_IPC_COMMAND_LINE; 447 | 448 | // the WM_COPYDATA message for a query. 449 | #define EVERYTHING_IPC_COPYDATA_COMMAND_LINE_UTF8 0 // Send a EVERYTHING_IPC_COMMAND_LINE structure. 450 | #define EVERYTHING_IPC_COPYDATAQUERYA 1 451 | #define EVERYTHING_IPC_COPYDATAQUERYW 2 452 | 453 | // all results 454 | #define EVERYTHING_IPC_ALLRESULTS 0xFFFFFFFF // all results 455 | 456 | // macro to get the filename of an item 457 | #define EVERYTHING_IPC_ITEMFILENAMEA(list,item) (CHAR *)((CHAR *)(list) + ((EVERYTHING_IPC_ITEMA *)(item))->filename_offset) 458 | #define EVERYTHING_IPC_ITEMFILENAMEW(list,item) (WCHAR *)((CHAR *)(list) + ((EVERYTHING_IPC_ITEMW *)(item))->filename_offset) 459 | 460 | // macro to get the path of an item 461 | #define EVERYTHING_IPC_ITEMPATHA(list,item) (CHAR *)((CHAR *)(list) + ((EVERYTHING_IPC_ITEMA *)(item))->path_offset) 462 | #define EVERYTHING_IPC_ITEMPATHW(list,item) (WCHAR *)((CHAR *)(list) + ((EVERYTHING_IPC_ITEMW *)(item))->path_offset) 463 | 464 | #pragma pack (push,1) 465 | 466 | // 467 | // Varible sized query struct sent to everything. 468 | // 469 | // sent in the form of a WM_COPYDATA message with EVERYTHING_IPC_COPYDATAQUERY as the 470 | // dwData member in the COPYDATASTRUCT struct. 471 | // set the lpData member of the COPYDATASTRUCT struct to point to your EVERYTHING_IPC_QUERY struct. 472 | // set the cbData member of the COPYDATASTRUCT struct to the size of the 473 | // EVERYTHING_IPC_QUERY struct minus the size of a TCHAR plus the length of the search string in bytes plus 474 | // one TCHAR for the null terminator. 475 | // 476 | // NOTE: to determine the size of this structure use 477 | // ASCII: sizeof(EVERYTHING_IPC_QUERYA) - sizeof(CHAR) + strlen(search_string)*sizeof(CHAR) + sizeof(CHAR) 478 | // UNICODE: sizeof(EVERYTHING_IPC_QUERYW) - sizeof(WCHAR) + wcslen(search_string)*sizeof(WCHAR) + sizeof(WCHAR) 479 | // 480 | // NOTE: Everything will only do one query per window. 481 | // Sending another query when a query has not completed 482 | // will cancel the old query and start the new one. 483 | // 484 | // Everything will send the results to the reply_hwnd in the form of a 485 | // WM_COPYDATA message with the dwData value you specify. 486 | // 487 | // Everything will return TRUE if successful. 488 | // returns FALSE if not supported. 489 | // 490 | // If you query with EVERYTHING_IPC_COPYDATAQUERYW, the results sent from Everything will be Unicode. 491 | // 492 | 493 | typedef struct EVERYTHING_IPC_QUERYW 494 | { 495 | // the window that will receive the new results. 496 | // only 32bits are required to store a window handle. (even on x64) 497 | DWORD reply_hwnd; 498 | 499 | // the value to set the dwData member in the COPYDATASTRUCT struct 500 | // sent by Everything when the query is complete. 501 | DWORD reply_copydata_message; 502 | 503 | // search flags (see EVERYTHING_IPC_MATCHCASE | EVERYTHING_IPC_MATCHWHOLEWORD | EVERYTHING_IPC_MATCHPATH) 504 | DWORD search_flags; 505 | 506 | // only return results after 'offset' results (0 to return from the first result) 507 | // useful for scrollable lists 508 | DWORD offset; 509 | 510 | // the number of results to return 511 | // zero to return no results 512 | // EVERYTHING_IPC_ALLRESULTS to return ALL results 513 | DWORD max_results; 514 | 515 | // null terminated string. variable lengthed search string buffer. 516 | WCHAR search_string[1]; 517 | 518 | }EVERYTHING_IPC_QUERYW; 519 | 520 | // ASCII version 521 | typedef struct EVERYTHING_IPC_QUERYA 522 | { 523 | // the window that will receive the new results. 524 | // only 32bits are required to store a window handle. (even on x64) 525 | DWORD reply_hwnd; 526 | 527 | // the value to set the dwData member in the COPYDATASTRUCT struct 528 | // sent by Everything when the query is complete. 529 | DWORD reply_copydata_message; 530 | 531 | // search flags (see EVERYTHING_IPC_MATCHCASE | EVERYTHING_IPC_MATCHWHOLEWORD | EVERYTHING_IPC_MATCHPATH) 532 | DWORD search_flags; 533 | 534 | // only return results after 'offset' results (0 to return from the first result) 535 | // useful for scrollable lists 536 | DWORD offset; 537 | 538 | // the number of results to return 539 | // zero to return no results 540 | // EVERYTHING_IPC_ALLRESULTS to return ALL results 541 | DWORD max_results; 542 | 543 | // null terminated string. variable lengthed search string buffer. 544 | CHAR search_string[1]; 545 | 546 | }EVERYTHING_IPC_QUERYA; 547 | 548 | // 549 | // Varible sized result list struct received from Everything. 550 | // 551 | // Sent in the form of a WM_COPYDATA message to the hwnd specifed in the 552 | // EVERYTHING_IPC_QUERY struct. 553 | // the dwData member of the COPYDATASTRUCT struct will match the sent 554 | // reply_copydata_message member in the EVERYTHING_IPC_QUERY struct. 555 | // 556 | // make a copy of the data before returning. 557 | // 558 | // return TRUE if you processed the WM_COPYDATA message. 559 | // 560 | 561 | typedef struct EVERYTHING_IPC_ITEMW 562 | { 563 | // item flags 564 | DWORD flags; 565 | 566 | // The offset of the filename from the beginning of the list structure. 567 | // (wchar_t *)((char *)everything_list + everythinglist->name_offset) 568 | DWORD filename_offset; 569 | 570 | // The offset of the filename from the beginning of the list structure. 571 | // (wchar_t *)((char *)everything_list + everythinglist->path_offset) 572 | DWORD path_offset; 573 | 574 | }EVERYTHING_IPC_ITEMW; 575 | 576 | typedef struct EVERYTHING_IPC_ITEMA 577 | { 578 | // item flags 579 | DWORD flags; 580 | 581 | // The offset of the filename from the beginning of the list structure. 582 | // (char *)((char *)everything_list + everythinglist->name_offset) 583 | DWORD filename_offset; 584 | 585 | // The offset of the filename from the beginning of the list structure. 586 | // (char *)((char *)everything_list + everythinglist->path_offset) 587 | DWORD path_offset; 588 | 589 | }EVERYTHING_IPC_ITEMA; 590 | 591 | typedef struct EVERYTHING_IPC_LISTW 592 | { 593 | // the total number of folders found. 594 | DWORD totfolders; 595 | 596 | // the total number of files found. 597 | DWORD totfiles; 598 | 599 | // totfolders + totfiles 600 | DWORD totitems; 601 | 602 | // the number of folders available. 603 | DWORD numfolders; 604 | 605 | // the number of files available. 606 | DWORD numfiles; 607 | 608 | // the number of items available. 609 | DWORD numitems; 610 | 611 | // index offset of the first result in the item list. 612 | DWORD offset; 613 | 614 | // variable lengthed item list. 615 | // use numitems to determine the actual number of items available. 616 | EVERYTHING_IPC_ITEMW items[1]; 617 | 618 | }EVERYTHING_IPC_LISTW; 619 | 620 | typedef struct EVERYTHING_IPC_LISTA 621 | { 622 | // the total number of folders found. 623 | DWORD totfolders; 624 | 625 | // the total number of files found. 626 | DWORD totfiles; 627 | 628 | // totfolders + totfiles 629 | DWORD totitems; 630 | 631 | // the number of folders available. 632 | DWORD numfolders; 633 | 634 | // the number of files available. 635 | DWORD numfiles; 636 | 637 | // the number of items available. 638 | DWORD numitems; 639 | 640 | // index offset of the first result in the item list. 641 | DWORD offset; 642 | 643 | // variable lengthed item list. 644 | // use numitems to determine the actual number of items available. 645 | EVERYTHING_IPC_ITEMA items[1]; 646 | 647 | }EVERYTHING_IPC_LISTA; 648 | 649 | #pragma pack (pop) 650 | 651 | #ifdef UNICODE 652 | #define EVERYTHING_IPC_COPYDATAQUERY EVERYTHING_IPC_COPYDATAQUERYW 653 | #define EVERYTHING_IPC_ITEMFILENAME EVERYTHING_IPC_ITEMFILENAMEW 654 | #define EVERYTHING_IPC_ITEMPATH EVERYTHING_IPC_ITEMPATHW 655 | #define EVERYTHING_IPC_QUERY EVERYTHING_IPC_QUERYW 656 | #define EVERYTHING_IPC_ITEM EVERYTHING_IPC_ITEMW 657 | #define EVERYTHING_IPC_LIST EVERYTHING_IPC_LISTW 658 | #define EVERYTHING_IPC_WNDCLASS EVERYTHING_IPC_WNDCLASSW 659 | #define EVERYTHING_IPC_SEARCH_CLIENT_WNDCLASS EVERYTHING_IPC_SEARCH_CLIENT_WNDCLASSW 660 | #define EVERYTHING_IPC_CREATED EVERYTHING_IPC_CREATEDW 661 | #else 662 | #define EVERYTHING_IPC_COPYDATAQUERY EVERYTHING_IPC_COPYDATAQUERYA 663 | #define EVERYTHING_IPC_ITEMFILENAME EVERYTHING_IPC_ITEMFILENAMEA 664 | #define EVERYTHING_IPC_ITEMPATH EVERYTHING_IPC_ITEMPATHA 665 | #define EVERYTHING_IPC_QUERY EVERYTHING_IPC_QUERYA 666 | #define EVERYTHING_IPC_ITEM EVERYTHING_IPC_ITEMA 667 | #define EVERYTHING_IPC_LIST EVERYTHING_IPC_LISTA 668 | #define EVERYTHING_IPC_WNDCLASS EVERYTHING_IPC_WNDCLASSA 669 | #define EVERYTHING_IPC_SEARCH_CLIENT_WNDCLASS EVERYTHING_IPC_SEARCH_CLIENT_WNDCLASSA 670 | #define EVERYTHING_IPC_CREATED EVERYTHING_IPC_CREATEDA 671 | #endif 672 | 673 | // the WM_COPYDATA message for a query. 674 | // requires Everything 1.4.1 675 | #define EVERYTHING_IPC_COPYDATA_QUERY2A 17 676 | #define EVERYTHING_IPC_COPYDATA_QUERY2W 18 677 | 678 | #define EVERYTHING_IPC_SORT_NAME_ASCENDING 1 679 | #define EVERYTHING_IPC_SORT_NAME_DESCENDING 2 680 | #define EVERYTHING_IPC_SORT_PATH_ASCENDING 3 681 | #define EVERYTHING_IPC_SORT_PATH_DESCENDING 4 682 | #define EVERYTHING_IPC_SORT_SIZE_ASCENDING 5 683 | #define EVERYTHING_IPC_SORT_SIZE_DESCENDING 6 684 | #define EVERYTHING_IPC_SORT_EXTENSION_ASCENDING 7 685 | #define EVERYTHING_IPC_SORT_EXTENSION_DESCENDING 8 686 | #define EVERYTHING_IPC_SORT_TYPE_NAME_ASCENDING 9 687 | #define EVERYTHING_IPC_SORT_TYPE_NAME_DESCENDING 10 688 | #define EVERYTHING_IPC_SORT_DATE_CREATED_ASCENDING 11 689 | #define EVERYTHING_IPC_SORT_DATE_CREATED_DESCENDING 12 690 | #define EVERYTHING_IPC_SORT_DATE_MODIFIED_ASCENDING 13 691 | #define EVERYTHING_IPC_SORT_DATE_MODIFIED_DESCENDING 14 692 | #define EVERYTHING_IPC_SORT_ATTRIBUTES_ASCENDING 15 693 | #define EVERYTHING_IPC_SORT_ATTRIBUTES_DESCENDING 16 694 | #define EVERYTHING_IPC_SORT_FILE_LIST_FILENAME_ASCENDING 17 695 | #define EVERYTHING_IPC_SORT_FILE_LIST_FILENAME_DESCENDING 18 696 | #define EVERYTHING_IPC_SORT_RUN_COUNT_ASCENDING 19 697 | #define EVERYTHING_IPC_SORT_RUN_COUNT_DESCENDING 20 698 | #define EVERYTHING_IPC_SORT_DATE_RECENTLY_CHANGED_ASCENDING 21 699 | #define EVERYTHING_IPC_SORT_DATE_RECENTLY_CHANGED_DESCENDING 22 700 | #define EVERYTHING_IPC_SORT_DATE_ACCESSED_ASCENDING 23 701 | #define EVERYTHING_IPC_SORT_DATE_ACCESSED_DESCENDING 24 702 | #define EVERYTHING_IPC_SORT_DATE_RUN_ASCENDING 25 703 | #define EVERYTHING_IPC_SORT_DATE_RUN_DESCENDING 26 704 | 705 | #define EVERYTHING_IPC_QUERY2_REQUEST_NAME 0x00000001 706 | #define EVERYTHING_IPC_QUERY2_REQUEST_PATH 0x00000002 707 | #define EVERYTHING_IPC_QUERY2_REQUEST_FULL_PATH_AND_NAME 0x00000004 708 | #define EVERYTHING_IPC_QUERY2_REQUEST_EXTENSION 0x00000008 709 | #define EVERYTHING_IPC_QUERY2_REQUEST_SIZE 0x00000010 710 | #define EVERYTHING_IPC_QUERY2_REQUEST_DATE_CREATED 0x00000020 711 | #define EVERYTHING_IPC_QUERY2_REQUEST_DATE_MODIFIED 0x00000040 712 | #define EVERYTHING_IPC_QUERY2_REQUEST_DATE_ACCESSED 0x00000080 713 | #define EVERYTHING_IPC_QUERY2_REQUEST_ATTRIBUTES 0x00000100 714 | #define EVERYTHING_IPC_QUERY2_REQUEST_FILE_LIST_FILE_NAME 0x00000200 715 | #define EVERYTHING_IPC_QUERY2_REQUEST_RUN_COUNT 0x00000400 716 | #define EVERYTHING_IPC_QUERY2_REQUEST_DATE_RUN 0x00000800 717 | #define EVERYTHING_IPC_QUERY2_REQUEST_DATE_RECENTLY_CHANGED 0x00001000 718 | #define EVERYTHING_IPC_QUERY2_REQUEST_HIGHLIGHTED_NAME 0x00002000 719 | #define EVERYTHING_IPC_QUERY2_REQUEST_HIGHLIGHTED_PATH 0x00004000 720 | #define EVERYTHING_IPC_QUERY2_REQUEST_HIGHLIGHTED_FULL_PATH_AND_NAME 0x00008000 721 | 722 | #define EVERYTHING_IPC_FILE_INFO_FILE_SIZE 1 723 | #define EVERYTHING_IPC_FILE_INFO_FOLDER_SIZE 2 724 | #define EVERYTHING_IPC_FILE_INFO_DATE_CREATED 3 725 | #define EVERYTHING_IPC_FILE_INFO_DATE_MODIFIED 4 726 | #define EVERYTHING_IPC_FILE_INFO_DATE_ACCESSED 5 727 | #define EVERYTHING_IPC_FILE_INFO_ATTRIBUTES 6 728 | 729 | #pragma pack (push,1) 730 | 731 | // 732 | // Varible sized query struct sent to everything. 733 | // 734 | // sent in the form of a WM_COPYDATA message with EVERYTHING_IPC_COPYDATA_QUERY2 as the 735 | // dwData member in the COPYDATASTRUCT struct. 736 | // set the lpData member of the COPYDATASTRUCT struct to point to your EVERYTHING_IPC_QUERY struct. 737 | // set the cbData member of the COPYDATASTRUCT struct to the size of the 738 | // EVERYTHING_IPC_QUERY struct minus the size of a TCHAR plus the length of the search string in bytes plus 739 | // one TCHAR for the null terminator. 740 | // 741 | // NOTE: Everything will only do one query per window. 742 | // Sending another query when a query has not completed 743 | // will cancel the old query and start the new one. 744 | // 745 | // Everything will send the results to the reply_hwnd in the form of a 746 | // WM_COPYDATA message with the dwData value you specify. 747 | // 748 | // Everything will return TRUE if successful. 749 | // returns FALSE if not supported. 750 | // 751 | // If you query with EVERYTHING_IPC_COPYDATA_QUERYW, the results sent from Everything will be Unicode. 752 | // 753 | 754 | // ASCII version 755 | typedef struct EVERYTHING_IPC_QUERY2 756 | { 757 | // the window that will receive the new results. 758 | // only 32bits are required to store a window handle. (even on x64) 759 | DWORD reply_hwnd; 760 | 761 | // the value to set the dwData member in the COPYDATASTRUCT struct 762 | // sent by Everything when the query is complete. 763 | DWORD reply_copydata_message; 764 | 765 | // search flags (see EVERYTHING_IPC_MATCHCASE | EVERYTHING_IPC_MATCHWHOLEWORD | EVERYTHING_IPC_MATCHPATH) 766 | DWORD search_flags; 767 | 768 | // only return results after 'offset' results (0 to return from the first result) 769 | // useful for scrollable lists 770 | DWORD offset; 771 | 772 | // the number of results to return 773 | // zero to return no results 774 | // EVERYTHING_IPC_ALLRESULTS to return ALL results 775 | DWORD max_results; 776 | 777 | // request types. 778 | // one or more of EVERYTHING_IPC_QUERY2_REQUEST_* types. 779 | DWORD request_flags; 780 | 781 | // sort type, set to one of EVERYTHING_IPC_SORT_* types. 782 | // set to EVERYTHING_IPC_SORT_NAME_ASCENDING for the best performance (there will never be a performance hit when sorting by name ascending). 783 | // Other sorts will also be instant if the corresponding fast sort is enabled from Tools -> Options -> Indexes. 784 | DWORD sort_type; 785 | 786 | // followed by null terminated search. 787 | // TCHAR search_string[1]; 788 | 789 | }EVERYTHING_IPC_QUERY2; 790 | 791 | typedef struct EVERYTHING_IPC_ITEM2 792 | { 793 | // item flags one of (EVERYTHING_IPC_FOLDER|EVERYTHING_IPC_DRIVE|EVERYTHING_IPC_ROOT) 794 | DWORD flags; 795 | 796 | // offset from the start of the EVERYTHING_IPC_LIST2 struct to the data content 797 | DWORD data_offset; 798 | 799 | // data found at data_offset 800 | // if EVERYTHING_IPC_QUERY2_REQUEST_NAME was set in request_flags, DWORD name_length in characters (excluding the null terminator); followed by null terminated text. 801 | // if EVERYTHING_IPC_QUERY2_REQUEST_PATH was set in request_flags, DWORD name_length in characters (excluding the null terminator); followed by null terminated text. 802 | // if EVERYTHING_IPC_QUERY2_REQUEST_FULL_PATH_AND_NAME was set in request_flags, DWORD name_length (excluding the null terminator); followed by null terminated text. 803 | // if EVERYTHING_IPC_QUERY2_REQUEST_SIZE was set in request_flags, LARGE_INTERGER size; 804 | // if EVERYTHING_IPC_QUERY2_REQUEST_EXTENSION was set in request_flags, DWORD name_length in characters (excluding the null terminator); followed by null terminated text; 805 | // if EVERYTHING_IPC_QUERY2_REQUEST_TYPE_NAME was set in request_flags, DWORD name_length in characters (excluding the null terminator); followed by null terminated text; 806 | // if EVERYTHING_IPC_QUERY2_REQUEST_DATE_CREATED was set in request_flags, FILETIME date; 807 | // if EVERYTHING_IPC_QUERY2_REQUEST_DATE_MODIFIED was set in request_flags, FILETIME date; 808 | // if EVERYTHING_IPC_QUERY2_REQUEST_DATE_ACCESSED was set in request_flags, FILETIME date; 809 | // if EVERYTHING_IPC_QUERY2_REQUEST_ATTRIBUTES was set in request_flags, DWORD attributes; 810 | // if EVERYTHING_IPC_QUERY2_REQUEST_FILELIST_FILENAME was set in request_flags, DWORD name_length in characters (excluding the null terminator); followed by null terminated text; 811 | // if EVERYTHING_IPC_QUERY2_REQUEST_RUN_COUNT was set in request_flags, DWORD run_count; 812 | // if EVERYTHING_IPC_QUERY2_REQUEST_DATE_RUN was set in request_flags, FILETIME date; 813 | // if EVERYTHING_IPC_QUERY2_REQUEST_DATE_RECENTLY_CHANGED was set in request_flags, FILETIME date; 814 | // if EVERYTHING_IPC_QUERY2_REQUEST_HIGHLIGHTED_NAME was set in request_flags, DWORD name_length in characters (excluding the null terminator); followed by null terminated text; ** = *, *text* = highlighted text 815 | // if EVERYTHING_IPC_QUERY2_REQUEST_HIGHLIGHTED_PATH was set in request_flags, DWORD name_length in characters (excluding the null terminator); followed by null terminated text; ** = *, *text* = highlighted text 816 | // if EVERYTHING_IPC_QUERY2_REQUEST_HIGHLIGHTED_FULL_PATH_AND_NAME was set in request_flags, DWORD name_length in characters (excluding the null terminator); followed by null terminated text; ** = *, *text* = highlighted text 817 | 818 | }EVERYTHING_IPC_ITEM2; 819 | 820 | typedef struct EVERYTHING_IPC_LIST2 821 | { 822 | // number of items found. 823 | DWORD totitems; 824 | 825 | // the number of items available. 826 | DWORD numitems; 827 | 828 | // index offset of the first result in the item list. 829 | DWORD offset; 830 | 831 | // valid request types. 832 | DWORD request_flags; 833 | 834 | // this sort type. 835 | // one of EVERYTHING_IPC_SORT_* types. 836 | // maybe different to requested sort type. 837 | DWORD sort_type; 838 | 839 | // items follow. 840 | // EVERYTHING_IPC_ITEM2 items[numitems] 841 | 842 | // item data follows. 843 | 844 | }EVERYTHING_IPC_LIST2; 845 | 846 | #pragma pack (pop) 847 | 848 | // Get the Run Count for a file, by filename. 849 | // COPYDATASTRUCT cds; 850 | // cds.dwData = EVERYTHING_IPC_COPYDATA_GET_RUN_COUNTA; 851 | // cds.lpData = TEXT("C:\\folder\\file.txt"); 852 | // cds.cbData = size in bytes of cds.lpData including null terminator. 853 | // SendMessage(everything_taskbar_notification_hwnd,WM_COPYDATA,(WPARAM)(HWND)notify_hwnd,(LPARAM)(COPYDATASTRUCT *)&cds); 854 | 855 | #define EVERYTHING_IPC_COPYDATA_GET_RUN_COUNTA 19 856 | #define EVERYTHING_IPC_COPYDATA_GET_RUN_COUNTW 20 857 | 858 | #pragma pack (push,1) 859 | 860 | typedef struct EVERYTHING_IPC_RUN_HISTORY 861 | { 862 | DWORD run_count; 863 | 864 | // null terminated ansi/wchar filename follows. 865 | // TCHAR filename[]; 866 | 867 | }EVERYTHING_IPC_RUN_HISTORY; 868 | 869 | #pragma pack (pop) 870 | 871 | // Set the Run Count by one for a file, by filename. 872 | // COPYDATASTRUCT cds; 873 | // cds.dwData = EVERYTHING_IPC_COPYDATA_GET_RUN_COUNTA; 874 | // cds.lpData = (EVERYTHING_IPC_RUN_HISTORY *)run_history; 875 | // cds.cbData = size in bytes of cds.lpData including null terminator. 876 | // SendMessage(everything_taskbar_notification_hwnd,WM_COPYDATA,(WPARAM)(HWND)notify_hwnd,(LPARAM)(COPYDATASTRUCT *)&cds); 877 | 878 | #define EVERYTHING_IPC_COPYDATA_SET_RUN_COUNTA 21 879 | #define EVERYTHING_IPC_COPYDATA_SET_RUN_COUNTW 22 880 | 881 | // Increment the Run Count by one for a file, by filename. 882 | // COPYDATASTRUCT cds; 883 | // cds.dwData = EVERYTHING_IPC_COPYDATA_GET_RUN_COUNTA; 884 | // cds.lpData = TEXT("C:\\folder\\file.txt"); 885 | // cds.cbData = size in bytes of cds.lpData including null terminator. 886 | // SendMessage(everything_taskbar_notification_hwnd,WM_COPYDATA,(WPARAM)(HWND)notify_hwnd,(LPARAM)(COPYDATASTRUCT *)&cds); 887 | 888 | #define EVERYTHING_IPC_COPYDATA_INC_RUN_COUNTA 23 889 | #define EVERYTHING_IPC_COPYDATA_INC_RUN_COUNTW 24 890 | 891 | #ifdef UNICODE 892 | #define EVERYTHING_IPC_COPYDATA_QUERY2 EVERYTHING_IPC_COPYDATA_QUERY2W 893 | #else 894 | #define EVERYTHING_IPC_COPYDATA_QUERY2 EVERYTHING_IPC_COPYDATA_QUERY2A 895 | #endif 896 | 897 | // end extern C 898 | #ifdef __cplusplus 899 | } 900 | #endif 901 | 902 | #endif // _EVERYTHING_H_ 903 | 904 | -------------------------------------------------------------------------------- /Reference/EverythingDemo/EverythingDemo.cpp: -------------------------------------------------------------------------------- 1 | // EverythingDemo.cpp : This file contains the 'main' function. Program execution begins and ends there. 2 | // 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define EVERYTHING_IPC_WNDCLASSW L"EVERYTHING_TASKBAR_NOTIFICATION" 12 | 13 | #define EVERYTHING_IPC_ALLRESULTS 0xFFFFFFFF // all results 14 | #define EVERYTHING_IPC_COPYDATAQUERYW 2 15 | 16 | #define EVERYTHING_IPC_COPYDATA_QUERY2W 18 17 | 18 | #define EVERYTHING_IPC_MATCHCASE 0x00000001 // match case 19 | #define EVERYTHING_IPC_MATCHWHOLEWORD 0x00000002 // match whole word 20 | #define EVERYTHING_IPC_MATCHPATH 0x00000004 // include paths in search 21 | #define EVERYTHING_IPC_REGEX 0x00000008 // enable regex 22 | 23 | #define EVERYTHING_IPC_FOLDER 0x00000001 // The item is a folder. (it's a file if not set) 24 | #define EVERYTHING_IPC_DRIVE 0x00000002 // the file or folder is a drive/root. 25 | 26 | #define EVERYTHING_WM_IPC (WM_USER) 27 | 28 | #define EVERYTHING_IPC_GET_MAJOR_VERSION 0 // int major_version = (int)SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_GET_MAJOR_VERSION,0); 29 | #define EVERYTHING_IPC_GET_MINOR_VERSION 1 // int minor_version = (int)SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_GET_MINOR_VERSION,0); 30 | #define EVERYTHING_IPC_GET_REVISION 2 // int revision = (int)SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_GET_REVISION,0); 31 | #define EVERYTHING_IPC_GET_BUILD_NUMBER 3 // int build = (int)SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_GET_BUILD,0); 32 | 33 | #define EVERYTHING_IPC_IS_DB_BUSY 402 // int is_db_busy = (int)SendMessage(everything_taskbar_notification_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_DB_BUSY,0); // db is busy, issueing another action will cancel the current one (if possible). 34 | 35 | typedef struct EVERYTHING_IPC_QUERYW 36 | { 37 | // the window that will receive the new results. 38 | // only 32bits are required to store a window handle. (even on x64) 39 | DWORD reply_hwnd; 40 | 41 | // the value to set the dwData member in the COPYDATASTRUCT struct 42 | // sent by Everything when the query is complete. 43 | DWORD reply_copydata_message; 44 | 45 | // search flags (see EVERYTHING_IPC_MATCHCASE | EVERYTHING_IPC_MATCHWHOLEWORD | EVERYTHING_IPC_MATCHPATH) 46 | DWORD search_flags; 47 | 48 | // only return results after 'offset' results (0 to return from the first result) 49 | // useful for scrollable lists 50 | DWORD offset; 51 | 52 | // the number of results to return 53 | // zero to return no results 54 | // EVERYTHING_IPC_ALLRESULTS to return ALL results 55 | DWORD max_results; 56 | 57 | // null terminated string. variable lengthed search string buffer. 58 | WCHAR search_string[1]; 59 | 60 | } EVERYTHING_IPC_QUERYW; 61 | 62 | #define MY_DEMO_CLASS_NAME L"MyDemoWindowClassName" 63 | 64 | #define MY_REQUEST_ID 43 65 | #define MY_REQUEST_ID2 51 66 | 67 | typedef struct EVERYTHING_IPC_ITEMW 68 | { 69 | // item flags 70 | DWORD flags; 71 | 72 | // The offset of the filename from the beginning of the list structure. 73 | // (wchar_t *)((char *)everything_list + everythinglist->name_offset) 74 | DWORD filename_offset; 75 | 76 | // The offset of the filename from the beginning of the list structure. 77 | // (wchar_t *)((char *)everything_list + everythinglist->path_offset) 78 | DWORD path_offset; 79 | 80 | } EVERYTHING_IPC_ITEMW; 81 | 82 | typedef struct EVERYTHING_IPC_LISTW 83 | { 84 | // the total number of folders found. 85 | DWORD totfolders; 86 | 87 | // the total number of files found. 88 | DWORD totfiles; 89 | 90 | // totfolders + totfiles 91 | DWORD totitems; 92 | 93 | // the number of folders available. 94 | DWORD numfolders; 95 | 96 | // the number of files available. 97 | DWORD numfiles; 98 | 99 | // the number of items available. 100 | DWORD numitems; 101 | 102 | // index offset of the first result in the item list. 103 | DWORD offset; 104 | 105 | // variable lengthed item list. 106 | // use numitems to determine the actual number of items available. 107 | EVERYTHING_IPC_ITEMW items[1]; 108 | 109 | } EVERYTHING_IPC_LISTW; 110 | 111 | 112 | 113 | // ASCII version 114 | typedef struct EVERYTHING_IPC_QUERY2 115 | { 116 | // the window that will receive the new results. 117 | // only 32bits are required to store a window handle. (even on x64) 118 | DWORD reply_hwnd; 119 | 120 | // the value to set the dwData member in the COPYDATASTRUCT struct 121 | // sent by Everything when the query is complete. 122 | DWORD reply_copydata_message; 123 | 124 | // search flags (see EVERYTHING_IPC_MATCHCASE | EVERYTHING_IPC_MATCHWHOLEWORD | EVERYTHING_IPC_MATCHPATH) 125 | DWORD search_flags; 126 | 127 | // only return results after 'offset' results (0 to return from the first result) 128 | // useful for scrollable lists 129 | DWORD offset; 130 | 131 | // the number of results to return 132 | // zero to return no results 133 | // EVERYTHING_IPC_ALLRESULTS to return ALL results 134 | DWORD max_results; 135 | 136 | // request types. 137 | // one or more of EVERYTHING_IPC_QUERY2_REQUEST_* types. 138 | DWORD request_flags; 139 | 140 | // sort type, set to one of EVERYTHING_IPC_SORT_* types. 141 | // set to EVERYTHING_IPC_SORT_NAME_ASCENDING for the best performance (there will never be a performance hit when sorting by name ascending). 142 | // Other sorts will also be instant if the corresponding fast sort is enabled from Tools -> Options -> Indexes. 143 | DWORD sort_type; 144 | 145 | // followed by null terminated search. 146 | // TCHAR search_string[1]; 147 | 148 | } EVERYTHING_IPC_QUERY2; 149 | 150 | #define EVERYTHING_IPC_QUERY2_REQUEST_NAME 0x00000001 151 | #define EVERYTHING_IPC_QUERY2_REQUEST_PATH 0x00000002 152 | #define EVERYTHING_IPC_QUERY2_REQUEST_FULL_PATH_AND_NAME 0x00000004 153 | #define EVERYTHING_IPC_QUERY2_REQUEST_EXTENSION 0x00000008 154 | #define EVERYTHING_IPC_QUERY2_REQUEST_SIZE 0x00000010 155 | #define EVERYTHING_IPC_QUERY2_REQUEST_DATE_CREATED 0x00000020 156 | #define EVERYTHING_IPC_QUERY2_REQUEST_DATE_MODIFIED 0x00000040 157 | #define EVERYTHING_IPC_QUERY2_REQUEST_DATE_ACCESSED 0x00000080 158 | #define EVERYTHING_IPC_QUERY2_REQUEST_ATTRIBUTES 0x00000100 159 | 160 | 161 | typedef struct EVERYTHING_IPC_ITEM2 162 | { 163 | // item flags one of (EVERYTHING_IPC_FOLDER|EVERYTHING_IPC_DRIVE|EVERYTHING_IPC_ROOT) 164 | DWORD flags; 165 | 166 | // offset from the start of the EVERYTHING_IPC_LIST2 struct to the data content 167 | DWORD data_offset; 168 | 169 | // data found at data_offset 170 | // if EVERYTHING_IPC_QUERY2_REQUEST_NAME was set in request_flags, DWORD name_length in characters (excluding the null terminator); followed by null terminated text. 171 | // if EVERYTHING_IPC_QUERY2_REQUEST_PATH was set in request_flags, DWORD name_length in characters (excluding the null terminator); followed by null terminated text. 172 | // if EVERYTHING_IPC_QUERY2_REQUEST_FULL_PATH_AND_NAME was set in request_flags, DWORD name_length (excluding the null terminator); followed by null terminated text. 173 | // if EVERYTHING_IPC_QUERY2_REQUEST_SIZE was set in request_flags, LARGE_INTERGER size; 174 | // if EVERYTHING_IPC_QUERY2_REQUEST_EXTENSION was set in request_flags, DWORD name_length in characters (excluding the null terminator); followed by null terminated text; 175 | // if EVERYTHING_IPC_QUERY2_REQUEST_TYPE_NAME was set in request_flags, DWORD name_length in characters (excluding the null terminator); followed by null terminated text; 176 | // if EVERYTHING_IPC_QUERY2_REQUEST_DATE_CREATED was set in request_flags, FILETIME date; 177 | // if EVERYTHING_IPC_QUERY2_REQUEST_DATE_MODIFIED was set in request_flags, FILETIME date; 178 | // if EVERYTHING_IPC_QUERY2_REQUEST_DATE_ACCESSED was set in request_flags, FILETIME date; 179 | // if EVERYTHING_IPC_QUERY2_REQUEST_ATTRIBUTES was set in request_flags, DWORD attributes; 180 | // if EVERYTHING_IPC_QUERY2_REQUEST_FILELIST_FILENAME was set in request_flags, DWORD name_length in characters (excluding the null terminator); followed by null terminated text; 181 | // if EVERYTHING_IPC_QUERY2_REQUEST_RUN_COUNT was set in request_flags, DWORD run_count; 182 | // if EVERYTHING_IPC_QUERY2_REQUEST_DATE_RUN was set in request_flags, FILETIME date; 183 | // if EVERYTHING_IPC_QUERY2_REQUEST_DATE_RECENTLY_CHANGED was set in request_flags, FILETIME date; 184 | // if EVERYTHING_IPC_QUERY2_REQUEST_HIGHLIGHTED_NAME was set in request_flags, DWORD name_length in characters (excluding the null terminator); followed by null terminated text; ** = *, *text* = highlighted text 185 | // if EVERYTHING_IPC_QUERY2_REQUEST_HIGHLIGHTED_PATH was set in request_flags, DWORD name_length in characters (excluding the null terminator); followed by null terminated text; ** = *, *text* = highlighted text 186 | // if EVERYTHING_IPC_QUERY2_REQUEST_HIGHLIGHTED_FULL_PATH_AND_NAME was set in request_flags, DWORD name_length in characters (excluding the null terminator); followed by null terminated text; ** = *, *text* = highlighted text 187 | 188 | } EVERYTHING_IPC_ITEM2; 189 | 190 | typedef struct EVERYTHING_IPC_LIST2 191 | { 192 | // number of items found. 193 | DWORD totitems; 194 | 195 | // the number of items available. 196 | DWORD numitems; 197 | 198 | // index offset of the first result in the item list. 199 | DWORD offset; 200 | 201 | // valid request types. 202 | DWORD request_flags; 203 | 204 | // this sort type. 205 | // one of EVERYTHING_IPC_SORT_* types. 206 | // maybe different to requested sort type. 207 | DWORD sort_type; 208 | 209 | // items follow. 210 | // EVERYTHING_IPC_ITEM2 items[numitems] 211 | 212 | // item data follows. 213 | 214 | } EVERYTHING_IPC_LIST2; 215 | 216 | 217 | static LRESULT WINAPI myDemoWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 218 | { 219 | COPYDATASTRUCT* cds = reinterpret_cast(lParam); 220 | if (msg == WM_COPYDATA) 221 | { 222 | if (cds->dwData == MY_REQUEST_ID || cds->dwData == MY_REQUEST_ID + 1) 223 | { 224 | // version 1W query answer 225 | void* mem = malloc(cds->cbData); 226 | CopyMemory(mem, cds->lpData, cds->cbData); 227 | 228 | // Assuming this is Unicode, because I requested using the Unicode message 229 | EVERYTHING_IPC_LISTW* list = static_cast(mem); 230 | 231 | for (DWORD i = 0; i < list->numitems; i++) 232 | { 233 | EVERYTHING_IPC_ITEMW const& item = list->items[i]; 234 | 235 | wchar_t const* filename = reinterpret_cast(reinterpret_cast(mem) + item.filename_offset); 236 | wchar_t const* path = reinterpret_cast(reinterpret_cast(mem) + item.path_offset); 237 | 238 | std::wcout << filename << L"\n\t" << item.flags << L"\n\t" << path << std::endl; 239 | } 240 | 241 | free(mem); 242 | 243 | PostQuitMessage(0); 244 | } 245 | else if (cds->dwData == MY_REQUEST_ID2 || cds->dwData == MY_REQUEST_ID2 + 1) 246 | { 247 | // version 2W query answer 248 | EVERYTHING_IPC_LIST2 const* list = static_cast(cds->lpData); 249 | 250 | for (DWORD i = 0; i < list->numitems; i++) 251 | { 252 | EVERYTHING_IPC_ITEM2 const* item 253 | = reinterpret_cast( 254 | static_cast(cds->lpData) 255 | + sizeof(EVERYTHING_IPC_LIST2) 256 | + i * sizeof(EVERYTHING_IPC_ITEM2)); 257 | 258 | std::wstring filename, path; 259 | int64_t fileSize{ 0 }; 260 | uint64_t fileModTime{ 0 }; 261 | uint32_t fileAttribs{ 0 }; 262 | 263 | uint8_t const* data = static_cast(cds->lpData) + item->data_offset; 264 | 265 | // data found at data_offset 266 | // if EVERYTHING_IPC_QUERY2_REQUEST_NAME was set in request_flags, DWORD name_length in characters (excluding the null terminator); followed by null terminated text. 267 | if ((list->request_flags & EVERYTHING_IPC_QUERY2_REQUEST_NAME) == EVERYTHING_IPC_QUERY2_REQUEST_NAME) 268 | { 269 | uint32_t len = *reinterpret_cast(data); 270 | data += sizeof(uint32_t); 271 | filename = std::wstring{ reinterpret_cast(data), static_cast(len) }; 272 | data += sizeof(wchar_t) * (len + 1); 273 | } 274 | // if EVERYTHING_IPC_QUERY2_REQUEST_PATH was set in request_flags, DWORD name_length in characters (excluding the null terminator); followed by null terminated text. 275 | if ((list->request_flags & EVERYTHING_IPC_QUERY2_REQUEST_PATH) == EVERYTHING_IPC_QUERY2_REQUEST_PATH) 276 | { 277 | uint32_t len = *reinterpret_cast(data); 278 | data += sizeof(uint32_t); 279 | path = std::wstring{ reinterpret_cast(data), static_cast(len) }; 280 | data += sizeof(wchar_t) * (len + 1); 281 | } 282 | // if EVERYTHING_IPC_QUERY2_REQUEST_FULL_PATH_AND_NAME was set in request_flags, DWORD name_length (excluding the null terminator); followed by null terminated text. 283 | if ((list->request_flags & EVERYTHING_IPC_QUERY2_REQUEST_FULL_PATH_AND_NAME) == EVERYTHING_IPC_QUERY2_REQUEST_FULL_PATH_AND_NAME) 284 | { 285 | uint32_t len = *reinterpret_cast(data); 286 | data += sizeof(uint32_t); 287 | std::wstring fullPathAndName = std::wstring{ reinterpret_cast(data), static_cast(len) }; 288 | data += sizeof(wchar_t) * (len + 1); 289 | } 290 | // if EVERYTHING_IPC_QUERY2_REQUEST_SIZE was set in request_flags, LARGE_INTERGER size; 291 | if ((list->request_flags & EVERYTHING_IPC_QUERY2_REQUEST_SIZE) == EVERYTHING_IPC_QUERY2_REQUEST_SIZE) 292 | { 293 | fileSize= *reinterpret_cast(data); 294 | data += sizeof(int64_t); 295 | } 296 | // if EVERYTHING_IPC_QUERY2_REQUEST_EXTENSION was set in request_flags, DWORD name_length in characters (excluding the null terminator); followed by null terminated text; 297 | if ((list->request_flags & EVERYTHING_IPC_QUERY2_REQUEST_EXTENSION) == EVERYTHING_IPC_QUERY2_REQUEST_EXTENSION) 298 | { 299 | uint32_t len = *reinterpret_cast(data); 300 | data += sizeof(uint32_t); 301 | std::wstring extension = std::wstring{ reinterpret_cast(data), static_cast(len) }; 302 | data += sizeof(wchar_t) * (len + 1); 303 | } 304 | // if EVERYTHING_IPC_QUERY2_REQUEST_TYPE_NAME was set in request_flags, DWORD name_length in characters (excluding the null terminator); followed by null terminated text; 305 | // Docu outdated | does not exist 306 | // if EVERYTHING_IPC_QUERY2_REQUEST_DATE_CREATED was set in request_flags, FILETIME date; 307 | if ((list->request_flags & EVERYTHING_IPC_QUERY2_REQUEST_DATE_CREATED) == EVERYTHING_IPC_QUERY2_REQUEST_DATE_CREATED) 308 | { 309 | uint64_t ft = *reinterpret_cast(data); 310 | data += sizeof(uint64_t); 311 | } 312 | // if EVERYTHING_IPC_QUERY2_REQUEST_DATE_MODIFIED was set in request_flags, FILETIME date; 313 | if ((list->request_flags & EVERYTHING_IPC_QUERY2_REQUEST_DATE_MODIFIED) == EVERYTHING_IPC_QUERY2_REQUEST_DATE_MODIFIED) 314 | { 315 | fileModTime = *reinterpret_cast(data); 316 | data += sizeof(uint64_t); 317 | } 318 | // if EVERYTHING_IPC_QUERY2_REQUEST_DATE_ACCESSED was set in request_flags, FILETIME date; 319 | if ((list->request_flags & EVERYTHING_IPC_QUERY2_REQUEST_DATE_ACCESSED) == EVERYTHING_IPC_QUERY2_REQUEST_DATE_ACCESSED) 320 | { 321 | uint64_t ft = *reinterpret_cast(data); 322 | data += sizeof(uint64_t); 323 | } 324 | // if EVERYTHING_IPC_QUERY2_REQUEST_ATTRIBUTES was set in request_flags, DWORD attributes; 325 | if ((list->request_flags & EVERYTHING_IPC_QUERY2_REQUEST_ATTRIBUTES) == EVERYTHING_IPC_QUERY2_REQUEST_ATTRIBUTES) 326 | { 327 | fileAttribs = *reinterpret_cast(data); 328 | data += sizeof(uint32_t); 329 | } 330 | // if EVERYTHING_IPC_QUERY2_REQUEST_FILELIST_FILENAME was set in request_flags, DWORD name_length in characters (excluding the null terminator); followed by null terminated text; 331 | // if EVERYTHING_IPC_QUERY2_REQUEST_RUN_COUNT was set in request_flags, DWORD run_count; 332 | // if EVERYTHING_IPC_QUERY2_REQUEST_DATE_RUN was set in request_flags, FILETIME date; 333 | // if EVERYTHING_IPC_QUERY2_REQUEST_DATE_RECENTLY_CHANGED was set in request_flags, FILETIME date; 334 | // if EVERYTHING_IPC_QUERY2_REQUEST_HIGHLIGHTED_NAME was set in request_flags, DWORD name_length in characters (excluding the null terminator); followed by null terminated text; ** = *, *text* = highlighted text 335 | // if EVERYTHING_IPC_QUERY2_REQUEST_HIGHLIGHTED_PATH was set in request_flags, DWORD name_length in characters (excluding the null terminator); followed by null terminated text; ** = *, *text* = highlighted text 336 | // if EVERYTHING_IPC_QUERY2_REQUEST_HIGHLIGHTED_FULL_PATH_AND_NAME was set in request_flags, DWORD name_length in characters (excluding the null terminator); followed by null terminated text; ** = *, *text* = highlighted text 337 | 338 | std::wcout << filename 339 | << L"\n\t" << item->flags 340 | << L"\n\t" << path 341 | << L"\n\t" << fileSize 342 | << L"\n\t" << fileModTime 343 | << L"\n\t" << fileAttribs 344 | << std::endl; 345 | 346 | } 347 | 348 | PostQuitMessage(0); 349 | } 350 | 351 | } 352 | 353 | return DefWindowProc(hwnd, msg, wParam, lParam); 354 | } 355 | 356 | void RegisterClass() 357 | { 358 | WNDCLASSEXW wcex; 359 | ZeroMemory(&wcex, sizeof(WNDCLASSEXW)); 360 | wcex.cbSize = sizeof(WNDCLASSEXW); 361 | if (!GetClassInfoExW(GetModuleHandleW(0), MY_DEMO_CLASS_NAME, &wcex)) 362 | { 363 | ZeroMemory(&wcex, sizeof(WNDCLASSEXW)); 364 | wcex.cbSize = sizeof(WNDCLASSEXW); 365 | wcex.hInstance = GetModuleHandleW(0); 366 | wcex.lpfnWndProc = &myDemoWindowProc; 367 | wcex.lpszClassName = MY_DEMO_CLASS_NAME; 368 | if (!RegisterClassEx(&wcex)) 369 | { 370 | throw std::runtime_error("Failed to register window class"); 371 | } 372 | } 373 | } 374 | 375 | bool IsEverythingDbBussy(HWND everything_hwnd) 376 | { 377 | int is_db_busy = (int)SendMessage(everything_hwnd, EVERYTHING_WM_IPC, EVERYTHING_IPC_IS_DB_BUSY, 0); 378 | return is_db_busy; 379 | } 380 | 381 | bool SendQuery(HWND everything_hwnd, HWND hwnd, std::wstring const& query) 382 | { 383 | size_t size = sizeof(EVERYTHING_IPC_QUERYW) + sizeof(wchar_t) * query.size(); 384 | void* queryMem = malloc(size); 385 | if (queryMem == nullptr) 386 | { 387 | throw std::runtime_error("Failed to allocate query memory"); 388 | } 389 | ZeroMemory(queryMem, size); 390 | 391 | std::wcout << L"Query: " << query << L"\n\tBussy: " << (IsEverythingDbBussy(everything_hwnd) ? L"true" : L"false") << L"\n" << std::endl; 392 | 393 | static DWORD qId = MY_REQUEST_ID - 1; 394 | qId++; 395 | 396 | EVERYTHING_IPC_QUERYW* q = static_cast(queryMem); 397 | q->max_results = (DWORD)EVERYTHING_IPC_ALLRESULTS; 398 | q->offset = 0; 399 | q->reply_copydata_message = qId; // Do something clever 400 | q->search_flags = EVERYTHING_IPC_MATCHWHOLEWORD | EVERYTHING_IPC_REGEX; 401 | q->reply_hwnd = (DWORD)((DWORD_PTR)hwnd); 402 | 403 | ::memcpy(q->search_string, query.c_str(), sizeof(wchar_t) * query.size()); 404 | 405 | COPYDATASTRUCT cds; 406 | cds.cbData = (DWORD)size; 407 | cds.dwData = EVERYTHING_IPC_COPYDATAQUERYW; 408 | cds.lpData = queryMem; 409 | 410 | LRESULT res = SendMessageW(everything_hwnd, WM_COPYDATA, (WPARAM)hwnd, (LPARAM)&cds); 411 | 412 | free(queryMem); 413 | 414 | return res != 0; 415 | } 416 | 417 | bool SendQuery2(HWND everything_hwnd, HWND hwnd, std::wstring const& query) 418 | { 419 | size_t size = sizeof(EVERYTHING_IPC_QUERY2) + sizeof(wchar_t) * (query.size() + 1); 420 | void* queryMem = malloc(size); 421 | if (queryMem == nullptr) 422 | { 423 | throw std::runtime_error("Failed to allocate query memory"); 424 | } 425 | ZeroMemory(queryMem, size); 426 | 427 | static DWORD qId = MY_REQUEST_ID2 - 1; 428 | qId++; 429 | 430 | EVERYTHING_IPC_QUERY2* q = static_cast(queryMem); 431 | q->reply_hwnd = (DWORD)((DWORD_PTR)hwnd); 432 | q->reply_copydata_message = qId; 433 | q->search_flags = EVERYTHING_IPC_MATCHWHOLEWORD | EVERYTHING_IPC_REGEX; 434 | q->request_flags = EVERYTHING_IPC_QUERY2_REQUEST_NAME | EVERYTHING_IPC_QUERY2_REQUEST_PATH | EVERYTHING_IPC_QUERY2_REQUEST_SIZE | EVERYTHING_IPC_QUERY2_REQUEST_DATE_MODIFIED | EVERYTHING_IPC_QUERY2_REQUEST_ATTRIBUTES; 435 | q->max_results = (DWORD)EVERYTHING_IPC_ALLRESULTS; 436 | 437 | ::memcpy(static_cast(queryMem) + sizeof(EVERYTHING_IPC_QUERY2), query.c_str(), sizeof(wchar_t) * (query.size() + 1)); 438 | 439 | COPYDATASTRUCT cds; 440 | cds.cbData = (DWORD)size; 441 | cds.dwData = EVERYTHING_IPC_COPYDATA_QUERY2W; 442 | cds.lpData = queryMem; 443 | 444 | LRESULT res = SendMessageW(everything_hwnd, WM_COPYDATA, (WPARAM)hwnd, (LPARAM)&cds); 445 | 446 | free(queryMem); 447 | 448 | return res != 0; 449 | } 450 | 451 | void MessagePump() 452 | { 453 | MSG msg; 454 | int ret; 455 | bool running = true; 456 | 457 | while (running) 458 | { 459 | WaitMessage(); 460 | while (PeekMessageW(&msg, NULL, 0, 0, 0)) 461 | { 462 | ret = (DWORD)GetMessageW(&msg, 0, 0, 0); 463 | if (ret == -1) 464 | { 465 | running = false; 466 | break; 467 | } 468 | if (!ret) 469 | { 470 | running = false; 471 | break; 472 | } 473 | 474 | // let windows handle it. 475 | TranslateMessage(&msg); 476 | DispatchMessageW(&msg); 477 | } 478 | } 479 | } 480 | 481 | void PrintEverythingVersion(HWND everything_hwnd) 482 | { 483 | int major_version = (int)SendMessage(everything_hwnd, EVERYTHING_WM_IPC, EVERYTHING_IPC_GET_MAJOR_VERSION, 0); 484 | int minor_version = (int)SendMessage(everything_hwnd, EVERYTHING_WM_IPC, EVERYTHING_IPC_GET_MINOR_VERSION, 0); 485 | int revision = (int)SendMessage(everything_hwnd, EVERYTHING_WM_IPC, EVERYTHING_IPC_GET_REVISION, 0); 486 | int build = (int)SendMessage(everything_hwnd, EVERYTHING_WM_IPC, EVERYTHING_IPC_GET_BUILD_NUMBER, 0); 487 | 488 | std::wcout << L"Everything v" << major_version << L"." << minor_version << L"." << revision << L"." << build << L"\n"; 489 | } 490 | 491 | int main() 492 | { 493 | try 494 | { 495 | _setmode(_fileno(stdout), _O_U16TEXT); 496 | 497 | HWND everything_hwnd = FindWindowW(EVERYTHING_IPC_WNDCLASSW, 0); 498 | if (!everything_hwnd) 499 | { 500 | throw std::runtime_error("Failed to find everything IPC window"); 501 | } 502 | 503 | PrintEverythingVersion(everything_hwnd); 504 | 505 | RegisterClass(); 506 | 507 | HWND hwnd = CreateWindowW(MY_DEMO_CLASS_NAME, L"", 0, 0, 0, 0, 0, 0, 0, GetModuleHandleW(0), 0); 508 | if (!hwnd) 509 | { 510 | throw std::runtime_error("Failed to create window"); 511 | } 512 | 513 | if (SendQuery2(everything_hwnd, hwnd, L"^\\.git$")) 514 | { 515 | //SendQuery(everything_hwnd, hwnd, L"\\.rar$"); 516 | MessagePump(); 517 | } 518 | 519 | DestroyWindow(hwnd); 520 | } 521 | catch (std::exception& ex) 522 | { 523 | std::cerr << "EXCEPTION: " << ex.what() << std::endl; 524 | return -1; 525 | } 526 | catch (...) 527 | { 528 | std::cerr << "UNKNOWN EXCEPTION" << std::endl; 529 | return -1; 530 | } 531 | return 0; 532 | } 533 | -------------------------------------------------------------------------------- /Reference/EverythingDemo/EverythingDemo.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.33103.201 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EverythingDemo", "EverythingDemo.vcxproj", "{697D9B79-0B16-4E5A-9F88-BDFE06E9A88C}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {697D9B79-0B16-4E5A-9F88-BDFE06E9A88C}.Debug|x64.ActiveCfg = Debug|x64 17 | {697D9B79-0B16-4E5A-9F88-BDFE06E9A88C}.Debug|x64.Build.0 = Debug|x64 18 | {697D9B79-0B16-4E5A-9F88-BDFE06E9A88C}.Debug|x86.ActiveCfg = Debug|Win32 19 | {697D9B79-0B16-4E5A-9F88-BDFE06E9A88C}.Debug|x86.Build.0 = Debug|Win32 20 | {697D9B79-0B16-4E5A-9F88-BDFE06E9A88C}.Release|x64.ActiveCfg = Release|x64 21 | {697D9B79-0B16-4E5A-9F88-BDFE06E9A88C}.Release|x64.Build.0 = Release|x64 22 | {697D9B79-0B16-4E5A-9F88-BDFE06E9A88C}.Release|x86.ActiveCfg = Release|Win32 23 | {697D9B79-0B16-4E5A-9F88-BDFE06E9A88C}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {F90B52A6-443A-47C6-96AE-F987983A3D3B} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /Reference/EverythingDemo/EverythingDemo.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {697d9b79-0b16-4e5a-9f88-bdfe06e9a88c} 25 | EverythingDemo 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Level3 76 | true 77 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 78 | true 79 | 80 | 81 | Console 82 | true 83 | 84 | 85 | 86 | 87 | Level3 88 | true 89 | true 90 | true 91 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 92 | true 93 | 94 | 95 | Console 96 | true 97 | true 98 | true 99 | 100 | 101 | 102 | 103 | Level3 104 | true 105 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 106 | true 107 | 108 | 109 | Console 110 | true 111 | 112 | 113 | 114 | 115 | Level3 116 | true 117 | true 118 | true 119 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 120 | true 121 | 122 | 123 | Console 124 | true 125 | true 126 | true 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /Reference/EverythingDemo/EverythingDemo.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /TestNugetConsoleApp/Program.cs: -------------------------------------------------------------------------------- 1 | using EverythingSearchClient; 2 | using System.Reflection; 3 | 4 | internal class Program 5 | { 6 | 7 | private static void MyAssert(bool test, string desc) 8 | { 9 | if (test) 10 | { 11 | Console.WriteLine("✅ {0}", desc); 12 | } 13 | else 14 | { 15 | Console.WriteLine("Failed -- {0}", desc); 16 | } 17 | } 18 | 19 | private static int Main(string[] args) 20 | { 21 | try 22 | { 23 | Console.OutputEncoding = System.Text.Encoding.UTF8; 24 | 25 | Console.WriteLine("Everything {0}", SearchClient.GetEverythingVersion()); 26 | 27 | AssemblyName[] assemblies = Assembly.GetEntryAssembly()?.GetReferencedAssemblies() ?? Array.Empty(); 28 | foreach (AssemblyName a in assemblies) 29 | { 30 | Console.WriteLine("Using {0}", a); 31 | } 32 | 33 | string myPath = Assembly.GetExecutingAssembly().Location; 34 | Console.WriteLine("Path from Assembly: {0}", myPath); 35 | 36 | string myFileName = Path.GetFileName(myPath); 37 | MyAssert(string.Equals(myFileName, "TestNugetConsoleApp.dll", StringComparison.InvariantCultureIgnoreCase), "File name from assembly"); 38 | 39 | myPath = Path.GetDirectoryName(myPath) ?? string.Empty; 40 | Console.WriteLine("Path: {0}", myPath); 41 | 42 | SearchClient everything = new(); 43 | Result r = everything.Search(myFileName); 44 | Console.WriteLine("Found {0} items", r.NumItems); 45 | MyAssert(r.NumItems > 0, "Found files"); 46 | 47 | bool found = false; 48 | foreach (Result.Item i in r.Items) { 49 | Console.WriteLine("{0} / {1} [{2}]", i.Path, i.Name, i.Flags); 50 | if (!string.Equals(i.Name, myFileName, StringComparison.InvariantCultureIgnoreCase)) 51 | { 52 | Console.WriteLine("Warning: file name does not match"); 53 | continue; 54 | } 55 | if (!string.Equals(i.Path, myPath, StringComparison.InvariantCultureIgnoreCase)) 56 | { 57 | continue; 58 | } 59 | if (i.Flags != Result.ItemFlags.None) 60 | { 61 | Console.WriteLine("Warning: Flags are unexpectedly set"); 62 | } 63 | found = true; 64 | } 65 | MyAssert(found, "Found my file in the right path"); 66 | Console.WriteLine("Complete."); 67 | 68 | return 0; 69 | } 70 | catch (Exception e) 71 | { 72 | Console.Error.WriteLine("❌ Exception: {0}", e); 73 | return -1; 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /TestNugetConsoleApp/README.md: -------------------------------------------------------------------------------- 1 | # 🔎 EverythingSearchClient 📦 Nuget Test 2 | This test application performs one simple search call. 3 | However, it's dependency is the freshly built Nuget package. 4 | 5 | If you run this locally, you might need to: 6 | 7 | * First build the `Release` configuration from the [EverythingSearchClient library](../EverythingSearchClient.sln). 8 | * Manually edit [TestNugetConsoleApp.csproj](TestNugetConsoleApp.csproj) to reference the built package with the correct version number. 9 | * If you want to built against the `Debug` version of the EverythingSearchClient library, you also need to edit [nuget.config](nuget.config) to target the `Debug` bin directory as package source. 10 | -------------------------------------------------------------------------------- /TestNugetConsoleApp/TestNugetConsoleApp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0-windows 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /TestNugetConsoleApp/TestNugetConsoleApp.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.33103.201 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestNugetConsoleApp", "TestNugetConsoleApp.csproj", "{B5DDAA43-76F2-45E3-A1DE-86D59819E82A}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {B5DDAA43-76F2-45E3-A1DE-86D59819E82A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {B5DDAA43-76F2-45E3-A1DE-86D59819E82A}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {B5DDAA43-76F2-45E3-A1DE-86D59819E82A}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {B5DDAA43-76F2-45E3-A1DE-86D59819E82A}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {1005202A-CB6F-4884-B422-547E3E9B3B1A} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /TestNugetConsoleApp/nuget.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /TestProject/DataGenerator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace EverythingSearchClient.TestProject 10 | { 11 | internal class DataGenerator 12 | { 13 | 14 | public string TestDataRootName { get; set; } 15 | 16 | public string TestDataRootDirectory { get; set; } 17 | 18 | public DataGenerator() 19 | { 20 | string p = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? Environment.CurrentDirectory; 21 | TestDataRootName = string.Format("ESC{0}_TestData", Process.GetCurrentProcess().Id); 22 | TestDataRootDirectory = Path.Combine(p, TestDataRootName); 23 | 24 | // If you edit this list of test directories and file, it will affect the expected results of all tests! 25 | DirectoryInfo root = EnsureDir(TestDataRootDirectory); 26 | EnsureFile(root, "FileA.txt", 8, 1, 7); 27 | EnsureFile(root, "FileB.txt", 1, 2, 3); 28 | EnsureFile(root, "FileC.xml", 5, 0, 2); 29 | DirectoryInfo sub1 = EnsureDir(root, "SubDir1"); 30 | EnsureFile(sub1, "fileA.jpg", 0, 5, 4); 31 | EnsureFile(sub1, "FileD.gif", 3, 6, 0); 32 | DirectoryInfo sub2 = EnsureDir(root, "SubDir2"); 33 | EnsureFile(sub2, "fileA.html", 2, 3, 6); 34 | File.SetAttributes(Path.Combine(sub2.FullName, "fileA.html"), FileAttributes.Hidden | FileAttributes.Archive); 35 | EnsureFile(sub2, "FileE.dat", 6, 7, 8); 36 | DirectoryInfo sub2sub = EnsureDir(sub2, "SubSubDirA"); 37 | EnsureFile(sub2sub, "FileA.json", 7, 8, 5); 38 | EnsureFile(sub2sub, "FileF.txt", 4, 4, 1); 39 | 40 | // We need to wait for EverythingIndex to be built up 41 | SearchClient everything = new(); 42 | Result res = new(); 43 | DateTime startWaiting = DateTime.Now; 44 | while (res.TotalItems == 0) 45 | { 46 | if ((DateTime.Now - startWaiting).TotalMinutes > 30.0) 47 | { 48 | throw new Exception("Everything file indexing took longer than 30 minutes"); 49 | } 50 | Thread.Sleep(20); 51 | try 52 | { 53 | res = everything.Search("File " + TestDataRootDirectory, SearchClient.BehaviorWhenBusy.Error); 54 | } 55 | catch 56 | { 57 | res = new(); 58 | } 59 | } 60 | } 61 | 62 | public DateTime TestCreationTime { get; } = new DateTime(2015, 4, 1, 14, 44, 59); 63 | 64 | public DateTime TestLastWriteTime { get; } = new DateTime(2016, 6, 30, 12, 0, 1); 65 | 66 | private void EnsureFile(DirectoryInfo dir, string filename, int size, int creationOffset, int modifiedOffset) 67 | { 68 | string path = Path.Combine(dir.FullName, filename); 69 | if (!File.Exists(path)) 70 | { 71 | File.WriteAllText(path, "Test Data" + new string('X', size)); 72 | File.SetCreationTime(path, TestCreationTime + TimeSpan.FromDays(creationOffset)); 73 | File.SetLastWriteTime(path, TestLastWriteTime + TimeSpan.FromDays(modifiedOffset)); 74 | } 75 | } 76 | 77 | private DirectoryInfo EnsureDir(string testDir) 78 | { 79 | if (!Directory.Exists(testDir)) 80 | { 81 | Directory.CreateDirectory(testDir); 82 | } 83 | return new(testDir); 84 | } 85 | 86 | private DirectoryInfo EnsureDir(DirectoryInfo dir, string testSubDir) 87 | { 88 | return EnsureDir(Path.Combine(dir.FullName, testSubDir)); 89 | } 90 | 91 | public bool Contains(Result res, string name) 92 | { 93 | string p = Path.GetDirectoryName(Path.Combine(TestDataRootDirectory, name)) ?? string.Empty; 94 | string n = Path.GetFileName(name); 95 | foreach (Result.Item i in res.Items) 96 | { 97 | if (string.Compare(i.Name, n) != 0) continue; 98 | if (!i.Path.EndsWith(p)) continue; 99 | return true; 100 | } 101 | return false; 102 | } 103 | 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /TestProject/README.md: -------------------------------------------------------------------------------- 1 | # 🔎 EverythingSearchClient TestProject 2 | Note: this test project is not to do an exhaustive test of Everything itself. 3 | It's only purpose is to the whether or not the features of the EverythingSearchClient's interface show the expected effects. 4 | It is also not meant to be complete, e.g. in terms of test-driven development. 5 | Consider this project a smoke test, doing a rough check of fitness only. 6 | -------------------------------------------------------------------------------- /TestProject/TestBusyBehavior.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Security.Cryptography; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace EverythingSearchClient.TestProject 9 | { 10 | [TestClass] 11 | public class TestBusyBehavior 12 | { 13 | private DataGenerator data = new(); 14 | private SearchClient everything1 = new(); 15 | private SearchClient everything2 = new(); 16 | 17 | private void WaitUntilReady() 18 | { 19 | DateTime start = DateTime.Now; 20 | while (SearchClient.IsEverythingBusy()) 21 | { 22 | if ((DateTime.Now - start).TotalMinutes > 10) 23 | { 24 | throw new Exception("Everything was busy for over 10 minutes"); 25 | } 26 | } 27 | } 28 | 29 | private void WaitUntilBusy() 30 | { 31 | DateTime start = DateTime.Now; 32 | while (!SearchClient.IsEverythingBusy()) 33 | { 34 | if ((DateTime.Now - start).TotalMinutes > 10) 35 | { 36 | throw new Exception("Everything was busy for over 10 minutes"); 37 | } 38 | } 39 | } 40 | 41 | #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. 42 | private TestContext testContextInstance; 43 | #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. 44 | 45 | /// 46 | /// Gets or sets the test context which provides 47 | /// information about and functionality for the current test run. 48 | /// 49 | public TestContext TestContext 50 | { 51 | get { return testContextInstance; } 52 | set { testContextInstance = value; } 53 | } 54 | 55 | private static uint longTimeout = 0; // SearchClient.DefaultTimeoutMs; 56 | 57 | private void EvaluateTimeout() 58 | { 59 | if (longTimeout > 0) 60 | { 61 | TestContext.WriteLine("Long Timeout kept at {0} ms", longTimeout); 62 | return; 63 | } 64 | 65 | WaitUntilReady(); 66 | DateTime start = DateTime.Now; 67 | try 68 | { 69 | Result _ = everything1.Search(".exe"); 70 | } 71 | catch 72 | { 73 | } 74 | 75 | longTimeout = Math.Max( 76 | 2 * (uint)(DateTime.Now - start).TotalMilliseconds, 77 | SearchClient.DefaultTimeoutMs); 78 | 79 | TestContext.WriteLine("Long Timeout evaluated to be {0} ms", longTimeout); 80 | } 81 | 82 | [TestMethod] 83 | public void TestMethodWaitOrErrorWhenBusy() 84 | { 85 | EvaluateTimeout(); 86 | WaitUntilReady(); 87 | bool search1Complete = false; 88 | bool search1Failed = false; 89 | 90 | Result blocker = everything2.Search("File " + data.TestDataRootDirectory); 91 | Assert.AreEqual(9, blocker.TotalItems); 92 | WaitUntilReady(); 93 | 94 | Thread t = new(() => 95 | { 96 | try 97 | { 98 | Result _ = everything1.Search(".exe"); 99 | search1Complete = true; 100 | } 101 | catch 102 | { 103 | search1Failed = true; 104 | } 105 | 106 | }); 107 | t.Start(); 108 | 109 | WaitUntilBusy(); 110 | Result r2 = everything2.Search("File " + data.TestDataRootDirectory, SearchClient.BehaviorWhenBusy.WaitOrError, longTimeout); 111 | 112 | Assert.IsTrue(search1Complete); 113 | Assert.IsFalse(search1Failed); 114 | 115 | Assert.AreEqual(9, r2.TotalItems); 116 | 117 | t.Join(); 118 | } 119 | 120 | [TestMethod] 121 | public void TestMethodWaitOrErrorWhenBusyErrorCase() 122 | { 123 | EvaluateTimeout(); 124 | WaitUntilReady(); 125 | bool search1Complete = false; 126 | bool search1Failed = false; 127 | bool search2Complete = false; 128 | bool search2Failed = false; 129 | 130 | Thread t = new(() => 131 | { 132 | try 133 | { 134 | Result _ = everything1.Search(".exe"); 135 | search1Complete = true; 136 | } 137 | catch 138 | { 139 | search1Failed = true; 140 | } 141 | 142 | }); 143 | t.Start(); 144 | 145 | WaitUntilBusy(); 146 | try 147 | { 148 | Result _ = everything2.Search("File " + data.TestDataRootDirectory, SearchClient.BehaviorWhenBusy.WaitOrError, 1); 149 | search2Complete = true; 150 | } 151 | catch 152 | { 153 | search2Failed = true; 154 | } 155 | 156 | Assert.IsFalse(search2Complete); 157 | Assert.IsTrue(search2Failed); 158 | 159 | t.Join(); 160 | 161 | Assert.IsTrue(search1Complete); 162 | Assert.IsFalse(search1Failed); 163 | } 164 | 165 | [TestMethod] 166 | public void TestMethodWaitOrContinueWhenBusy() 167 | { 168 | EvaluateTimeout(); 169 | WaitUntilReady(); 170 | bool search1Complete = false; 171 | bool search1Failed = false; 172 | 173 | Thread t = new(() => 174 | { 175 | try 176 | { 177 | Result _ = everything1.Search(".exe"); 178 | search1Complete = true; 179 | } 180 | catch 181 | { 182 | search1Failed = true; 183 | } 184 | 185 | }); 186 | t.Start(); 187 | 188 | WaitUntilBusy(); 189 | Result r2 = everything2.Search("File " + data.TestDataRootDirectory, SearchClient.BehaviorWhenBusy.WaitOrContinue, longTimeout); 190 | 191 | Assert.IsTrue(search1Complete); 192 | Assert.IsFalse(search1Failed); 193 | 194 | Assert.AreEqual(9, r2.TotalItems); 195 | 196 | t.Join(); 197 | } 198 | 199 | [TestMethod] 200 | public void TestMethodErrorWhenBusy() 201 | { 202 | EvaluateTimeout(); 203 | WaitUntilReady(); 204 | bool search1Complete = false; 205 | bool search1Failed = false; 206 | bool search2Complete = false; 207 | bool search2Failed = false; 208 | 209 | Thread t = new(() => 210 | { 211 | try 212 | { 213 | Result _ = everything1.Search(".exe"); 214 | search1Complete = true; 215 | } 216 | catch 217 | { 218 | search1Failed = true; 219 | } 220 | 221 | }); 222 | t.Start(); 223 | 224 | WaitUntilBusy(); 225 | try 226 | { 227 | Result _ = everything2.Search("File " + data.TestDataRootDirectory, SearchClient.BehaviorWhenBusy.Error, longTimeout); 228 | search2Complete = true; 229 | } 230 | catch 231 | { 232 | search2Failed = true; 233 | } 234 | 235 | Assert.IsFalse(search2Complete); 236 | Assert.IsTrue(search2Failed); 237 | 238 | t.Join(); 239 | 240 | Assert.IsTrue(search1Complete); 241 | Assert.IsFalse(search1Failed); 242 | } 243 | 244 | [TestMethod] 245 | public void TestMethodContinueWhenBusy() 246 | { 247 | EvaluateTimeout(); 248 | WaitUntilReady(); 249 | 250 | Thread t = new(() => 251 | { 252 | try 253 | { 254 | Result _ = everything1.Search(".exe"); 255 | } 256 | catch 257 | { 258 | } 259 | }); 260 | t.Start(); 261 | 262 | WaitUntilBusy(); 263 | Result r2 = everything2.Search("File " + data.TestDataRootDirectory, SearchClient.BehaviorWhenBusy.Continue, longTimeout); 264 | Assert.AreEqual(9, r2.TotalItems); 265 | 266 | // result of search1 within t is undefined 267 | t.Join(); 268 | } 269 | } 270 | } 271 | -------------------------------------------------------------------------------- /TestProject/TestProject.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0-windows 5 | enable 6 | enable 7 | 8 | false 9 | 10 | EverythingSearchClient.$(MSBuildProjectName.Replace(" ", "_")) 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /TestProject/TestQuery2Results.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace EverythingSearchClient.TestProject 8 | { 9 | [TestClass] 10 | public class TestQuery2Results 11 | { 12 | private DataGenerator data = new(); 13 | private SearchClient everything = new(); 14 | 15 | [TestMethod] 16 | public void TestSearchQuery2Results() 17 | { 18 | Result r = everything.Search("FileA " + data.TestDataRootDirectory, SearchClient.SearchFlags.None); 19 | Assert.AreEqual(4, r.TotalItems); 20 | Assert.IsTrue(data.Contains(r, @"FileA.txt")); 21 | Assert.IsTrue(data.Contains(r, @"SubDir1\fileA.jpg")); 22 | Assert.IsTrue(data.Contains(r, @"SubDir2\fileA.html")); 23 | Assert.IsTrue(data.Contains(r, @"SubDir2\SubSubDirA\FileA.json")); 24 | 25 | Assert.IsTrue(r.Items[0].Size.HasValue); 26 | Assert.IsTrue(r.Items[0].CreationTime.HasValue); 27 | Assert.IsTrue(r.Items[0].LastWriteTime.HasValue); 28 | Assert.IsTrue(r.Items[0].FileAttributes.HasValue); 29 | 30 | int idx = -1; 31 | for (int i = 0; i < r.NumItems; ++i) 32 | { 33 | if (r.Items[i].Name.Equals("fileA.html")) 34 | { 35 | idx = i; 36 | break; 37 | } 38 | } 39 | 40 | Assert.AreEqual("fileA.html", r.Items[idx].Name); 41 | Assert.AreEqual(9 + 2, r.Items[idx].Size ?? 0); 42 | Assert.AreEqual(data.TestCreationTime + TimeSpan.FromDays(3), r.Items[idx].CreationTime); 43 | Assert.AreEqual(data.TestLastWriteTime + TimeSpan.FromDays(6), r.Items[idx].LastWriteTime); 44 | var attr = r.Items[idx].FileAttributes; 45 | Assert.IsTrue(attr.HasValue); 46 | if (attr.HasValue) 47 | { 48 | Assert.IsTrue(attr.Value.HasFlag(Result.ItemFileAttributes.Hidden)); 49 | Assert.IsTrue(attr.Value.HasFlag(Result.ItemFileAttributes.Archive)); 50 | } 51 | } 52 | 53 | } 54 | 55 | } -------------------------------------------------------------------------------- /TestProject/TestResultLimit.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace EverythingSearchClient.TestProject 8 | { 9 | [TestClass] 10 | public class TestResultLimit 11 | { 12 | private DataGenerator data = new DataGenerator(); 13 | private SearchClient everything = new(); 14 | 15 | private bool[] EvalResult(Result r) 16 | { 17 | bool[] f = new bool[9]; 18 | f[0] = data.Contains(r, @"FileA.txt"); 19 | f[1] = data.Contains(r, @"FileB.txt"); 20 | f[2] = data.Contains(r, @"FileC.xml"); 21 | f[3] = data.Contains(r, @"SubDir1\fileA.jpg"); 22 | f[4] = data.Contains(r, @"SubDir1\FileD.gif"); 23 | f[5] = data.Contains(r, @"SubDir2\fileA.html"); 24 | f[6] = data.Contains(r, @"SubDir2\FileE.dat"); 25 | f[7] = data.Contains(r, @"SubDir2\SubSubDirA\FileA.json"); 26 | f[8] = data.Contains(r, @"SubDir2\SubSubDirA\FileF.txt"); 27 | return f; 28 | } 29 | 30 | private int CountTrue(bool[] f) 31 | { 32 | int c = 0; 33 | foreach (bool b in f) 34 | { 35 | if (b) c++; 36 | } 37 | return c; 38 | } 39 | 40 | private int CountBothTrue(bool[] f1, bool[] f2) 41 | { 42 | int c = 0; 43 | for (int i = 0; i < Math.Min(f1.Length, f2.Length); ++i) 44 | { 45 | if (f1[i] && f2[i]) c++; 46 | } 47 | return c; 48 | } 49 | 50 | [TestMethod] 51 | public void TestSearchResultLimit() 52 | { 53 | Result r = everything.Search("File " + data.TestDataRootDirectory); 54 | Assert.AreEqual(9, r.TotalItems); 55 | 56 | bool[] f = EvalResult(r); 57 | Assert.IsTrue(f[0]); 58 | Assert.IsTrue(f[1]); 59 | Assert.IsTrue(f[2]); 60 | Assert.IsTrue(f[3]); 61 | Assert.IsTrue(f[4]); 62 | Assert.IsTrue(f[5]); 63 | Assert.IsTrue(f[6]); 64 | Assert.IsTrue(f[7]); 65 | Assert.IsTrue(f[8]); 66 | 67 | r = everything.Search("File " + data.TestDataRootDirectory, 4); 68 | Assert.AreEqual(9, r.TotalItems); 69 | Assert.AreEqual(4, r.NumItems); 70 | f = EvalResult(r); 71 | Assert.AreEqual(4, CountTrue(f)); 72 | 73 | r = everything.Search("File " + data.TestDataRootDirectory, 4, 4); 74 | Assert.AreEqual(9, r.TotalItems); 75 | Assert.AreEqual(4, r.NumItems); 76 | bool[] f2 = EvalResult(r); 77 | Assert.AreEqual(4, CountTrue(f2)); 78 | Assert.AreEqual(0, CountBothTrue(f, f2)); 79 | 80 | r = everything.Search("File " + data.TestDataRootDirectory, 4, 3); 81 | Assert.AreEqual(9, r.TotalItems); 82 | Assert.AreEqual(4, r.NumItems); 83 | f2 = EvalResult(r); 84 | Assert.AreEqual(4, CountTrue(f2)); 85 | Assert.AreEqual(1, CountBothTrue(f, f2)); 86 | 87 | r = everything.Search("File " + data.TestDataRootDirectory, 4, 8); 88 | Assert.AreEqual(9, r.TotalItems); 89 | Assert.AreEqual(1, r.NumItems); 90 | f2 = EvalResult(r); 91 | Assert.AreEqual(1, CountTrue(f2)); 92 | Assert.AreEqual(0, CountBothTrue(f, f2)); 93 | 94 | r = everything.Search("File " + data.TestDataRootDirectory, 4, 12); 95 | Assert.AreEqual(9, r.TotalItems); 96 | Assert.AreEqual(0, r.NumItems); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /TestProject/TestSearchFlags.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Text.RegularExpressions; 6 | using System.Threading.Tasks; 7 | 8 | namespace EverythingSearchClient.TestProject 9 | { 10 | [TestClass] 11 | public class TestSearchFlags 12 | { 13 | private DataGenerator data = new(); 14 | private SearchClient everything = new(); 15 | 16 | [TestMethod] 17 | public void TestSearchFlagsNone() 18 | { 19 | Result r = everything.Search("File " + data.TestDataRootDirectory, SearchClient.SearchFlags.None); 20 | Assert.AreEqual(9, r.TotalItems); 21 | Assert.IsTrue(data.Contains(r, @"FileA.txt")); 22 | Assert.IsTrue(data.Contains(r, @"FileB.txt")); 23 | Assert.IsTrue(data.Contains(r, @"FileC.xml")); 24 | Assert.IsTrue(data.Contains(r, @"SubDir1\fileA.jpg")); 25 | Assert.IsTrue(data.Contains(r, @"SubDir1\FileD.gif")); 26 | Assert.IsTrue(data.Contains(r, @"SubDir2\fileA.html")); 27 | Assert.IsTrue(data.Contains(r, @"SubDir2\FileE.dat")); 28 | Assert.IsTrue(data.Contains(r, @"SubDir2\SubSubDirA\FileA.json")); 29 | Assert.IsTrue(data.Contains(r, @"SubDir2\SubSubDirA\FileF.txt")); 30 | 31 | r = everything.Search("FileA " + data.TestDataRootDirectory, SearchClient.SearchFlags.None); 32 | Assert.AreEqual(4, r.TotalItems); 33 | Assert.IsTrue(data.Contains(r, @"FileA.txt")); 34 | Assert.IsTrue(data.Contains(r, @"SubDir1\fileA.jpg")); 35 | Assert.IsTrue(data.Contains(r, @"SubDir2\fileA.html")); 36 | Assert.IsTrue(data.Contains(r, @"SubDir2\SubSubDirA\FileA.json")); 37 | } 38 | 39 | [TestMethod] 40 | public void TestSearchFlagsMatchCase() 41 | { 42 | Result r = everything.Search("File " + data.TestDataRootDirectory, SearchClient.SearchFlags.MatchCase); 43 | Assert.AreEqual(7, r.TotalItems); 44 | Assert.IsTrue(data.Contains(r, @"FileA.txt")); 45 | Assert.IsTrue(data.Contains(r, @"FileB.txt")); 46 | Assert.IsTrue(data.Contains(r, @"FileC.xml")); 47 | Assert.IsTrue(data.Contains(r, @"SubDir1\FileD.gif")); 48 | Assert.IsTrue(data.Contains(r, @"SubDir2\FileE.dat")); 49 | Assert.IsTrue(data.Contains(r, @"SubDir2\SubSubDirA\FileA.json")); 50 | Assert.IsTrue(data.Contains(r, @"SubDir2\SubSubDirA\FileF.txt")); 51 | 52 | r = everything.Search("file " + data.TestDataRootDirectory, SearchClient.SearchFlags.MatchCase); 53 | Assert.AreEqual(2, r.TotalItems); 54 | Assert.IsTrue(data.Contains(r, @"SubDir1\fileA.jpg")); 55 | Assert.IsTrue(data.Contains(r, @"SubDir2\fileA.html")); 56 | } 57 | 58 | [TestMethod] 59 | public void TestSearchFlagsMatchWholeWord() 60 | { 61 | Result r = everything.Search("File " + data.TestDataRootDirectory, SearchClient.SearchFlags.MatchWholeWord); 62 | Assert.AreEqual(0, r.TotalItems); 63 | 64 | r = everything.Search("txt " + data.TestDataRootDirectory, SearchClient.SearchFlags.MatchWholeWord); 65 | Assert.AreEqual(3, r.TotalItems); 66 | Assert.IsTrue(data.Contains(r, @"FileA.txt")); 67 | Assert.IsTrue(data.Contains(r, @"FileB.txt")); 68 | Assert.IsTrue(data.Contains(r, @"SubDir2\SubSubDirA\FileF.txt")); 69 | } 70 | 71 | [TestMethod] 72 | public void TestSearchFlagsMatchPath() 73 | { 74 | Result r = everything.Search("Dir1 " + data.TestDataRootDirectory, SearchClient.SearchFlags.None); 75 | Assert.AreEqual(1, r.TotalItems); 76 | Assert.IsTrue(data.Contains(r, @"SubDir1")); 77 | 78 | r = everything.Search("Dir1 " + data.TestDataRootDirectory, SearchClient.SearchFlags.MatchPath); 79 | Assert.AreEqual(3, r.TotalItems); 80 | Assert.IsTrue(data.Contains(r, @"SubDir1")); 81 | Assert.IsTrue(data.Contains(r, @"SubDir1\fileA.jpg")); 82 | Assert.IsTrue(data.Contains(r, @"SubDir1\FileD.gif")); 83 | } 84 | 85 | [TestMethod] 86 | public void TestSearchFlagsRegEx() 87 | { 88 | Result r = everything.Search(@"^fileA\.[^\.]+$", SearchClient.SearchFlags.RegEx); 89 | 90 | Assert.IsTrue(4 <= r.TotalItems); // will also find stuff outside the test directory 91 | Assert.IsTrue(data.Contains(r, @"FileA.txt")); 92 | Assert.IsFalse(data.Contains(r, @"FileB.txt")); 93 | Assert.IsFalse(data.Contains(r, @"FileC.xml")); 94 | Assert.IsTrue(data.Contains(r, @"SubDir1\fileA.jpg")); 95 | Assert.IsFalse(data.Contains(r, @"SubDir1\FileD.gif")); 96 | Assert.IsTrue(data.Contains(r, @"SubDir2\fileA.html")); 97 | Assert.IsFalse(data.Contains(r, @"SubDir2\FileE.dat")); 98 | Assert.IsTrue(data.Contains(r, @"SubDir2\SubSubDirA\FileA.json")); 99 | Assert.IsFalse(data.Contains(r, @"SubDir2\SubSubDirA\FileF.txt")); 100 | 101 | r = everything.Search("^" + Regex.Escape(data.TestDataRootDirectory) + @".+fileA\.[^\.]+$", SearchClient.SearchFlags.RegEx); 102 | Assert.AreEqual(4, r.TotalItems); 103 | Assert.IsTrue(data.Contains(r, @"FileA.txt")); 104 | Assert.IsTrue(data.Contains(r, @"SubDir1\fileA.jpg")); 105 | Assert.IsTrue(data.Contains(r, @"SubDir2\fileA.html")); 106 | Assert.IsTrue(data.Contains(r, @"SubDir2\SubSubDirA\FileA.json")); 107 | 108 | r = everything.Search("^" + Regex.Escape(data.TestDataRootDirectory) + @"[^a]+fileA\.[^\.]+$", SearchClient.SearchFlags.RegEx); 109 | Assert.AreEqual(3, r.TotalItems); 110 | Assert.IsTrue(data.Contains(r, @"FileA.txt")); 111 | Assert.IsTrue(data.Contains(r, @"SubDir1\fileA.jpg")); 112 | Assert.IsTrue(data.Contains(r, @"SubDir2\fileA.html")); 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /TestProject/TestServiceInfo.cs: -------------------------------------------------------------------------------- 1 | namespace EverythingSearchClient.TestProject 2 | { 3 | [TestClass] 4 | public class TestServiceInfo 5 | { 6 | [TestMethod] 7 | public void EverythingIsAvailable() 8 | { 9 | Assert.IsTrue(SearchClient.IsEverythingAvailable()); 10 | } 11 | 12 | [TestMethod] 13 | public void EverythingTellsItsVersion() 14 | { 15 | Version v = SearchClient.GetEverythingVersion(); 16 | Assert.IsTrue(v.Major > -1); 17 | Assert.IsTrue(v.Minor > -1); 18 | Assert.IsTrue(v > new Version(1, 0)); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /TestProject/TestSortedResults.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using static System.Net.Mime.MediaTypeNames; 7 | 8 | namespace EverythingSearchClient.TestProject 9 | { 10 | [TestClass] 11 | public class TestSortedResults 12 | { 13 | private DataGenerator data = new(); 14 | private SearchClient everything = new(); 15 | 16 | private static readonly string[] filesByName = new string[] { 17 | "fileA.html", 18 | "fileA.jpg", 19 | "FileA.json", 20 | "FileA.txt", 21 | "FileB.txt", 22 | "FileC.xml", 23 | "FileD.gif", 24 | "FileE.dat", 25 | "FileF.txt" 26 | }; 27 | 28 | private static readonly string[] filesBySize = new string[] { 29 | "fileA.jpg", 30 | "FileB.txt", 31 | "fileA.html", 32 | "FileD.gif", 33 | "FileF.txt", 34 | "FileC.xml", 35 | "FileE.dat", 36 | "FileA.json", 37 | "FileA.txt" 38 | }; 39 | 40 | private static readonly string[] filesByCreationDate = new string[] { 41 | "FileC.xml", 42 | "FileA.txt", 43 | "FileB.txt", 44 | "fileA.html", 45 | "FileF.txt", 46 | "fileA.jpg", 47 | "FileD.gif", 48 | "FileE.dat", 49 | "FileA.json" 50 | }; 51 | 52 | private static readonly string[] filesByModifyDate = new string[] { 53 | "FileD.gif", 54 | "FileF.txt", 55 | "FileC.xml", 56 | "FileB.txt", 57 | "fileA.jpg", 58 | "FileA.json", 59 | "fileA.html", 60 | "FileA.txt", 61 | "FileE.dat" 62 | }; 63 | 64 | private void AssertResults8Asc(string[] ex, Result r) 65 | { 66 | Assert.AreEqual(8u, r.NumItems); 67 | Assert.AreEqual(9, ex.Length); 68 | 69 | Assert.AreEqual(ex[0], r.Items[0].Name); 70 | Assert.AreEqual(ex[1], r.Items[1].Name); 71 | Assert.AreEqual(ex[2], r.Items[2].Name); 72 | Assert.AreEqual(ex[3], r.Items[3].Name); 73 | Assert.AreEqual(ex[4], r.Items[4].Name); 74 | Assert.AreEqual(ex[5], r.Items[5].Name); 75 | Assert.AreEqual(ex[6], r.Items[6].Name); 76 | Assert.AreEqual(ex[7], r.Items[7].Name); 77 | } 78 | 79 | private void AssertResults8Desc(string[] ex, Result r) 80 | { 81 | Assert.AreEqual(8u, r.NumItems); 82 | Assert.AreEqual(9, ex.Length); 83 | 84 | Assert.AreEqual(ex[8], r.Items[0].Name); 85 | Assert.AreEqual(ex[7], r.Items[1].Name); 86 | Assert.AreEqual(ex[6], r.Items[2].Name); 87 | Assert.AreEqual(ex[5], r.Items[3].Name); 88 | Assert.AreEqual(ex[4], r.Items[4].Name); 89 | Assert.AreEqual(ex[3], r.Items[5].Name); 90 | Assert.AreEqual(ex[2], r.Items[6].Name); 91 | Assert.AreEqual(ex[1], r.Items[7].Name); 92 | } 93 | 94 | [TestMethod] 95 | public void TestSearchSortedNameAsc() 96 | { 97 | Result r = everything.Search( 98 | "File " + data.TestDataRootDirectory, 99 | maxResults: 8, 100 | sortBy: SearchClient.SortBy.Name, 101 | sortDirection: SearchClient.SortDirection.Ascending); 102 | Assert.AreEqual(8u, r.NumItems); 103 | Assert.AreEqual(9u, r.TotalItems); 104 | AssertResults8Asc(filesByName, r); 105 | } 106 | 107 | [TestMethod] 108 | public void TestSearchSortedNameDesc() 109 | { 110 | Result r = everything.Search( 111 | "File " + data.TestDataRootDirectory, 112 | maxResults: 8, 113 | sortBy: SearchClient.SortBy.Name, 114 | sortDirection: SearchClient.SortDirection.Decending); 115 | Assert.AreEqual(8, r.NumItems); 116 | Assert.AreEqual(9, r.TotalItems); 117 | AssertResults8Desc(filesByName, r); 118 | } 119 | 120 | [TestMethod] 121 | public void TestSearchSortedSizeAsc() 122 | { 123 | Result r = everything.Search( 124 | "File " + data.TestDataRootDirectory, 125 | maxResults: 8, 126 | sortBy: SearchClient.SortBy.Size, 127 | sortDirection: SearchClient.SortDirection.Ascending); 128 | Assert.AreEqual(8u, r.NumItems); 129 | Assert.AreEqual(9u, r.TotalItems); 130 | AssertResults8Asc(filesBySize, r); 131 | } 132 | 133 | [TestMethod] 134 | public void TestSearchSortedSizeDesc() 135 | { 136 | Result r = everything.Search( 137 | "File " + data.TestDataRootDirectory, 138 | maxResults: 8, 139 | sortBy: SearchClient.SortBy.Size, 140 | sortDirection: SearchClient.SortDirection.Decending); 141 | Assert.AreEqual(8, r.NumItems); 142 | Assert.AreEqual(9, r.TotalItems); 143 | AssertResults8Desc(filesBySize, r); 144 | } 145 | 146 | [TestMethod] 147 | public void TestSearchSortedDateCreatedAsc() 148 | { 149 | Result r = everything.Search( 150 | "File " + data.TestDataRootDirectory, 151 | maxResults: 8, 152 | sortBy: SearchClient.SortBy.DateCreated, 153 | sortDirection: SearchClient.SortDirection.Ascending); 154 | Assert.AreEqual(8u, r.NumItems); 155 | Assert.AreEqual(9u, r.TotalItems); 156 | AssertResults8Asc(filesByCreationDate, r); 157 | } 158 | 159 | [TestMethod] 160 | public void TestSearchSortedDateCreatedDesc() 161 | { 162 | Result r = everything.Search( 163 | "File " + data.TestDataRootDirectory, 164 | maxResults: 8, 165 | sortBy: SearchClient.SortBy.DateCreated, 166 | sortDirection: SearchClient.SortDirection.Decending); 167 | Assert.AreEqual(8, r.NumItems); 168 | Assert.AreEqual(9, r.TotalItems); 169 | AssertResults8Desc(filesByCreationDate, r); 170 | } 171 | 172 | [TestMethod] 173 | public void TestSearchSortedDateModifiedAsc() 174 | { 175 | Result r = everything.Search( 176 | "File " + data.TestDataRootDirectory, 177 | maxResults: 8, 178 | sortBy: SearchClient.SortBy.DateModified, 179 | sortDirection: SearchClient.SortDirection.Ascending); 180 | Assert.AreEqual(8u, r.NumItems); 181 | Assert.AreEqual(9u, r.TotalItems); 182 | AssertResults8Asc(filesByModifyDate, r); 183 | } 184 | 185 | [TestMethod] 186 | public void TestSearchSortedDateModifiedDesc() 187 | { 188 | Result r = everything.Search( 189 | "File " + data.TestDataRootDirectory, 190 | maxResults: 8, 191 | sortBy: SearchClient.SortBy.DateModified, 192 | sortDirection: SearchClient.SortDirection.Decending); 193 | Assert.AreEqual(8, r.NumItems); 194 | Assert.AreEqual(9, r.TotalItems); 195 | AssertResults8Desc(filesByModifyDate, r); 196 | } 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /TestProject/Usings.cs: -------------------------------------------------------------------------------- 1 | global using Microsoft.VisualStudio.TestTools.UnitTesting; --------------------------------------------------------------------------------