├── .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 | [](https://github.com/sgrottel/EverythingSearchClient/actions/workflows/dotnet-desktop.yml)
5 | [](https://www.nuget.org/packages/EverythingSearchClient)
6 | [](./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;
--------------------------------------------------------------------------------