using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using Wox.Infrastructure.Logger;
using Wox.Plugin.Everything.Everything.Exceptions;
namespace Wox.Plugin.Everything.Everything
{
public interface IEverythingApi
{
///
/// Searches the specified key word.
///
/// The key word.
/// token that allow cancellation
/// The offset.
/// The max count.
///
List Search(string keyWord, CancellationToken token, int offset = 0, int maxCount = 100);
void Load(string sdkPath);
}
public sealed class EverythingApi : IEverythingApi
{
private const int BufferSize = 4096;
private readonly object _syncObject = new object();
// cached buffer to remove redundant allocations.
private readonly StringBuilder _buffer = new StringBuilder(BufferSize);
public enum StateCode
{
OK,
MemoryError,
IPCError,
RegisterClassExError,
CreateWindowError,
CreateThreadError,
InvalidIndexError,
InvalidCallError
}
///
/// Gets or sets a value indicating whether [match path].
///
/// true if [match path]; otherwise, false.
public bool MatchPath
{
get
{
return EverythingApiDllImport.Everything_GetMatchPath();
}
set
{
EverythingApiDllImport.Everything_SetMatchPath(value);
}
}
///
/// Gets or sets a value indicating whether [match case].
///
/// true if [match case]; otherwise, false.
public bool MatchCase
{
get
{
return EverythingApiDllImport.Everything_GetMatchCase();
}
set
{
EverythingApiDllImport.Everything_SetMatchCase(value);
}
}
///
/// Gets or sets a value indicating whether [match whole word].
///
/// true if [match whole word]; otherwise, false.
public bool MatchWholeWord
{
get
{
return EverythingApiDllImport.Everything_GetMatchWholeWord();
}
set
{
EverythingApiDllImport.Everything_SetMatchWholeWord(value);
}
}
///
/// Gets or sets a value indicating whether [enable regex].
///
/// true if [enable regex]; otherwise, false.
public bool EnableRegex
{
get
{
return EverythingApiDllImport.Everything_GetRegex();
}
set
{
EverythingApiDllImport.Everything_SetRegex(value);
}
}
///
/// Resets this instance.
///
public void Reset()
{
lock (_syncObject)
{
EverythingApiDllImport.Everything_Reset();
}
}
///
/// Searches the specified key word and reset the everything API afterwards
///
/// The key word.
/// when cancelled the current search will stop and exit (and would not reset)
/// The offset.
/// The max count.
///
public List Search(string keyWord, CancellationToken token, int offset = 0, int maxCount = 100)
{
if (string.IsNullOrEmpty(keyWord))
throw new ArgumentNullException(nameof(keyWord));
if (offset < 0)
throw new ArgumentOutOfRangeException(nameof(offset));
if (maxCount < 0)
throw new ArgumentOutOfRangeException(nameof(maxCount));
lock (_syncObject)
{
if (keyWord.StartsWith("@"))
{
EverythingApiDllImport.Everything_SetRegex(true);
keyWord = keyWord.Substring(1);
}
EverythingApiDllImport.Everything_SetSearchW(keyWord);
EverythingApiDllImport.Everything_SetOffset(offset);
EverythingApiDllImport.Everything_SetMax(maxCount);
if (token.IsCancellationRequested)
{
return null;
}
if (!EverythingApiDllImport.Everything_QueryW(true))
{
CheckAndThrowExceptionOnError();
return null;
}
var results = new List();
for (int idx = 0; idx < EverythingApiDllImport.Everything_GetNumResults(); ++idx)
{
if (token.IsCancellationRequested)
{
return null;
}
EverythingApiDllImport.Everything_GetResultFullPathNameW(idx, _buffer, BufferSize);
var result = new SearchResult { FullPath = _buffer.ToString() };
if (EverythingApiDllImport.Everything_IsFolderResult(idx))
result.Type = ResultType.Folder;
else if (EverythingApiDllImport.Everything_IsFileResult(idx))
result.Type = ResultType.File;
results.Add(result);
}
Reset();
return results;
}
}
[DllImport("kernel32.dll")]
private static extern int LoadLibrary(string name);
public void Load(string sdkPath)
{
LoadLibrary(sdkPath);
}
private static void CheckAndThrowExceptionOnError()
{
switch (EverythingApiDllImport.Everything_GetLastError())
{
case StateCode.CreateThreadError:
throw new CreateThreadException();
case StateCode.CreateWindowError:
throw new CreateWindowException();
case StateCode.InvalidCallError:
throw new InvalidCallException();
case StateCode.InvalidIndexError:
throw new InvalidIndexException();
case StateCode.IPCError:
throw new IPCErrorException();
case StateCode.MemoryError:
throw new MemoryErrorException();
case StateCode.RegisterClassExError:
throw new RegisterClassExException();
}
}
}
}