Enabling static analysis on indexer plugin and fixing errors (#5220)
* Enabling code analysis, and treating warnings as errors * Error CA1724 The type name Settings conflicts in whole or in part with the namespace name 'Microsoft.PowerToys.Settings'. Change either name to eliminate the conflict. Microsoft.Plugin.Indexer C:\repos\powertoys\src\modules\launcher\Plugins\Microsoft.Plugin.Indexer\Settings.cs 9 Active * Removing keyword "Interface" from namespace to fix fxcop warnings * Fixing static analysis warnings on ContextMenuLoader * Fixing general exception warnings for static analysis * Fixing public list variables, non static methods, and general exception warning * Implementing IDisposable on OleDBSearch although in practice these objects were already being disposed. Also Validated we were not using user input directly for sql strings. * Removing VS generated comments from dispose methods as per PR feedback. * Setting translated text to use current culture as per PR feedback. * Explicity specifying 'internal' access modifier for Indexer 'Main' class, as per PR feedback * Updating to FxCop 3.0.0
This commit is contained in:
parent
aa8c31e79b
commit
8f17f7297d
12 changed files with 287 additions and 215 deletions
|
@ -29,8 +29,9 @@ namespace Microsoft.Plugin.Indexer
|
|||
public ContextMenuLoader(PluginInitContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "We want to keep the process alive, and instead log and show an error message")]
|
||||
public List<ContextMenuResult> LoadContextMenus(Result selectedResult)
|
||||
{
|
||||
var contextMenus = new List<ContextMenuResult>();
|
||||
|
@ -111,6 +112,7 @@ namespace Microsoft.Plugin.Indexer
|
|||
}
|
||||
|
||||
// Function to add the context menu item to run as admin
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "We want to keep the process alive, and instead log the exeption message")]
|
||||
private ContextMenuResult CreateRunAsAdminContextMenu(SearchResult record)
|
||||
{
|
||||
return new ContextMenuResult
|
||||
|
@ -152,7 +154,7 @@ namespace Microsoft.Plugin.Indexer
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "We want to keep the process alive, and instead log and show an error message")]
|
||||
private ContextMenuResult CreateOpenContainingFolderResult(SearchResult record)
|
||||
{
|
||||
return new ContextMenuResult
|
||||
|
@ -182,7 +184,7 @@ namespace Microsoft.Plugin.Indexer
|
|||
};
|
||||
}
|
||||
|
||||
public void LogException(string message, Exception e)
|
||||
public static void LogException(string message, Exception e)
|
||||
{
|
||||
Log.Exception($"|Microsoft.Plugin.Folder.ContextMenu|{message}", e);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.Plugin.Indexer.DriveDetection;
|
||||
using Microsoft.Plugin.Indexer.Interface;
|
||||
|
||||
namespace Microsoft.Plugin.Indexer.DriveDetection
|
||||
namespace Microsoft.Plugin.Indexer.DriveDetection
|
||||
{
|
||||
public class IndexerDriveDetection
|
||||
{
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows.Input;
|
||||
using Microsoft.Plugin.Indexer.Interface;
|
||||
using Microsoft.Plugin.Indexer;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace Microsoft.Plugin.Indexer.DriveDetection
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Plugin.Indexer.Interface
|
||||
namespace Microsoft.Plugin.Indexer
|
||||
{
|
||||
public interface IRegistryWrapper
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using Microsoft.Plugin.Indexer.SearchHelper;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Plugin.Indexer.Interface
|
||||
namespace Microsoft.Plugin.Indexer
|
||||
{
|
||||
public interface ISearch
|
||||
{
|
||||
|
|
|
@ -1,37 +1,39 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Wox.Plugin;
|
||||
using System.IO;
|
||||
using System.ComponentModel;
|
||||
using Wox.Infrastructure.Storage;
|
||||
using Microsoft.Plugin.Indexer.SearchHelper;
|
||||
using Microsoft.Search.Interop;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Wox.Plugin;
|
||||
using System.IO;
|
||||
using System.ComponentModel;
|
||||
using Wox.Infrastructure.Storage;
|
||||
using Microsoft.Plugin.Indexer.SearchHelper;
|
||||
using Microsoft.Search.Interop;
|
||||
using Microsoft.PowerToys.Settings.UI.Lib;
|
||||
using System.Windows.Controls;
|
||||
using Wox.Infrastructure.Logger;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.Plugin.Indexer.DriveDetection;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Microsoft.Plugin.Indexer
|
||||
{
|
||||
class Main : ISettingProvider, IPlugin, ISavable, IPluginI18n, IContextMenu
|
||||
{
|
||||
|
||||
// This variable contains metadata about the Plugin
|
||||
private PluginInitContext _context;
|
||||
|
||||
// This variable contains information about the context menus
|
||||
private Settings _settings;
|
||||
|
||||
// Contains information about the plugin stored in json format
|
||||
private PluginJsonStorage<Settings> _storage;
|
||||
|
||||
// To access Windows Search functionalities
|
||||
private readonly WindowsSearchAPI _api = new WindowsSearchAPI(new OleDBSearch());
|
||||
namespace Microsoft.Plugin.Indexer
|
||||
{
|
||||
internal class Main : ISettingProvider, IPlugin, ISavable, IPluginI18n, IContextMenu, IDisposable
|
||||
{
|
||||
|
||||
// This variable contains metadata about the Plugin
|
||||
private PluginInitContext _context;
|
||||
|
||||
// This variable contains information about the context menus
|
||||
private IndexerSettings _settings;
|
||||
|
||||
// Contains information about the plugin stored in json format
|
||||
private PluginJsonStorage<IndexerSettings> _storage;
|
||||
|
||||
// To access Windows Search functionalities
|
||||
private static readonly OleDBSearch _search = new OleDBSearch();
|
||||
private readonly WindowsSearchAPI _api = new WindowsSearchAPI(_search);
|
||||
|
||||
// To obtain information regarding the drives that are indexed
|
||||
private readonly IndexerDriveDetection _driveDetection = new IndexerDriveDetection(new RegistryWrapper());
|
||||
|
@ -39,129 +41,132 @@ namespace Microsoft.Plugin.Indexer
|
|||
// Reserved keywords in oleDB
|
||||
private string ReservedStringPattern = @"^[\/\\\$\%]+$";
|
||||
private string WarningIconPath { get; set; }
|
||||
private IContextMenu _contextMenuLoader;
|
||||
private IContextMenu _contextMenuLoader;
|
||||
private bool disposedValue;
|
||||
|
||||
// To save the configurations of plugins
|
||||
public void Save()
|
||||
{
|
||||
_storage.Save();
|
||||
}
|
||||
|
||||
|
||||
// This function uses the Windows indexer and returns the list of results obtained
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "We want to keep the process alive but will log the exception")]
|
||||
public List<Result> Query(Query query)
|
||||
{
|
||||
var results = new List<Result>();
|
||||
|
||||
if (!string.IsNullOrEmpty(query.Search))
|
||||
{
|
||||
var searchQuery = query.Search;
|
||||
if (_settings.MaxSearchCount <= 0)
|
||||
{
|
||||
_settings.MaxSearchCount = 50;
|
||||
}
|
||||
|
||||
// To save the configurations of plugins
|
||||
public void Save()
|
||||
{
|
||||
_storage.Save();
|
||||
}
|
||||
var regexMatch = Regex.Match(searchQuery, ReservedStringPattern);
|
||||
|
||||
// This function uses the Windows indexer and returns the list of results obtained
|
||||
public List<Result> Query(Query query)
|
||||
{
|
||||
var results = new List<Result>();
|
||||
if (!regexMatch.Success)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(_driveDetection.DisplayWarning())
|
||||
{
|
||||
results.Add(new Result
|
||||
{
|
||||
Title = _context.API.GetTranslation("Microsoft_plugin_indexer_drivedetectionwarning"),
|
||||
SubTitle = _context.API.GetTranslation("Microsoft_plugin_indexer_disable_warning_in_settings"),
|
||||
IcoPath = WarningIconPath,
|
||||
Action = e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Process.Start(GetWindowsSearchSettingsProcessInfo());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Exception("Microsoft.Plugin.Indexer", $"Unable to launch Windows Search Settings: {ex.Message}", ex, "Query");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(query.Search))
|
||||
{
|
||||
var searchQuery = query.Search;
|
||||
if (_settings.MaxSearchCount <= 0)
|
||||
{
|
||||
_settings.MaxSearchCount = 50;
|
||||
}
|
||||
|
||||
var regexMatch = Regex.Match(searchQuery, ReservedStringPattern);
|
||||
|
||||
if (!regexMatch.Success)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(_driveDetection.DisplayWarning())
|
||||
{
|
||||
results.Add(new Result
|
||||
{
|
||||
Title = _context.API.GetTranslation("Microsoft_plugin_indexer_drivedetectionwarning"),
|
||||
SubTitle = _context.API.GetTranslation("Microsoft_plugin_indexer_disable_warning_in_settings"),
|
||||
IcoPath = WarningIconPath,
|
||||
Action = e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Process.Start(GetWindowsSearchSettingsProcessInfo());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Exception("Microsoft.Plugin.Indexer", $"Unable to launch Windows Search Settings: {ex.Message}", ex, "Query");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var searchResultsList = _api.Search(searchQuery, maxCount: _settings.MaxSearchCount).ToList();
|
||||
foreach (var searchResult in searchResultsList)
|
||||
{
|
||||
var path = searchResult.Path;
|
||||
var toolTipTitle = string.Format("{0} : {1}", _context.API.GetTranslation("Microsoft_plugin_indexer_name"), searchResult.Title);
|
||||
var toolTipText = string.Format("{0} : {1}", _context.API.GetTranslation("Microsoft_plugin_indexer_path"), path);
|
||||
string workingDir = null;
|
||||
if (_settings.UseLocationAsWorkingDir)
|
||||
workingDir = Path.GetDirectoryName(path);
|
||||
|
||||
Result r = new Result();
|
||||
r.Title = searchResult.Title;
|
||||
r.SubTitle = "Search: " + path;
|
||||
r.IcoPath = path;
|
||||
r.ToolTipData = new ToolTipData(toolTipTitle, toolTipText);
|
||||
r.Action = c =>
|
||||
{
|
||||
bool hide;
|
||||
try
|
||||
{
|
||||
Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = path,
|
||||
UseShellExecute = true,
|
||||
WorkingDirectory = workingDir
|
||||
});
|
||||
hide = true;
|
||||
}
|
||||
catch (Win32Exception)
|
||||
{
|
||||
var name = $"Plugin: {_context.CurrentPluginMetadata.Name}";
|
||||
var msg = "Can't Open this file";
|
||||
_context.API.ShowMsg(name, msg, string.Empty);
|
||||
hide = false;
|
||||
}
|
||||
return hide;
|
||||
};
|
||||
r.ContextData = searchResult;
|
||||
|
||||
//If the result is a directory, then it's display should show a directory.
|
||||
if (Directory.Exists(path))
|
||||
{
|
||||
r.QueryTextDisplay = path;
|
||||
}
|
||||
|
||||
results.Add(r);
|
||||
}
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
//The connection has closed, internal error of ExecuteReader()
|
||||
//Not showing this exception to the users
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Info(ex.ToString());
|
||||
var searchResultsList = _api.Search(searchQuery, maxCount: _settings.MaxSearchCount).ToList();
|
||||
foreach (var searchResult in searchResultsList)
|
||||
{
|
||||
var path = searchResult.Path;
|
||||
var toolTipTitle = string.Format(CultureInfo.CurrentCulture, "{0} : {1}", _context.API.GetTranslation("Microsoft_plugin_indexer_name"), searchResult.Title);
|
||||
var toolTipText = string.Format(CultureInfo.CurrentCulture, "{0} : {1}", _context.API.GetTranslation("Microsoft_plugin_indexer_path"), path);
|
||||
string workingDir = null;
|
||||
if (_settings.UseLocationAsWorkingDir)
|
||||
workingDir = Path.GetDirectoryName(path);
|
||||
|
||||
Result r = new Result();
|
||||
r.Title = searchResult.Title;
|
||||
r.SubTitle = "Search: " + path;
|
||||
r.IcoPath = path;
|
||||
r.ToolTipData = new ToolTipData(toolTipTitle, toolTipText);
|
||||
r.Action = c =>
|
||||
{
|
||||
bool hide;
|
||||
try
|
||||
{
|
||||
Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = path,
|
||||
UseShellExecute = true,
|
||||
WorkingDirectory = workingDir
|
||||
});
|
||||
hide = true;
|
||||
}
|
||||
catch (Win32Exception)
|
||||
{
|
||||
var name = $"Plugin: {_context.CurrentPluginMetadata.Name}";
|
||||
var msg = "Can't Open this file";
|
||||
_context.API.ShowMsg(name, msg, string.Empty);
|
||||
hide = false;
|
||||
}
|
||||
return hide;
|
||||
};
|
||||
r.ContextData = searchResult;
|
||||
|
||||
//If the result is a directory, then it's display should show a directory.
|
||||
if (Directory.Exists(path))
|
||||
{
|
||||
r.QueryTextDisplay = path;
|
||||
}
|
||||
|
||||
results.Add(r);
|
||||
}
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
//The connection has closed, internal error of ExecuteReader()
|
||||
//Not showing this exception to the users
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Info(ex.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public void Init(PluginInitContext context)
|
||||
{
|
||||
// initialize the context of the plugin
|
||||
_context = context;
|
||||
_contextMenuLoader = new ContextMenuLoader(context);
|
||||
_storage = new PluginJsonStorage<Settings>();
|
||||
_settings = _storage.Load();
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public void Init(PluginInitContext context)
|
||||
{
|
||||
// initialize the context of the plugin
|
||||
_context = context;
|
||||
_contextMenuLoader = new ContextMenuLoader(context);
|
||||
_storage = new PluginJsonStorage<IndexerSettings>();
|
||||
_settings = _storage.Load();
|
||||
_context.API.ThemeChanged += OnThemeChanged;
|
||||
UpdateIconPath(_context.API.GetCurrentTheme());
|
||||
}
|
||||
|
||||
UpdateIconPath(_context.API.GetCurrentTheme());
|
||||
}
|
||||
|
||||
// Todo : Update with theme based IconPath
|
||||
private void UpdateIconPath(Theme theme)
|
||||
{
|
||||
|
@ -178,25 +183,25 @@ namespace Microsoft.Plugin.Indexer
|
|||
private void OnThemeChanged(Theme _, Theme newTheme)
|
||||
{
|
||||
UpdateIconPath(newTheme);
|
||||
}
|
||||
|
||||
// TODO: Localize the strings
|
||||
// Set the Plugin Title
|
||||
public string GetTranslatedPluginTitle()
|
||||
{
|
||||
return "Windows Indexer Plugin";
|
||||
}
|
||||
|
||||
// TODO: Localize the string
|
||||
// Set the plugin Description
|
||||
public string GetTranslatedPluginDescription()
|
||||
{
|
||||
return "Returns files and folders";
|
||||
}
|
||||
|
||||
public List<ContextMenuResult> LoadContextMenus(Result selectedResult)
|
||||
{
|
||||
return _contextMenuLoader.LoadContextMenus(selectedResult);
|
||||
// TODO: Localize the strings
|
||||
// Set the Plugin Title
|
||||
public string GetTranslatedPluginTitle()
|
||||
{
|
||||
return "Windows Indexer Plugin";
|
||||
}
|
||||
|
||||
// TODO: Localize the string
|
||||
// Set the plugin Description
|
||||
public string GetTranslatedPluginDescription()
|
||||
{
|
||||
return "Returns files and folders";
|
||||
}
|
||||
|
||||
public List<ContextMenuResult> LoadContextMenus(Result selectedResult)
|
||||
{
|
||||
return _contextMenuLoader.LoadContextMenus(selectedResult);
|
||||
}
|
||||
public void UpdateSettings(PowerLauncherSettings settings)
|
||||
{
|
||||
|
@ -209,7 +214,7 @@ namespace Microsoft.Plugin.Indexer
|
|||
}
|
||||
|
||||
// Returns the Process Start Information for the new Windows Search Settings
|
||||
public ProcessStartInfo GetWindowsSearchSettingsProcessInfo()
|
||||
public static ProcessStartInfo GetWindowsSearchSettingsProcessInfo()
|
||||
{
|
||||
var ps = new ProcessStartInfo("ms-settings:cortana-windowssearch")
|
||||
{
|
||||
|
@ -218,7 +223,26 @@ namespace Microsoft.Plugin.Indexer
|
|||
};
|
||||
|
||||
return ps;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_search.Dispose();
|
||||
}
|
||||
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Optimize>false</Optimize>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
@ -38,6 +39,10 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.Data.OleDb" Version="4.7.1" />
|
||||
<PackageReference Include="tlbimp-Microsoft.Search.Interop" Version="1.0.0">
|
||||
<NoWarn>NU1701</NoWarn>
|
||||
|
|
|
@ -8,11 +8,11 @@ namespace Microsoft.Plugin.Indexer.SearchHelper
|
|||
{
|
||||
public class OleDBResult
|
||||
{
|
||||
public List<object> fieldData;
|
||||
public List<object> FieldData { get; }
|
||||
|
||||
public OleDBResult(List<object> fieldData)
|
||||
{
|
||||
this.fieldData = fieldData;
|
||||
FieldData = fieldData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
using Microsoft.Plugin.Indexer.Interface;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.OleDb;
|
||||
|
||||
namespace Microsoft.Plugin.Indexer.SearchHelper
|
||||
{
|
||||
public class OleDBSearch : ISearch
|
||||
public class OleDBSearch : ISearch, IDisposable
|
||||
{
|
||||
private OleDbCommand command;
|
||||
private OleDbConnection conn;
|
||||
private OleDbDataReader WDSResults;
|
||||
|
||||
private OleDbDataReader WDSResults;
|
||||
private bool disposedValue;
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Security", "CA2100:Review SQL queries for security vulnerabilities",
|
||||
Justification = "sqlQuery does not come from user input but is generated via the ISearchQueryHelper::GenerateSqlFromUserQuery " +
|
||||
" see: https://docs.microsoft.com/en-us/windows/win32/search/-search-3x-wds-qryidx-searchqueryhelper#using-the-generatesqlfromuserquery-method")]
|
||||
public List<OleDBResult> Query(string connectionString, string sqlQuery)
|
||||
{
|
||||
List<OleDBResult> result = new List<OleDBResult>();
|
||||
|
@ -75,6 +78,37 @@ namespace Microsoft.Plugin.Indexer.SearchHelper
|
|||
}
|
||||
|
||||
return commandDisposed && resultDisposed && connDisposed;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
command?.Dispose();
|
||||
conn?.Dispose();
|
||||
WDSResults?.Dispose();
|
||||
}
|
||||
|
||||
// TODO: free unmanaged resources (unmanaged objects) and override finalizer
|
||||
// TODO: set large fields to null
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
// // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources
|
||||
// ~OleDBSearch()
|
||||
// {
|
||||
// // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
// Dispose(disposing: false);
|
||||
// }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Plugin.Indexer.Interface;
|
||||
using Microsoft.Search.Interop;
|
||||
|
||||
namespace Microsoft.Plugin.Indexer.SearchHelper
|
||||
|
@ -21,6 +20,11 @@ namespace Microsoft.Plugin.Indexer.SearchHelper
|
|||
|
||||
public List<SearchResult> ExecuteQuery(ISearchQueryHelper queryHelper, string keyword)
|
||||
{
|
||||
if(queryHelper == null)
|
||||
{
|
||||
throw new ArgumentNullException(paramName: nameof(queryHelper));
|
||||
}
|
||||
|
||||
List<SearchResult> _Result = new List<SearchResult>();
|
||||
|
||||
// Generate SQL from our parameters, converting the userQuery from AQS->WHERE clause
|
||||
|
@ -32,21 +36,21 @@ namespace Microsoft.Plugin.Indexer.SearchHelper
|
|||
// Loop over all records from the database
|
||||
foreach (OleDBResult oleDBResult in oleDBResults)
|
||||
{
|
||||
if (oleDBResult.fieldData[0] == DBNull.Value || oleDBResult.fieldData[1] == DBNull.Value || oleDBResult.fieldData[2] == DBNull.Value)
|
||||
if (oleDBResult.FieldData[0] == DBNull.Value || oleDBResult.FieldData[1] == DBNull.Value || oleDBResult.FieldData[2] == DBNull.Value)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
UInt32 fileAttributes = (UInt32)((Int64)oleDBResult.fieldData[2]);
|
||||
UInt32 fileAttributes = (UInt32)((Int64)oleDBResult.FieldData[2]);
|
||||
bool isFileHidden = (fileAttributes & FILE_ATTRIBUTE_HIDDEN) == FILE_ATTRIBUTE_HIDDEN;
|
||||
|
||||
if (DisplayHiddenFiles || !isFileHidden)
|
||||
{
|
||||
var uri_path = new Uri((string)oleDBResult.fieldData[0]);
|
||||
var uri_path = new Uri((string)oleDBResult.FieldData[0]);
|
||||
var result = new SearchResult
|
||||
{
|
||||
Path = uri_path.LocalPath,
|
||||
Title = (string)oleDBResult.fieldData[1]
|
||||
Title = (string)oleDBResult.FieldData[1]
|
||||
};
|
||||
_Result.Add(result);
|
||||
}
|
||||
|
@ -56,15 +60,25 @@ namespace Microsoft.Plugin.Indexer.SearchHelper
|
|||
}
|
||||
|
||||
|
||||
public void ModifyQueryHelper(ref ISearchQueryHelper queryHelper, string pattern)
|
||||
public static void ModifyQueryHelper(ref ISearchQueryHelper queryHelper, string pattern)
|
||||
{
|
||||
if(pattern == null)
|
||||
{
|
||||
throw new ArgumentNullException(paramName: nameof(pattern));
|
||||
}
|
||||
|
||||
if (queryHelper == null)
|
||||
{
|
||||
throw new ArgumentNullException(paramName: nameof(queryHelper));
|
||||
}
|
||||
|
||||
// convert file pattern if it is not '*'. Don't create restriction for '*' as it includes all files.
|
||||
if (pattern != "*")
|
||||
{
|
||||
pattern = pattern.Replace("*", "%");
|
||||
pattern = pattern.Replace("?", "_");
|
||||
pattern = pattern.Replace("*", "%", StringComparison.InvariantCulture);
|
||||
pattern = pattern.Replace("?", "_", StringComparison.InvariantCulture);
|
||||
|
||||
if (pattern.Contains("%") || pattern.Contains("_"))
|
||||
if (pattern.Contains("%", StringComparison.InvariantCulture) || pattern.Contains("_", StringComparison.InvariantCulture))
|
||||
{
|
||||
queryHelper.QueryWhereRestrictions += " AND System.FileName LIKE '" + pattern + "' ";
|
||||
}
|
||||
|
@ -76,7 +90,7 @@ namespace Microsoft.Plugin.Indexer.SearchHelper
|
|||
}
|
||||
}
|
||||
|
||||
public void InitQueryHelper(out ISearchQueryHelper queryHelper, int maxCount)
|
||||
public static void InitQueryHelper(out ISearchQueryHelper queryHelper, int maxCount)
|
||||
{
|
||||
// This uses the Microsoft.Search.Interop assembly
|
||||
CSearchManager manager = new CSearchManager();
|
||||
|
|
|
@ -6,9 +6,9 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace Microsoft.Plugin.Indexer
|
||||
{
|
||||
public class Settings
|
||||
public class IndexerSettings
|
||||
{
|
||||
public List<ContextMenu> ContextMenus = new List<ContextMenu>();
|
||||
public List<ContextMenu> ContextMenus { get; } = new List<ContextMenu>();
|
||||
public int MaxSearchCount { get; set; } = 100;
|
||||
public bool UseLocationAsWorkingDir { get; set; } = false;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using Microsoft.Search.Interop;
|
||||
using Microsoft.Plugin.Indexer.SearchHelper;
|
||||
using Microsoft.Plugin.Indexer.Interface;
|
||||
using Microsoft.Plugin.Indexer;
|
||||
using Moq;
|
||||
using Wox.Plugin;
|
||||
|
@ -33,7 +32,7 @@ namespace Wox.Test.Plugins
|
|||
ISearchQueryHelper queryHelper = null;
|
||||
|
||||
// Act
|
||||
_api.InitQueryHelper(out queryHelper, maxCount);
|
||||
WindowsSearchAPI.InitQueryHelper(out queryHelper, maxCount);
|
||||
|
||||
// Assert
|
||||
Assert.IsNotNull(queryHelper);
|
||||
|
@ -47,10 +46,10 @@ namespace Wox.Test.Plugins
|
|||
ISearchQueryHelper queryHelper;
|
||||
String pattern = "*";
|
||||
WindowsSearchAPI _api = GetWindowsSearchAPI();
|
||||
_api.InitQueryHelper(out queryHelper, 10);
|
||||
WindowsSearchAPI.InitQueryHelper(out queryHelper, 10);
|
||||
|
||||
// Act
|
||||
_api.ModifyQueryHelper(ref queryHelper, pattern);
|
||||
WindowsSearchAPI.ModifyQueryHelper(ref queryHelper, pattern);
|
||||
|
||||
// Assert
|
||||
Assert.IsFalse(queryHelper.QueryWhereRestrictions.Contains("LIKE"));
|
||||
|
@ -64,10 +63,10 @@ namespace Wox.Test.Plugins
|
|||
ISearchQueryHelper queryHelper;
|
||||
String pattern = "tt*^&)";
|
||||
WindowsSearchAPI _api = GetWindowsSearchAPI();
|
||||
_api.InitQueryHelper(out queryHelper, 10);
|
||||
WindowsSearchAPI.InitQueryHelper(out queryHelper, 10);
|
||||
|
||||
// Act
|
||||
_api.ModifyQueryHelper(ref queryHelper, pattern);
|
||||
WindowsSearchAPI.ModifyQueryHelper(ref queryHelper, pattern);
|
||||
|
||||
// Assert
|
||||
Assert.IsTrue(queryHelper.QueryWhereRestrictions.Contains("LIKE"));
|
||||
|
@ -81,10 +80,10 @@ namespace Wox.Test.Plugins
|
|||
ISearchQueryHelper queryHelper;
|
||||
String pattern = "tt%^&)";
|
||||
WindowsSearchAPI _api = GetWindowsSearchAPI();
|
||||
_api.InitQueryHelper(out queryHelper, 10);
|
||||
WindowsSearchAPI.InitQueryHelper(out queryHelper, 10);
|
||||
|
||||
// Act
|
||||
_api.ModifyQueryHelper(ref queryHelper, pattern);
|
||||
WindowsSearchAPI.ModifyQueryHelper(ref queryHelper, pattern);
|
||||
|
||||
// Assert
|
||||
Assert.IsTrue(queryHelper.QueryWhereRestrictions.Contains("LIKE"));
|
||||
|
@ -98,10 +97,10 @@ namespace Wox.Test.Plugins
|
|||
ISearchQueryHelper queryHelper;
|
||||
String pattern = "tt_^&)";
|
||||
WindowsSearchAPI _api = GetWindowsSearchAPI();
|
||||
_api.InitQueryHelper(out queryHelper, 10);
|
||||
WindowsSearchAPI.InitQueryHelper(out queryHelper, 10);
|
||||
|
||||
// Act
|
||||
_api.ModifyQueryHelper(ref queryHelper, pattern);
|
||||
WindowsSearchAPI.ModifyQueryHelper(ref queryHelper, pattern);
|
||||
|
||||
// Assert
|
||||
Assert.IsTrue(queryHelper.QueryWhereRestrictions.Contains("LIKE"));
|
||||
|
@ -115,10 +114,10 @@ namespace Wox.Test.Plugins
|
|||
ISearchQueryHelper queryHelper;
|
||||
String pattern = "tt?^&)";
|
||||
WindowsSearchAPI _api = GetWindowsSearchAPI();
|
||||
_api.InitQueryHelper(out queryHelper, 10);
|
||||
WindowsSearchAPI.InitQueryHelper(out queryHelper, 10);
|
||||
|
||||
// Act
|
||||
_api.ModifyQueryHelper(ref queryHelper, pattern);
|
||||
WindowsSearchAPI.ModifyQueryHelper(ref queryHelper, pattern);
|
||||
|
||||
// Assert
|
||||
Assert.IsTrue(queryHelper.QueryWhereRestrictions.Contains("LIKE"));
|
||||
|
@ -132,10 +131,10 @@ namespace Wox.Test.Plugins
|
|||
ISearchQueryHelper queryHelper;
|
||||
String pattern = "tt^&)bc";
|
||||
WindowsSearchAPI _api = GetWindowsSearchAPI();
|
||||
_api.InitQueryHelper(out queryHelper, 10);
|
||||
WindowsSearchAPI.InitQueryHelper(out queryHelper, 10);
|
||||
|
||||
// Act
|
||||
_api.ModifyQueryHelper(ref queryHelper, pattern);
|
||||
WindowsSearchAPI.ModifyQueryHelper(ref queryHelper, pattern);
|
||||
|
||||
// Assert
|
||||
Assert.IsFalse(queryHelper.QueryWhereRestrictions.Contains("LIKE"));
|
||||
|
|
Loading…
Reference in a new issue