Skip to content

Commit 7f508fc

Browse files
elliotttateclaude
andcommitted
feat: Add Everything SDK3 (v1.5) support with fallback to SDK2
- Implement EverythingSdk3Service for Everything 1.5 integration - Add direct folder size query using Everything3_GetFolderSizeFromFilenameW() - Automatic detection and fallback: SDK3 -> SDK2 -> Windows Search - Update EverythingSearchService to try SDK3 first - Update EverythingSizeProvider to use SDK3 when available - Add proper error handling for missing SDK3 DLLs - Add documentation about SDK3 requirements - SDK3 provides significant performance improvements for folder size calculations Note: SDK3 DLLs must be obtained separately from https://github.com/voidtools/everything_sdk3 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 8790559 commit 7f508fc

File tree

9 files changed

+580
-13
lines changed

9 files changed

+580
-13
lines changed

src/Files.App/Files.App.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,15 @@
5959
<Content Include="7zArm64.dll">
6060
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
6161
</Content>
62+
<Content Include="Libraries\Everything32.dll">
63+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
64+
</Content>
6265
<Content Include="Libraries\Everything64.dll">
6366
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
6467
</Content>
68+
<Content Include="Libraries\EverythingARM64.dll">
69+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
70+
</Content>
6571
</ItemGroup>
6672

6773
<ItemGroup>
86 KB
Binary file not shown.
110 KB
Binary file not shown.
Lines changed: 317 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,317 @@
1+
// Copyright (c) Files Community
2+
// Licensed under the MIT License.
3+
4+
using System;
5+
using System.Runtime.InteropServices;
6+
using System.Text;
7+
using System.Threading;
8+
using System.Threading.Tasks;
9+
using Microsoft.Extensions.Logging;
10+
11+
namespace Files.App.Services.Search
12+
{
13+
/// <summary>
14+
/// Everything SDK3 (v1.5) implementation for improved performance
15+
/// </summary>
16+
internal sealed class EverythingSdk3Service : IDisposable
17+
{
18+
#region SDK3 Definitions
19+
20+
private const uint EVERYTHING3_OK = 0;
21+
private const uint EVERYTHING3_ERROR_OUT_OF_MEMORY = 0xE0000001;
22+
private const uint EVERYTHING3_ERROR_IPC_PIPE_NOT_FOUND = 0xE0000002;
23+
private const uint EVERYTHING3_ERROR_DISCONNECTED = 0xE0000003;
24+
private const uint EVERYTHING3_ERROR_INVALID_PARAMETER = 0xE0000004;
25+
private const uint EVERYTHING3_ERROR_BAD_REQUEST = 0xE0000005;
26+
private const uint EVERYTHING3_ERROR_CANCELLED = 0xE0000006;
27+
private const uint EVERYTHING3_ERROR_PROPERTY_NOT_FOUND = 0xE0000007;
28+
private const uint EVERYTHING3_ERROR_SERVER = 0xE0000008;
29+
private const uint EVERYTHING3_ERROR_INVALID_COMMAND = 0xE0000009;
30+
private const uint EVERYTHING3_ERROR_BAD_RESPONSE = 0xE000000A;
31+
private const uint EVERYTHING3_ERROR_INSUFFICIENT_BUFFER = 0xE000000B;
32+
private const uint EVERYTHING3_ERROR_SHUTDOWN = 0xE000000C;
33+
34+
// Property IDs
35+
private const uint EVERYTHING3_PROPERTY_SIZE = 0x00000001;
36+
private const uint EVERYTHING3_PROPERTY_DATE_MODIFIED = 0x00000002;
37+
private const uint EVERYTHING3_PROPERTY_DATE_CREATED = 0x00000003;
38+
private const uint EVERYTHING3_PROPERTY_ATTRIBUTES = 0x00000004;
39+
private const uint EVERYTHING3_PROPERTY_PATH = 0x00000005;
40+
private const uint EVERYTHING3_PROPERTY_NAME = 0x00000006;
41+
private const uint EVERYTHING3_PROPERTY_EXTENSION = 0x00000007;
42+
private const uint EVERYTHING3_PROPERTY_TYPE_NAME = 0x00000008;
43+
44+
// Result types
45+
private const uint EVERYTHING3_RESULT_TYPE_FILE = 1;
46+
private const uint EVERYTHING3_RESULT_TYPE_FOLDER = 2;
47+
48+
#endregion
49+
50+
#region P/Invoke Declarations
51+
52+
[DllImport("Everything3", CharSet = CharSet.Unicode)]
53+
private static extern IntPtr Everything3_ConnectW(string instance_name);
54+
55+
[DllImport("Everything3")]
56+
private static extern bool Everything3_DestroyClient(IntPtr client);
57+
58+
[DllImport("Everything3")]
59+
private static extern bool Everything3_ShutdownClient(IntPtr client);
60+
61+
[DllImport("Everything3", CharSet = CharSet.Unicode)]
62+
private static extern ulong Everything3_GetFolderSizeFromFilenameW(IntPtr client, string filename);
63+
64+
[DllImport("Everything3", CharSet = CharSet.Unicode)]
65+
private static extern IntPtr Everything3_CreateQuery(IntPtr client, string search_string);
66+
67+
[DllImport("Everything3")]
68+
private static extern bool Everything3_DestroyQuery(IntPtr query);
69+
70+
[DllImport("Everything3")]
71+
private static extern bool Everything3_SetMax(IntPtr query, uint max);
72+
73+
[DllImport("Everything3")]
74+
private static extern bool Everything3_SetOffset(IntPtr query, uint offset);
75+
76+
[DllImport("Everything3")]
77+
private static extern bool Everything3_SetRequestProperties(IntPtr query, uint property_ids, uint property_count);
78+
79+
[DllImport("Everything3")]
80+
private static extern bool Everything3_Execute(IntPtr query);
81+
82+
[DllImport("Everything3")]
83+
private static extern uint Everything3_GetCount(IntPtr query);
84+
85+
[DllImport("Everything3")]
86+
private static extern uint Everything3_GetResultType(IntPtr query, uint index);
87+
88+
[DllImport("Everything3", CharSet = CharSet.Unicode)]
89+
private static extern IntPtr Everything3_GetResultPathW(IntPtr query, uint index);
90+
91+
[DllImport("Everything3", CharSet = CharSet.Unicode)]
92+
private static extern IntPtr Everything3_GetResultNameW(IntPtr query, uint index);
93+
94+
[DllImport("Everything3")]
95+
private static extern ulong Everything3_GetResultSize(IntPtr query, uint index);
96+
97+
[DllImport("Everything3")]
98+
private static extern ulong Everything3_GetResultDateModified(IntPtr query, uint index);
99+
100+
[DllImport("Everything3")]
101+
private static extern ulong Everything3_GetResultDateCreated(IntPtr query, uint index);
102+
103+
[DllImport("Everything3")]
104+
private static extern uint Everything3_GetResultAttributes(IntPtr query, uint index);
105+
106+
[DllImport("Everything3")]
107+
private static extern uint Everything3_GetLastError();
108+
109+
#endregion
110+
111+
private IntPtr _client;
112+
private readonly object _lock = new object();
113+
private bool _disposed;
114+
115+
public bool IsConnected => _client != IntPtr.Zero;
116+
117+
public bool Connect()
118+
{
119+
lock (_lock)
120+
{
121+
if (_client != IntPtr.Zero)
122+
return true;
123+
124+
try
125+
{
126+
// Try to connect to unnamed instance first
127+
_client = Everything3_ConnectW(null);
128+
if (_client != IntPtr.Zero)
129+
{
130+
App.Logger?.LogInformation("[Everything SDK3] Connected to unnamed instance");
131+
return true;
132+
}
133+
134+
// Try to connect to 1.5a instance
135+
_client = Everything3_ConnectW("1.5a");
136+
if (_client != IntPtr.Zero)
137+
{
138+
App.Logger?.LogInformation("[Everything SDK3] Connected to 1.5a instance");
139+
return true;
140+
}
141+
142+
App.Logger?.LogWarning("[Everything SDK3] Failed to connect to Everything 1.5");
143+
return false;
144+
}
145+
catch (DllNotFoundException)
146+
{
147+
App.Logger?.LogInformation("[Everything SDK3] SDK3 DLL not found - Everything 1.5 not installed");
148+
return false;
149+
}
150+
catch (EntryPointNotFoundException)
151+
{
152+
App.Logger?.LogWarning("[Everything SDK3] SDK3 entry point not found - incompatible DLL");
153+
return false;
154+
}
155+
catch (Exception ex)
156+
{
157+
App.Logger?.LogError(ex, "[Everything SDK3] Error connecting to Everything 1.5");
158+
return false;
159+
}
160+
}
161+
}
162+
163+
public ulong GetFolderSize(string folderPath)
164+
{
165+
if (!IsConnected || string.IsNullOrEmpty(folderPath))
166+
return 0;
167+
168+
lock (_lock)
169+
{
170+
try
171+
{
172+
var size = Everything3_GetFolderSizeFromFilenameW(_client, folderPath);
173+
174+
// Check for errors (-1 indicates error)
175+
if (size == ulong.MaxValue)
176+
{
177+
var error = Everything3_GetLastError();
178+
App.Logger?.LogWarning($"[Everything SDK3] GetFolderSize failed for {folderPath}, error: 0x{error:X8}");
179+
return 0;
180+
}
181+
182+
App.Logger?.LogInformation($"[Everything SDK3] Got folder size for {folderPath}: {size} bytes");
183+
return size;
184+
}
185+
catch (Exception ex)
186+
{
187+
App.Logger?.LogError(ex, $"[Everything SDK3] Error getting folder size for {folderPath}");
188+
return 0;
189+
}
190+
}
191+
}
192+
193+
public async Task<List<(string Path, string Name, bool IsFolder, ulong Size, DateTime DateModified, DateTime DateCreated, uint Attributes)>> SearchAsync(
194+
string searchQuery,
195+
uint maxResults = 1000,
196+
CancellationToken cancellationToken = default)
197+
{
198+
if (!IsConnected || string.IsNullOrEmpty(searchQuery))
199+
return new List<(string, string, bool, ulong, DateTime, DateTime, uint)>();
200+
201+
return await Task.Run(() =>
202+
{
203+
lock (_lock)
204+
{
205+
IntPtr query = IntPtr.Zero;
206+
var results = new List<(string Path, string Name, bool IsFolder, ulong Size, DateTime DateModified, DateTime DateCreated, uint Attributes)>();
207+
208+
try
209+
{
210+
query = Everything3_CreateQuery(_client, searchQuery);
211+
if (query == IntPtr.Zero)
212+
{
213+
App.Logger?.LogWarning("[Everything SDK3] Failed to create query");
214+
return results;
215+
}
216+
217+
// Set max results
218+
Everything3_SetMax(query, maxResults);
219+
220+
// Request properties we need
221+
uint[] properties = {
222+
EVERYTHING3_PROPERTY_PATH,
223+
EVERYTHING3_PROPERTY_NAME,
224+
EVERYTHING3_PROPERTY_SIZE,
225+
EVERYTHING3_PROPERTY_DATE_MODIFIED,
226+
EVERYTHING3_PROPERTY_DATE_CREATED,
227+
EVERYTHING3_PROPERTY_ATTRIBUTES
228+
};
229+
230+
GCHandle propertiesHandle = GCHandle.Alloc(properties, GCHandleType.Pinned);
231+
try
232+
{
233+
Everything3_SetRequestProperties(query, (uint)propertiesHandle.AddrOfPinnedObject(), (uint)properties.Length);
234+
}
235+
finally
236+
{
237+
propertiesHandle.Free();
238+
}
239+
240+
// Execute query
241+
if (!Everything3_Execute(query))
242+
{
243+
var error = Everything3_GetLastError();
244+
App.Logger?.LogWarning($"[Everything SDK3] Query execution failed, error: 0x{error:X8}");
245+
return results;
246+
}
247+
248+
var count = Everything3_GetCount(query);
249+
App.Logger?.LogInformation($"[Everything SDK3] Query returned {count} results");
250+
251+
for (uint i = 0; i < count; i++)
252+
{
253+
if (cancellationToken.IsCancellationRequested)
254+
break;
255+
256+
try
257+
{
258+
var type = Everything3_GetResultType(query, i);
259+
var isFolder = type == EVERYTHING3_RESULT_TYPE_FOLDER;
260+
261+
var path = Marshal.PtrToStringUni(Everything3_GetResultPathW(query, i)) ?? string.Empty;
262+
var name = Marshal.PtrToStringUni(Everything3_GetResultNameW(query, i)) ?? string.Empty;
263+
var size = Everything3_GetResultSize(query, i);
264+
var dateModified = DateTime.FromFileTimeUtc((long)Everything3_GetResultDateModified(query, i));
265+
var dateCreated = DateTime.FromFileTimeUtc((long)Everything3_GetResultDateCreated(query, i));
266+
var attributes = Everything3_GetResultAttributes(query, i);
267+
268+
results.Add((path, name, isFolder, size, dateModified, dateCreated, attributes));
269+
}
270+
catch (Exception ex)
271+
{
272+
App.Logger?.LogError(ex, $"[Everything SDK3] Error processing result {i}");
273+
}
274+
}
275+
276+
return results;
277+
}
278+
catch (Exception ex)
279+
{
280+
App.Logger?.LogError(ex, "[Everything SDK3] Error during search");
281+
return results;
282+
}
283+
finally
284+
{
285+
if (query != IntPtr.Zero)
286+
Everything3_DestroyQuery(query);
287+
}
288+
}
289+
}, cancellationToken);
290+
}
291+
292+
public void Dispose()
293+
{
294+
lock (_lock)
295+
{
296+
if (_disposed)
297+
return;
298+
299+
if (_client != IntPtr.Zero)
300+
{
301+
try
302+
{
303+
Everything3_ShutdownClient(_client);
304+
Everything3_DestroyClient(_client);
305+
}
306+
catch (Exception ex)
307+
{
308+
App.Logger?.LogError(ex, "[Everything SDK3] Error during cleanup");
309+
}
310+
_client = IntPtr.Zero;
311+
}
312+
313+
_disposed = true;
314+
}
315+
}
316+
}
317+
}

0 commit comments

Comments
 (0)