using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using AxCopilot.SDK; using AxCopilot.Services; namespace AxCopilot.Handlers; public class EverythingHandler : IActionHandler { private const int EVERYTHING_OK = 0; private const int EVERYTHING_REQUEST_FILE_NAME = 1; private const int EVERYTHING_REQUEST_PATH = 2; private const int EVERYTHING_REQUEST_SIZE = 16; private bool? _isAvailable; public string? Prefix => "es"; public PluginMetadata Metadata => new PluginMetadata("EverythingSearch", "Everything 초고속 파일 검색 — es [키워드]", "1.0", "AX"); private bool IsAvailable { get { if (_isAvailable.HasValue) { return _isAvailable.Value; } try { Everything_GetMajorVersion(); _isAvailable = true; } catch { _isAvailable = false; } return _isAvailable.Value; } } [DllImport("Everything64.dll", CharSet = CharSet.Unicode)] private static extern uint Everything_SetSearchW(string lpSearchString); [DllImport("Everything64.dll")] private static extern void Everything_SetMax(uint dwMax); [DllImport("Everything64.dll")] private static extern void Everything_SetRequestFlags(uint dwRequestFlags); [DllImport("Everything64.dll")] private static extern bool Everything_QueryW(bool bWait); [DllImport("Everything64.dll")] private static extern uint Everything_GetNumResults(); [DllImport("Everything64.dll")] private static extern uint Everything_GetLastError(); [DllImport("Everything64.dll", CharSet = CharSet.Unicode)] private static extern nint Everything_GetResultFullPathNameW(uint nIndex, nint lpString, uint nMaxCount); [DllImport("Everything64.dll", CharSet = CharSet.Unicode)] private static extern void Everything_GetResultSize(uint nIndex, out long lpFileSize); [DllImport("Everything64.dll")] private static extern uint Everything_GetMajorVersion(); public Task> GetItemsAsync(string query, CancellationToken ct) { if (!IsAvailable) { return Task.FromResult((IEnumerable)new LauncherItem[1] { new LauncherItem("Everything이 설치되어 있지 않습니다", "voidtools.com에서 Everything을 설치하면 초고속 파일 검색을 사용할 수 있습니다", null, null, null, "\ue7ba") }); } string text = query.Trim(); if (string.IsNullOrWhiteSpace(text)) { return Task.FromResult((IEnumerable)new LauncherItem[1] { new LauncherItem("Everything 파일 검색", "검색어를 입력하세요 — 파일명, 확장자(*.xlsx), 경로 일부 등", null, null, null, "\ue721") }); } try { Everything_SetSearchW(text); Everything_SetMax(30u); Everything_SetRequestFlags(19u); if (!Everything_QueryW(bWait: true)) { return Task.FromResult((IEnumerable)new LauncherItem[1] { new LauncherItem("Everything 검색 실패", $"오류 코드: {Everything_GetLastError()} — Everything 서비스가 실행 중인지 확인하세요", null, null, null, "\ue7ba") }); } uint num = Everything_GetNumResults(); if (num == 0) { return Task.FromResult((IEnumerable)new LauncherItem[1] { new LauncherItem("검색 결과 없음: " + text, "다른 키워드나 와일드카드(*.xlsx)를 시도해 보세요", null, null, null, "\ue946") }); } List list = new List(); nint num2 = Marshal.AllocHGlobal(1040); try { for (uint num3 = 0u; num3 < num && num3 < 30; num3++) { Everything_GetResultFullPathNameW(num3, num2, 520u); string text2 = Marshal.PtrToStringUni(num2) ?? ""; Everything_GetResultSize(num3, out var lpFileSize); string fileName = Path.GetFileName(text2); string text3 = Path.GetDirectoryName(text2) ?? ""; string text4 = ((lpFileSize > 0) ? FormatSize(lpFileSize) : ""); string subtitle = (string.IsNullOrEmpty(text4) ? text3 : (text4 + " · " + text3)); string symbol = (Directory.Exists(text2) ? "\ue8b7" : GetFileSymbol(text2)); list.Add(new LauncherItem(fileName, subtitle, null, text2, null, symbol)); } } finally { Marshal.FreeHGlobal(num2); } return Task.FromResult((IEnumerable)list); } catch (Exception ex) { LogService.Warn("Everything 검색 오류: " + ex.Message); return Task.FromResult((IEnumerable)new LauncherItem[1] { new LauncherItem("Everything 검색 오류", ex.Message, null, null, null, "\ue7ba") }); } } public async Task ExecuteAsync(LauncherItem item, CancellationToken ct) { object data = item.Data; string path = data as string; if (path == null || string.IsNullOrEmpty(path)) { return; } try { if (Directory.Exists(path)) { Process.Start(new ProcessStartInfo { FileName = path, UseShellExecute = true }); } else if (File.Exists(path)) { Process.Start(new ProcessStartInfo { FileName = path, UseShellExecute = true }); } } catch (Exception ex) { Exception ex2 = ex; LogService.Warn("Everything 결과 열기 실패: " + ex2.Message); } await Task.CompletedTask; } private static string FormatSize(long bytes) { if (bytes >= 1024) { if (bytes >= 1048576) { if (bytes >= 1073741824) { return $"{(double)bytes / 1073741824.0:F2} GB"; } return $"{(double)bytes / 1048576.0:F1} MB"; } return $"{(double)bytes / 1024.0:F1} KB"; } return $"{bytes} B"; } private static string GetFileSymbol(string path) { string text = Path.GetExtension(path).ToLowerInvariant(); if (1 == 0) { } string result; switch (text) { case ".xlsx": case ".xls": case ".csv": result = "\ue9f9"; break; case ".docx": case ".doc": result = "\ue8a5"; break; case ".pptx": case ".ppt": result = "\uee71"; break; case ".pdf": result = "\uea90"; break; case ".png": case ".jpg": case ".jpeg": case ".gif": case ".bmp": case ".svg": result = "\ueb9f"; break; case ".mp4": case ".avi": case ".mkv": case ".mov": result = "\ue714"; break; case ".mp3": case ".wav": case ".flac": result = "\uec4f"; break; case ".zip": case ".rar": case ".7z": case ".tar": case ".gz": result = "\ue8c6"; break; case ".exe": case ".msi": result = "\uecaa"; break; case ".cs": case ".py": case ".js": case ".ts": case ".java": case ".cpp": case ".c": case ".go": result = "\ue943"; break; case ".json": case ".xml": case ".yaml": case ".yml": result = "\ue713"; break; case ".txt": case ".md": case ".log": result = "\ue8d2"; break; case ".html": case ".htm": case ".css": result = "\ue774"; break; default: result = "\ue8a5"; break; } if (1 == 0) { } return result; } }