/// <summary> /// Performs a full-text search against the Windows Search Index, by a given file system <paramref name="path"/> /// and <paramref name="sqlQuery"/> string. /// </summary> /// <param name="path">A path in the local file system.</param> /// <param name="sqlQuery">Valid SQL query.</param> /// <param name="progress">Optionally provide an <see cref="IProgress{T}"/> object to view progress output.</param> public static List <SearchResult> PerformQuery(string path, string sqlQuery, IProgress <string> progress = null) { using (var session = new WindowsSearchSession(path)) { var startTicks = Environment.TickCount; var ticksToFirstRead = 0; List <SearchResult> rows; using (var reader = session.Query(sqlQuery)) { //reader.WriteColumnNamesToCsv(Console.Out); // Need unchecked because tickcount can wrap around - nevertheless it still generates a valid result unchecked { ticksToFirstRead = Environment.TickCount - startTicks; } rows = reader.OutputRowsToSearchResults(); var output = $"{rows.Count} rows."; progress?.Report(output); Debug.WriteLine(output); } int elapsedTicks; unchecked { elapsedTicks = Environment.TickCount - startTicks; } progress?.Report($"{ticksToFirstRead / 1000:d}.{ticksToFirstRead % 1000:d3} until first read."); Debug.WriteLine($"{ticksToFirstRead / 1000:d}.{ticksToFirstRead % 1000:d3} until first read."); progress?.Report($"{elapsedTicks / 1000:d}.{elapsedTicks % 1000:d3} seconds elapsed."); Debug.WriteLine($"{elapsedTicks / 1000:d}.{elapsedTicks % 1000:d3} seconds elapsed."); return(rows); } }
static void Main(string[] args) { bool writeSyntax = false; bool writeAllTags = false; string libraryPath = null; string matchPath = null; string dumpPath = null; string tag = null; bool delsrc = false; string backupPath = null; bool simulate = false; try { for (int nArg = 0; nArg < args.Length; ++nArg) { switch (args[nArg].ToLower()) { case "-?": case "-h": writeSyntax = true; break; case "-lib": ++nArg; if (nArg >= args.Length) throw new ArgumentException("Command-Line Syntax Error: No value specified for '-lib'"); libraryPath = Path.GetFullPath(args[nArg]); if (!Directory.Exists(libraryPath)) { throw new ArgumentException(String.Format("Folder '{0}' not found.", libraryPath)); } break; case "-alltags": writeAllTags = true; break; case "-match": ++nArg; if (nArg >= args.Length) throw new ArgumentException("Command-Line Syntax Error: No value specified for '-match'"); matchPath = PhotoEnumerable.GetFullPath(args[nArg]); break; case "-tag": ++nArg; if (nArg >= args.Length) throw new ArgumentException("Command-Line Syntax Error: No value specified for '-tag'"); tag = args[nArg]; if (tag.IndexOfAny(s_invalidTagChars) >= 0) throw new ArgumentException("Prohibited character in tag."); break; case "-delsrc": delsrc = true; break; case "-backup": ++nArg; if (nArg >= args.Length) throw new ArgumentException("Command-Line Syntax Error: No value specified for '-backup'"); backupPath = PhotoEnumerable.GetFullPath(args[nArg]); break; case "-dump": ++nArg; if (nArg >= args.Length) throw new ArgumentException("Command-Line Syntax Error: No value specified for '-dump'"); dumpPath = PhotoEnumerable.GetFullPath(args[nArg]); break; case "-simulate": simulate = true; break; case "-verbose": s_verbose = true; break; default: throw new ArgumentException(string.Format("Unexpected command-line parameter '{0}'", args[nArg])); } } // Make sure only one command was specified { int nCommands = 0; if (writeAllTags) ++nCommands; if (matchPath != null) ++nCommands; if (dumpPath != null) ++nCommands; if (nCommands != 1) throw new ArgumentException(string.Format("Must specify one and only one command: alltags, match, or dump.")); } if (writeSyntax) { // Do nothing here } else if (writeAllTags) { using (WindowsSearchSession session = new WindowsSearchSession(libraryPath)) { Console.Error.WriteLine("All Tags:"); Console.Error.WriteLine(); string[] keywords = session.GetAllKeywords(); foreach (string keyword in keywords) { Console.WriteLine(keyword); } } } else if (matchPath != null) { // If a backup folder was specified. Create it if necessary. Make sure it is empty. if (backupPath != null) { if (!Directory.Exists(backupPath)) { Directory.CreateDirectory(backupPath); } else if (Directory.GetFileSystemEntries(backupPath).Length != 0) { throw new ArgumentException(string.Format("Backup folder '{0}' must be empty.", backupPath)); } } PhotoTagger tagger = new PhotoTagger(libraryPath); tagger.Verbose = s_verbose; tagger.Simulate = simulate; tagger.TagAllMatches(matchPath, tag, delsrc, backupPath); } else if (dumpPath != null) { PhotoTagger tagger = new PhotoTagger(libraryPath); tagger.Verbose = s_verbose; tagger.Dump(dumpPath, tag); } else { throw new ArgumentException("No operation option specified."); } } catch (Exception err) { #if DEBUG Console.Error.WriteLine(err.ToString()); #else Console.Error.WriteLine(err.Message); #endif Console.Error.WriteLine(); if (err is ArgumentException) Console.Error.Write("For syntax: FMAutoTagPhotos -h"); } if (writeSyntax) Console.Error.Write(c_syntax); if (Win32Interop.ConsoleHelper.IsSoleConsoleOwner) { Console.Error.WriteLine(); Console.Error.Write("Press any key to exit."); Console.ReadKey(true); } }