Remove all third-party plugins into separate repos (except WPM).
@ -1,57 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Wox.Infrastructure;
|
||||
|
||||
namespace Wox.Plugin.BrowserBookmark
|
||||
{
|
||||
public class Bookmark : IEquatable<Bookmark>, IEqualityComparer<Bookmark>
|
||||
{
|
||||
private string m_Name;
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Name;
|
||||
}
|
||||
set
|
||||
{
|
||||
m_Name = value;
|
||||
PinyinName = m_Name.Unidecode();
|
||||
}
|
||||
}
|
||||
public string PinyinName { get; private set; }
|
||||
public string Url { get; set; }
|
||||
public string Source { get; set; }
|
||||
public int Score { get; set; }
|
||||
|
||||
/* TODO: since Source maybe unimportant, we just need to compare Name and Url */
|
||||
public bool Equals(Bookmark other)
|
||||
{
|
||||
return Equals(this, other);
|
||||
}
|
||||
|
||||
public bool Equals(Bookmark x, Bookmark y)
|
||||
{
|
||||
if (Object.ReferenceEquals(x, y)) return true;
|
||||
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
|
||||
return false;
|
||||
|
||||
return x.Name == y.Name && x.Url == y.Url;
|
||||
}
|
||||
|
||||
public int GetHashCode(Bookmark bookmark)
|
||||
{
|
||||
if (Object.ReferenceEquals(bookmark, null)) return 0;
|
||||
int hashName = bookmark.Name == null ? 0 : bookmark.Name.GetHashCode();
|
||||
int hashUrl = bookmark.Url == null ? 0 : bookmark.Url.GetHashCode();
|
||||
return hashName ^ hashUrl;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return GetHashCode(this);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Wox.Plugin.BrowserBookmark
|
||||
{
|
||||
public class ChromeBookmarks
|
||||
{
|
||||
private List<Bookmark> bookmarks = new List<Bookmark>();
|
||||
|
||||
public List<Bookmark> GetBookmarks()
|
||||
{
|
||||
bookmarks.Clear();
|
||||
LoadChromeBookmarks();
|
||||
|
||||
return bookmarks;
|
||||
}
|
||||
|
||||
private void ParseChromeBookmarks(String path, string source)
|
||||
{
|
||||
if (!File.Exists(path)) return;
|
||||
|
||||
string all = File.ReadAllText(path);
|
||||
Regex nameRegex = new Regex("\"name\": \"(?<name>.*?)\"");
|
||||
MatchCollection nameCollection = nameRegex.Matches(all);
|
||||
Regex typeRegex = new Regex("\"type\": \"(?<type>.*?)\"");
|
||||
MatchCollection typeCollection = typeRegex.Matches(all);
|
||||
Regex urlRegex = new Regex("\"url\": \"(?<url>.*?)\"");
|
||||
MatchCollection urlCollection = urlRegex.Matches(all);
|
||||
|
||||
List<string> names = (from Match match in nameCollection select match.Groups["name"].Value).ToList();
|
||||
List<string> types = (from Match match in typeCollection select match.Groups["type"].Value).ToList();
|
||||
List<string> urls = (from Match match in urlCollection select match.Groups["url"].Value).ToList();
|
||||
|
||||
int urlIndex = 0;
|
||||
for (int i = 0; i < names.Count; i++)
|
||||
{
|
||||
string name = DecodeUnicode(names[i]);
|
||||
string type = types[i];
|
||||
if (type == "url")
|
||||
{
|
||||
string url = urls[urlIndex];
|
||||
urlIndex++;
|
||||
|
||||
if (url == null) continue;
|
||||
if (url.StartsWith("javascript:", StringComparison.OrdinalIgnoreCase)) continue;
|
||||
if (url.StartsWith("vbscript:", StringComparison.OrdinalIgnoreCase)) continue;
|
||||
|
||||
bookmarks.Add(new Bookmark()
|
||||
{
|
||||
Name = name,
|
||||
Url = url,
|
||||
Source = source
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadChromeBookmarks(string path, string name)
|
||||
{
|
||||
if (!Directory.Exists(path)) return;
|
||||
var paths = Directory.GetDirectories(path);
|
||||
|
||||
foreach (var profile in paths)
|
||||
{
|
||||
if (File.Exists(Path.Combine(profile, "Bookmarks")))
|
||||
ParseChromeBookmarks(Path.Combine(profile, "Bookmarks"), name + (Path.GetFileName(profile) == "Default" ? "" : (" (" + Path.GetFileName(profile) + ")")));
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadChromeBookmarks()
|
||||
{
|
||||
String platformPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
LoadChromeBookmarks(Path.Combine(platformPath, @"Google\Chrome\User Data"), "Google Chrome");
|
||||
LoadChromeBookmarks(Path.Combine(platformPath, @"Google\Chrome SxS\User Data"), "Google Chrome Canary");
|
||||
LoadChromeBookmarks(Path.Combine(platformPath, @"Chromium\User Data"), "Chromium");
|
||||
}
|
||||
|
||||
private String DecodeUnicode(String dataStr)
|
||||
{
|
||||
Regex reg = new Regex(@"(?i)\\[uU]([0-9a-f]{4})");
|
||||
return reg.Replace(dataStr, m => ((char)Convert.ToInt32(m.Groups[1].Value, 16)).ToString());
|
||||
}
|
||||
}
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SQLite;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Wox.Plugin.BrowserBookmark
|
||||
{
|
||||
public class FirefoxBookmarks
|
||||
{
|
||||
private const string queryAllBookmarks = @"SELECT moz_places.url, moz_bookmarks.title
|
||||
FROM moz_places
|
||||
INNER JOIN moz_bookmarks ON (
|
||||
moz_bookmarks.fk NOT NULL AND moz_bookmarks.fk = moz_places.id
|
||||
)
|
||||
ORDER BY moz_places.visit_count DESC
|
||||
";
|
||||
|
||||
private const string dbPathFormat = "Data Source ={0};Version=3;New=False;Compress=True;";
|
||||
|
||||
/// <summary>
|
||||
/// Searches the places.sqlite db and returns all bookmarks
|
||||
/// </summary>
|
||||
public List<Bookmark> GetBookmarks()
|
||||
{
|
||||
// Return empty list if the places.sqlite file cannot be found
|
||||
if (string.IsNullOrEmpty(PlacesPath) || !File.Exists(PlacesPath))
|
||||
return new List<Bookmark>();
|
||||
|
||||
// create the connection string and init the connection
|
||||
string dbPath = string.Format(dbPathFormat, PlacesPath);
|
||||
var dbConnection = new SQLiteConnection(dbPath);
|
||||
|
||||
// Open connection to the database file and execute the query
|
||||
dbConnection.Open();
|
||||
var reader = new SQLiteCommand(queryAllBookmarks, dbConnection).ExecuteReader();
|
||||
|
||||
// return results in List<Bookmark> format
|
||||
return reader.Select(x => new Bookmark()
|
||||
{
|
||||
Name = (x["title"] is DBNull) ? string.Empty : x["title"].ToString(),
|
||||
Url = x["url"].ToString()
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Path to places.sqlite
|
||||
/// </summary>
|
||||
private string PlacesPath
|
||||
{
|
||||
get
|
||||
{
|
||||
var profileFolderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"Mozilla\Firefox");
|
||||
var profileIni = Path.Combine(profileFolderPath, @"profiles.ini");
|
||||
|
||||
if (!File.Exists(profileIni))
|
||||
return string.Empty;
|
||||
|
||||
// get firefox default profile directory from profiles.ini
|
||||
string ini;
|
||||
using (var sReader = new StreamReader(profileIni)) {
|
||||
ini = sReader.ReadToEnd();
|
||||
}
|
||||
var lines = ini.Split(new string[] { "\r\n" }, StringSplitOptions.None).ToList();
|
||||
|
||||
var index = lines.IndexOf("Default=1");
|
||||
if (index > 3) {
|
||||
var relative = lines[index - 2].Split('=')[1];
|
||||
var profiePath = lines[index - 1].Split('=')[1];
|
||||
return relative == "0"
|
||||
? profiePath + @"\places.sqlite"
|
||||
: Path.Combine(profileFolderPath, profiePath) + @"\places.sqlite";
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Extensions
|
||||
{
|
||||
public static IEnumerable<T> Select<T>(this SQLiteDataReader reader, Func<SQLiteDataReader, T> projection)
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
yield return projection(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 4.4 KiB |
@ -1,72 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Wox.Infrastructure;
|
||||
|
||||
namespace Wox.Plugin.BrowserBookmark
|
||||
{
|
||||
public class Main : IPlugin
|
||||
{
|
||||
private PluginInitContext context;
|
||||
|
||||
// TODO: periodically refresh the Cache?
|
||||
private List<Bookmark> cachedBookmarks = new List<Bookmark>();
|
||||
|
||||
public void Init(PluginInitContext context)
|
||||
{
|
||||
this.context = context;
|
||||
|
||||
// Cache all bookmarks
|
||||
var chromeBookmarks = new ChromeBookmarks();
|
||||
var mozBookmarks = new FirefoxBookmarks();
|
||||
|
||||
//TODO: Let the user select which browser's bookmarks are displayed
|
||||
// Add Firefox bookmarks
|
||||
cachedBookmarks.AddRange(mozBookmarks.GetBookmarks());
|
||||
// Add Chrome bookmarks
|
||||
cachedBookmarks.AddRange(chromeBookmarks.GetBookmarks());
|
||||
|
||||
cachedBookmarks = cachedBookmarks.Distinct().ToList();
|
||||
}
|
||||
|
||||
public List<Result> Query(Query query)
|
||||
{
|
||||
string param = query.GetAllRemainingParameter().TrimStart();
|
||||
|
||||
// Should top results be returned? (true if no search parameters have been passed)
|
||||
var topResults = string.IsNullOrEmpty(param);
|
||||
|
||||
var returnList = cachedBookmarks;
|
||||
|
||||
if (!topResults)
|
||||
{
|
||||
// Since we mixed chrome and firefox bookmarks, we should order them again
|
||||
var fuzzyMatcher = FuzzyMatcher.Create(param);
|
||||
returnList = cachedBookmarks.Where(o => MatchProgram(o, fuzzyMatcher)).ToList();
|
||||
returnList = returnList.OrderByDescending(o => o.Score).ToList();
|
||||
}
|
||||
|
||||
return returnList.Select(c => new Result()
|
||||
{
|
||||
Title = c.Name,
|
||||
SubTitle = "Bookmark: " + c.Url,
|
||||
IcoPath = @"Images\bookmark.png",
|
||||
Score = 5,
|
||||
Action = (e) =>
|
||||
{
|
||||
context.API.HideApp();
|
||||
context.API.ShellRun(c.Url);
|
||||
return true;
|
||||
}
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
private bool MatchProgram(Bookmark bookmark, FuzzyMatcher matcher)
|
||||
{
|
||||
if ((bookmark.Score = matcher.Evaluate(bookmark.Name).Score) > 0) return true;
|
||||
if ((bookmark.Score = matcher.Evaluate(bookmark.PinyinName).Score) > 0) return true;
|
||||
if ((bookmark.Score = matcher.Evaluate(bookmark.Url).Score / 10) > 0) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Wox.Plugin.BrowserBookmark")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Oracle Corporation")]
|
||||
[assembly: AssemblyProduct("Wox.Plugin.BrowserBookmark")]
|
||||
[assembly: AssemblyCopyright("Copyright © Oracle Corporation 2014")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("7dd2e33e-d029-4661-8f1d-594e82cef077")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
@ -1,97 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{9B130CC5-14FB-41FF-B310-0A95B6894C37}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Wox.Plugin.BrowserBookmark</RootNamespace>
|
||||
<AssemblyName>Wox.Plugin.BrowserBookmark</AssemblyName>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
|
||||
<RestorePackages>true</RestorePackages>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>..\..\Output\Debug\Plugins\Wox.Plugin.BrowserBookmark\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>..\..\Output\Release\Plugins\Wox.Plugin.BrowserBookmark\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="PresentationFramework" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data.SQLite, Version=1.0.93.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=x86">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\packages\System.Data.SQLite.Core.1.0.93.0\lib\net20\System.Data.SQLite.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Data.SQLite.Linq, Version=1.0.93.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\packages\System.Data.SQLite.Linq.1.0.93.0\lib\net20\System.Data.SQLite.Linq.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="WindowsBase" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Bookmark.cs" />
|
||||
<Compile Include="ChromeBookmarks.cs" />
|
||||
<Compile Include="FirefoxBookmarks.cs" />
|
||||
<Compile Include="Main.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Wox.Infrastructure\Wox.Infrastructure.csproj">
|
||||
<Project>{4fd29318-a8ab-4d8f-aa47-60bc241b8da3}</Project>
|
||||
<Name>Wox.Infrastructure</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Wox.Plugin\Wox.Plugin.csproj">
|
||||
<Project>{8451ecdd-2ea4-4966-bb0a-7bbc40138e80}</Project>
|
||||
<Name>Wox.Plugin</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="plugin.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Images\bookmark.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="x64\SQLite.Interop.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="x86\SQLite.Interop.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
|
||||
<system.data><DbProviderFactories><remove invariant="System.Data.SQLite" /><add name="SQLite Data Provider" invariant="System.Data.SQLite" description=".Net Framework Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" /></DbProviderFactories></system.data></configuration>
|
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="System.Data.SQLite" version="1.0.93.0" targetFramework="net35" />
|
||||
<package id="System.Data.SQLite.Core" version="1.0.93.0" targetFramework="net35" />
|
||||
<package id="System.Data.SQLite.Linq" version="1.0.93.0" targetFramework="net35" />
|
||||
</packages>
|
@ -1,12 +0,0 @@
|
||||
{
|
||||
"ID":"0ECADE17459B49F587BF81DC3A125110",
|
||||
"ActionKeyword":"b",
|
||||
"Name":"Browser Bookmarks",
|
||||
"Description":"Search your browser bookmarks",
|
||||
"Author":"qianlifeng, Ioannis G.",
|
||||
"Version":"1.1",
|
||||
"Language":"csharp",
|
||||
"Website":"http://www.getwox.com/plugin",
|
||||
"ExecuteFileName":"Wox.Plugin.browserBookmark.dll",
|
||||
"IcoPath":"Images\\bookmark.png"
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
using Wox.Infrastructure.Storage;
|
||||
|
||||
namespace Wox.Plugin.FindFile
|
||||
{
|
||||
public class FindFileContextMenuStorage : BaseStorage<FindFileContextMenuStorage>
|
||||
{
|
||||
[JsonProperty]
|
||||
public List<ContextMenu> ContextMenus = new List<ContextMenu>();
|
||||
|
||||
protected override string ConfigName
|
||||
{
|
||||
get { return "FindFileContextMenu"; }
|
||||
}
|
||||
|
||||
protected override FindFileContextMenuStorage LoadDefaultConfig()
|
||||
{
|
||||
ContextMenus = new List<ContextMenu>()
|
||||
{
|
||||
new ContextMenu()
|
||||
{
|
||||
Name = "Open Containing Folder",
|
||||
Command = "explorer.exe",
|
||||
Argument = " /select \"{path}\""
|
||||
}
|
||||
};
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public class ContextMenu
|
||||
{
|
||||
[JsonProperty]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty]
|
||||
public string Command { get; set; }
|
||||
|
||||
[JsonProperty]
|
||||
public string Argument { get; set; }
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 522 B |
Before Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 941 B |
Before Width: | Height: | Size: 5.1 KiB |
@ -1,22 +0,0 @@
|
||||
namespace Wox.Plugin.FindFile.MFTSearch
|
||||
{
|
||||
public class MFTSearchRecord
|
||||
{
|
||||
private USNRecord usn;
|
||||
|
||||
public MFTSearchRecord(USNRecord usn)
|
||||
{
|
||||
this.usn = usn;
|
||||
}
|
||||
|
||||
public string FullPath
|
||||
{
|
||||
get { return usn.FullPath; }
|
||||
}
|
||||
|
||||
public bool IsFolder
|
||||
{
|
||||
get { return usn.IsFolder; }
|
||||
}
|
||||
}
|
||||
}
|
@ -1,258 +0,0 @@
|
||||
/*
|
||||
* Thanks to the https://github.com/yiwenshengmei/MyEverything, we can bring MFT search to Wox
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Wox.Plugin.FindFile.MFTSearch
|
||||
{
|
||||
|
||||
public class MFTSearcher
|
||||
{
|
||||
private static MFTSearcherCache cache = new MFTSearcherCache();
|
||||
private static VolumeMonitor monitor = new VolumeMonitor();
|
||||
|
||||
private static void IndexVolume(string volume)
|
||||
{
|
||||
cache.EnsureVolumeExistInHashTable(volume);
|
||||
EnumerateVolume(volume, cache.VolumeRecords[volume]);
|
||||
monitor.Monitor(volume,cache);
|
||||
}
|
||||
|
||||
public static void IndexAllVolumes()
|
||||
{
|
||||
foreach (DriveInfo drive in DriveInfo.GetDrives())
|
||||
{
|
||||
IndexVolume(drive.Name.Replace("\\", ""));
|
||||
}
|
||||
}
|
||||
|
||||
public static long IndexedFileCount
|
||||
{
|
||||
get { return cache.RecordsCount; }
|
||||
}
|
||||
|
||||
public static List<MFTSearchRecord> Search(string item)
|
||||
{
|
||||
if (string.IsNullOrEmpty(item)) return new List<MFTSearchRecord>();
|
||||
|
||||
List<USNRecord> found = cache.FindByName(item, 100);
|
||||
found.ForEach(x => FillPath(x.VolumeName, x, cache));
|
||||
return found.ConvertAll(o => new MFTSearchRecord(o));
|
||||
}
|
||||
|
||||
private static void AddVolumeRootRecord(string volumeName, Dictionary<ulong, USNRecord> files)
|
||||
{
|
||||
string rightVolumeName = string.Concat("\\\\.\\", volumeName);
|
||||
rightVolumeName = string.Concat(rightVolumeName, Path.DirectorySeparatorChar);
|
||||
IntPtr hRoot = PInvokeWin32.CreateFile(rightVolumeName,
|
||||
0,
|
||||
PInvokeWin32.FILE_SHARE_READ | PInvokeWin32.FILE_SHARE_WRITE,
|
||||
IntPtr.Zero,
|
||||
PInvokeWin32.OPEN_EXISTING,
|
||||
PInvokeWin32.FILE_FLAG_BACKUP_SEMANTICS,
|
||||
IntPtr.Zero);
|
||||
|
||||
if (hRoot.ToInt32() != PInvokeWin32.INVALID_HANDLE_VALUE)
|
||||
{
|
||||
PInvokeWin32.BY_HANDLE_FILE_INFORMATION fi = new PInvokeWin32.BY_HANDLE_FILE_INFORMATION();
|
||||
bool bRtn = PInvokeWin32.GetFileInformationByHandle(hRoot, out fi);
|
||||
if (bRtn)
|
||||
{
|
||||
UInt64 fileIndexHigh = (UInt64)fi.FileIndexHigh;
|
||||
UInt64 indexRoot = (fileIndexHigh << 32) | fi.FileIndexLow;
|
||||
|
||||
files.Add(indexRoot, new USNRecord
|
||||
{
|
||||
FRN = indexRoot,
|
||||
Name = volumeName,
|
||||
ParentFrn = 0,
|
||||
IsVolumeRoot = true,
|
||||
IsFolder = true,
|
||||
VolumeName = volumeName
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IOException("GetFileInformationbyHandle() returned invalid handle",
|
||||
new Win32Exception(Marshal.GetLastWin32Error()));
|
||||
}
|
||||
PInvokeWin32.CloseHandle(hRoot);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IOException("Unable to get root frn entry", new Win32Exception(Marshal.GetLastWin32Error()));
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnumerateVolume(string volumeName, Dictionary<ulong, USNRecord> files)
|
||||
{
|
||||
IntPtr medBuffer = IntPtr.Zero;
|
||||
IntPtr pVolume = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
AddVolumeRootRecord(volumeName, files);
|
||||
pVolume = GetVolumeJournalHandle(volumeName);
|
||||
EnableVomuleJournal(pVolume);
|
||||
|
||||
SetupMFTEnumInBuffer(ref medBuffer, pVolume);
|
||||
EnumerateFiles(volumeName, pVolume, medBuffer, files);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e.Message, e);
|
||||
Exception innerException = e.InnerException;
|
||||
while (innerException != null)
|
||||
{
|
||||
Console.WriteLine(innerException.Message, innerException);
|
||||
innerException = innerException.InnerException;
|
||||
}
|
||||
throw new ApplicationException("Error in EnumerateVolume()", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (pVolume.ToInt32() != PInvokeWin32.INVALID_HANDLE_VALUE)
|
||||
{
|
||||
PInvokeWin32.CloseHandle(pVolume);
|
||||
if (medBuffer != IntPtr.Zero)
|
||||
{
|
||||
Marshal.FreeHGlobal(medBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static IntPtr GetVolumeJournalHandle(string volumeName)
|
||||
{
|
||||
string vol = string.Concat("\\\\.\\", volumeName);
|
||||
IntPtr pVolume = PInvokeWin32.CreateFile(vol,
|
||||
PInvokeWin32.GENERIC_READ | PInvokeWin32.GENERIC_WRITE,
|
||||
PInvokeWin32.FILE_SHARE_READ | PInvokeWin32.FILE_SHARE_WRITE,
|
||||
IntPtr.Zero,
|
||||
PInvokeWin32.OPEN_EXISTING,
|
||||
0,
|
||||
IntPtr.Zero);
|
||||
if (pVolume.ToInt32() == PInvokeWin32.INVALID_HANDLE_VALUE)
|
||||
{
|
||||
throw new IOException(string.Format("CreateFile(\"{0}\") returned invalid handle", volumeName),
|
||||
new Win32Exception(Marshal.GetLastWin32Error()));
|
||||
}
|
||||
else
|
||||
{
|
||||
return pVolume;
|
||||
}
|
||||
}
|
||||
unsafe private static void EnableVomuleJournal(IntPtr pVolume)
|
||||
{
|
||||
UInt64 MaximumSize = 0x800000;
|
||||
UInt64 AllocationDelta = 0x100000;
|
||||
UInt32 cb;
|
||||
PInvokeWin32.CREATE_USN_JOURNAL_DATA cujd;
|
||||
cujd.MaximumSize = MaximumSize;
|
||||
cujd.AllocationDelta = AllocationDelta;
|
||||
|
||||
int sizeCujd = Marshal.SizeOf(cujd);
|
||||
IntPtr cujdBuffer = Marshal.AllocHGlobal(sizeCujd);
|
||||
PInvokeWin32.ZeroMemory(cujdBuffer, sizeCujd);
|
||||
Marshal.StructureToPtr(cujd, cujdBuffer, true);
|
||||
|
||||
bool fOk = PInvokeWin32.DeviceIoControl(pVolume, PInvokeWin32.FSCTL_CREATE_USN_JOURNAL,
|
||||
cujdBuffer, sizeCujd, IntPtr.Zero, 0, out cb, IntPtr.Zero);
|
||||
if (!fOk)
|
||||
{
|
||||
throw new IOException("DeviceIoControl() returned false", new Win32Exception(Marshal.GetLastWin32Error()));
|
||||
}
|
||||
}
|
||||
unsafe internal static bool QueryUSNJournal(IntPtr pVolume, out PInvokeWin32.USN_JOURNAL_DATA ujd, out uint bytesReturned)
|
||||
{
|
||||
bool bOK = PInvokeWin32.DeviceIoControl(
|
||||
pVolume, PInvokeWin32.FSCTL_QUERY_USN_JOURNAL,
|
||||
IntPtr.Zero,
|
||||
0,
|
||||
out ujd,
|
||||
sizeof(PInvokeWin32.USN_JOURNAL_DATA),
|
||||
out bytesReturned,
|
||||
IntPtr.Zero
|
||||
);
|
||||
return bOK;
|
||||
}
|
||||
unsafe private static void SetupMFTEnumInBuffer(ref IntPtr medBuffer, IntPtr pVolume)
|
||||
{
|
||||
uint bytesReturned = 0;
|
||||
PInvokeWin32.USN_JOURNAL_DATA ujd = new PInvokeWin32.USN_JOURNAL_DATA();
|
||||
|
||||
bool bOk = QueryUSNJournal(pVolume, out ujd, out bytesReturned);
|
||||
if (bOk)
|
||||
{
|
||||
PInvokeWin32.MFT_ENUM_DATA med;
|
||||
med.StartFileReferenceNumber = 0;
|
||||
med.LowUsn = 0;
|
||||
med.HighUsn = ujd.NextUsn;
|
||||
int sizeMftEnumData = Marshal.SizeOf(med);
|
||||
medBuffer = Marshal.AllocHGlobal(sizeMftEnumData);
|
||||
PInvokeWin32.ZeroMemory(medBuffer, sizeMftEnumData);
|
||||
Marshal.StructureToPtr(med, medBuffer, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IOException("DeviceIoControl() returned false", new Win32Exception(Marshal.GetLastWin32Error()));
|
||||
}
|
||||
}
|
||||
|
||||
unsafe private static void EnumerateFiles(string volumeName, IntPtr pVolume, IntPtr medBuffer, Dictionary<ulong, USNRecord> files)
|
||||
{
|
||||
IntPtr pData = Marshal.AllocHGlobal(sizeof(UInt64) + 0x10000);
|
||||
PInvokeWin32.ZeroMemory(pData, sizeof(UInt64) + 0x10000);
|
||||
uint outBytesReturned = 0;
|
||||
|
||||
while (false != PInvokeWin32.DeviceIoControl(pVolume, PInvokeWin32.FSCTL_ENUM_USN_DATA, medBuffer,
|
||||
sizeof(PInvokeWin32.MFT_ENUM_DATA), pData, sizeof(UInt64) + 0x10000, out outBytesReturned,
|
||||
IntPtr.Zero))
|
||||
{
|
||||
IntPtr pUsnRecord = new IntPtr(pData.ToInt32() + sizeof(Int64));
|
||||
while (outBytesReturned > 60)
|
||||
{
|
||||
PInvokeWin32.USN_RECORD usn = new PInvokeWin32.USN_RECORD(pUsnRecord);
|
||||
|
||||
files.Add(usn.FRN, new USNRecord
|
||||
{
|
||||
Name = usn.FileName,
|
||||
ParentFrn = usn.ParentFRN,
|
||||
FRN = usn.FRN,
|
||||
IsFolder = usn.IsFolder,
|
||||
VolumeName = volumeName
|
||||
});
|
||||
|
||||
pUsnRecord = new IntPtr(pUsnRecord.ToInt32() + usn.RecordLength);
|
||||
outBytesReturned -= usn.RecordLength;
|
||||
}
|
||||
Marshal.WriteInt64(medBuffer, Marshal.ReadInt64(pData, 0));
|
||||
}
|
||||
Marshal.FreeHGlobal(pData);
|
||||
}
|
||||
|
||||
internal static void FillPath(string volume, USNRecord record, MFTSearcherCache db)
|
||||
{
|
||||
if (record == null) return;
|
||||
var fdSource = db.GetVolumeRecords(volume);
|
||||
string fullpath = record.Name;
|
||||
FindRecordPath(record, ref fullpath, fdSource);
|
||||
record.FullPath = fullpath;
|
||||
}
|
||||
|
||||
private static void FindRecordPath(USNRecord curRecord, ref string fullpath, Dictionary<ulong, USNRecord> fdSource)
|
||||
{
|
||||
if (curRecord.IsVolumeRoot) return;
|
||||
USNRecord nextRecord = null;
|
||||
if (!fdSource.TryGetValue(curRecord.ParentFrn, out nextRecord))
|
||||
return;
|
||||
fullpath = string.Format("{0}{1}{2}", nextRecord.Name, Path.DirectorySeparatorChar, fullpath);
|
||||
FindRecordPath(nextRecord, ref fullpath, fdSource);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,129 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Wox.Plugin.FindFile.MFTSearch
|
||||
{
|
||||
internal class MFTSearcherCache
|
||||
{
|
||||
public Dictionary<string, Dictionary<ulong, USNRecord>> VolumeRecords = new Dictionary<string, Dictionary<ulong, USNRecord>>();
|
||||
public static object locker = new object();
|
||||
|
||||
public MFTSearcherCache() { }
|
||||
|
||||
public bool ContainsVolume(string volume)
|
||||
{
|
||||
return VolumeRecords.ContainsKey(volume);
|
||||
}
|
||||
|
||||
public void AddRecord(string volume, List<USNRecord> r)
|
||||
{
|
||||
EnsureVolumeExistInHashTable(volume);
|
||||
r.ForEach(x => VolumeRecords[volume].Add(x.FRN, x));
|
||||
}
|
||||
|
||||
public void AddRecord(string volume, USNRecord record)
|
||||
{
|
||||
EnsureVolumeExistInHashTable(volume);
|
||||
if (!VolumeRecords[volume].ContainsKey(record.FRN))
|
||||
{
|
||||
lock (locker)
|
||||
{
|
||||
VolumeRecords[volume].Add(record.FRN, record);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void EnsureVolumeExistInHashTable(string volume)
|
||||
{
|
||||
if (!VolumeRecords.ContainsKey(volume))
|
||||
VolumeRecords.Add(volume, new Dictionary<ulong, USNRecord>());
|
||||
}
|
||||
|
||||
public bool DeleteRecord(string volume, ulong frn)
|
||||
{
|
||||
bool result = false;
|
||||
result = DeleteRecordHashTableItem(VolumeRecords, volume, frn);
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool DeleteRecordHashTableItem(Dictionary<string, Dictionary<ulong, USNRecord>> hashtable, string volume, ulong frn)
|
||||
{
|
||||
if (hashtable.ContainsKey(volume) && hashtable[volume].ContainsKey(frn))
|
||||
{
|
||||
lock (locker)
|
||||
{
|
||||
hashtable[volume].Remove(frn);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateRecord(string volume, USNRecord record)
|
||||
{
|
||||
RealUpdateRecord(volume, VolumeRecords, record);
|
||||
}
|
||||
|
||||
private bool RealUpdateRecord(string volume, Dictionary<string, Dictionary<ulong, USNRecord>> source, USNRecord record)
|
||||
{
|
||||
if (source.ContainsKey(volume) && source[volume].ContainsKey(record.FRN))
|
||||
{
|
||||
lock (locker)
|
||||
{
|
||||
source[volume][record.FRN] = record;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public List<USNRecord> FindByName(string filename, long maxResult = -1)
|
||||
{
|
||||
List<USNRecord> result = new List<USNRecord>();
|
||||
lock (locker)
|
||||
{
|
||||
foreach (Dictionary<ulong, USNRecord> dictionary in VolumeRecords.Values)
|
||||
{
|
||||
foreach (var usnRecord in dictionary)
|
||||
{
|
||||
if (usnRecord.Value.Name.IndexOf(filename, StringComparison.OrdinalIgnoreCase) >= 0)
|
||||
{
|
||||
result.Add(usnRecord.Value);
|
||||
if (maxResult > 0 && result.Count() >= maxResult) break;
|
||||
}
|
||||
if (maxResult > 0 && result.Count() >= maxResult) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public USNRecord FindByFrn(string volume, ulong frn)
|
||||
{
|
||||
if ((!VolumeRecords.ContainsKey(volume)))
|
||||
throw new Exception(string.Format("DB not contain the volume: {0}", volume));
|
||||
USNRecord result = null;
|
||||
VolumeRecords[volume].TryGetValue(frn, out result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public long RecordsCount
|
||||
{
|
||||
get { return VolumeRecords.Sum(x => x.Value.Count); }
|
||||
}
|
||||
|
||||
public Dictionary<ulong, USNRecord> GetVolumeRecords(string volume)
|
||||
{
|
||||
Dictionary<ulong, USNRecord> result = null;
|
||||
VolumeRecords.TryGetValue(volume, out result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,165 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Wox.Plugin.FindFile.MFTSearch {
|
||||
public class PInvokeWin32
|
||||
{
|
||||
|
||||
public const UInt32 GENERIC_READ = 0x80000000;
|
||||
public const UInt32 GENERIC_WRITE = 0x40000000;
|
||||
public const UInt32 FILE_SHARE_READ = 0x00000001;
|
||||
public const UInt32 FILE_SHARE_WRITE = 0x00000002;
|
||||
public const UInt32 FILE_ATTRIBUTE_DIRECTORY = 0x00000010;
|
||||
public const UInt32 OPEN_EXISTING = 3;
|
||||
public const UInt32 FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
|
||||
public const Int32 INVALID_HANDLE_VALUE = -1;
|
||||
public const UInt32 FSCTL_QUERY_USN_JOURNAL = 0x000900f4;
|
||||
public const UInt32 FSCTL_ENUM_USN_DATA = 0x000900b3;
|
||||
public const UInt32 FSCTL_CREATE_USN_JOURNAL = 0x000900e7;
|
||||
public const UInt32 FSCTL_READ_USN_JOURNAL = 0x000900bb;
|
||||
|
||||
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess,
|
||||
uint dwShareMode, IntPtr lpSecurityAttributes,
|
||||
uint dwCreationDisposition, uint dwFlagsAndAttributes,
|
||||
IntPtr hTemplateFile);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool GetFileInformationByHandle(IntPtr hFile,
|
||||
out BY_HANDLE_FILE_INFORMATION lpFileInformation);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool CloseHandle(IntPtr hObject);
|
||||
|
||||
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool DeviceIoControl(IntPtr hDevice,
|
||||
UInt32 dwIoControlCode,
|
||||
IntPtr lpInBuffer, Int32 nInBufferSize,
|
||||
out USN_JOURNAL_DATA lpOutBuffer, Int32 nOutBufferSize,
|
||||
out uint lpBytesReturned, IntPtr lpOverlapped);
|
||||
|
||||
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool DeviceIoControl(IntPtr hDevice,
|
||||
UInt32 dwIoControlCode,
|
||||
IntPtr lpInBuffer, Int32 nInBufferSize,
|
||||
IntPtr lpOutBuffer, Int32 nOutBufferSize,
|
||||
out uint lpBytesReturned, IntPtr lpOverlapped);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern void ZeroMemory(IntPtr ptr, Int32 size);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct BY_HANDLE_FILE_INFORMATION {
|
||||
public uint FileAttributes;
|
||||
public FILETIME CreationTime;
|
||||
public FILETIME LastAccessTime;
|
||||
public FILETIME LastWriteTime;
|
||||
public uint VolumeSerialNumber;
|
||||
public uint FileSizeHigh;
|
||||
public uint FileSizeLow;
|
||||
public uint NumberOfLinks;
|
||||
public uint FileIndexHigh;
|
||||
public uint FileIndexLow;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct FILETIME {
|
||||
public uint DateTimeLow;
|
||||
public uint DateTimeHigh;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct USN_JOURNAL_DATA {
|
||||
public UInt64 UsnJournalID;
|
||||
public Int64 FirstUsn;
|
||||
public Int64 NextUsn;
|
||||
public Int64 LowestValidUsn;
|
||||
public Int64 MaxUsn;
|
||||
public UInt64 MaximumSize;
|
||||
public UInt64 AllocationDelta;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct MFT_ENUM_DATA {
|
||||
public UInt64 StartFileReferenceNumber;
|
||||
public Int64 LowUsn;
|
||||
public Int64 HighUsn;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct CREATE_USN_JOURNAL_DATA {
|
||||
public UInt64 MaximumSize;
|
||||
public UInt64 AllocationDelta;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct READ_USN_JOURNAL_DATA {
|
||||
public Int64 StartUsn;
|
||||
public UInt32 ReasonMask;
|
||||
public UInt32 ReturnOnlyOnClose;
|
||||
public UInt64 Timeout;
|
||||
public UInt64 BytesToWaitFor;
|
||||
public UInt64 UsnJournalID;
|
||||
}
|
||||
|
||||
public class USN_RECORD {
|
||||
public UInt32 RecordLength;
|
||||
public UInt16 MajorVersion;
|
||||
public UInt16 MinorVersion;
|
||||
public UInt64 FRN; // 8
|
||||
public UInt64 ParentFRN; // 16
|
||||
public Int64 Usn; // Need be care
|
||||
public UInt64 TimeStamp; // Need Be care
|
||||
public UInt32 Reason;
|
||||
public UInt32 SourceInfo;
|
||||
public UInt32 SecurityId;
|
||||
public UInt32 FileAttributes; // 52
|
||||
public UInt16 FileNameLength;
|
||||
public UInt16 FileNameOffset;
|
||||
public string FileName = string.Empty;
|
||||
|
||||
private const int RecordLength_OFFSET = 0;
|
||||
private const int MajorVersion_OFFSET = 4;
|
||||
private const int MinorVersion_OFFSET = 6;
|
||||
private const int FileReferenceNumber_OFFSET = 8;
|
||||
private const int ParentFileReferenceNumber_OFFSET = 16;
|
||||
private const int Usn_OFFSET = 24;
|
||||
private const int TimeStamp_OFFSET = 32;
|
||||
private const int Reason_OFFSET = 40;
|
||||
private const int SourceInfo_OFFSET = 44;
|
||||
private const int SecurityId_OFFSET = 48;
|
||||
private const int FileAttributes_OFFSET = 52;
|
||||
private const int FileNameLength_OFFSET = 56;
|
||||
private const int FileNameOffset_OFFSET = 58;
|
||||
private const int FileName_OFFSET = 60;
|
||||
|
||||
public USN_RECORD(IntPtr p) {
|
||||
this.RecordLength = (UInt32)Marshal.ReadInt32(p, RecordLength_OFFSET);
|
||||
this.MajorVersion = (UInt16)Marshal.ReadInt16(p, MajorVersion_OFFSET);
|
||||
this.MinorVersion = (UInt16)Marshal.ReadInt16(p, MinorVersion_OFFSET);
|
||||
this.FRN = (UInt64)Marshal.ReadInt64(p, FileReferenceNumber_OFFSET);
|
||||
this.ParentFRN = (UInt64)Marshal.ReadInt64(p, ParentFileReferenceNumber_OFFSET);
|
||||
this.Usn = Marshal.ReadInt64(p, Usn_OFFSET);
|
||||
this.TimeStamp = (UInt64)Marshal.ReadInt64(p, TimeStamp_OFFSET);
|
||||
this.Reason = (UInt32)Marshal.ReadInt32(p, Reason_OFFSET);
|
||||
this.SourceInfo = (UInt32)Marshal.ReadInt32(p, SourceInfo_OFFSET);
|
||||
this.SecurityId = (UInt32)Marshal.ReadInt32(p, SecurityId_OFFSET);
|
||||
this.FileAttributes = (UInt32)Marshal.ReadInt32(p, FileAttributes_OFFSET);
|
||||
this.FileNameLength = (UInt16)Marshal.ReadInt16(p, FileNameLength_OFFSET);
|
||||
this.FileNameOffset = (UInt16)Marshal.ReadInt16(p, FileNameOffset_OFFSET);
|
||||
|
||||
this.FileName = Marshal.PtrToStringUni(new IntPtr(p.ToInt32() + this.FileNameOffset), this.FileNameLength / sizeof(char));
|
||||
}
|
||||
|
||||
public bool IsFolder {
|
||||
get { return 0 != (FileAttributes & PInvokeWin32.FILE_ATTRIBUTE_DIRECTORY); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Wox.Plugin.FindFile.MFTSearch
|
||||
{
|
||||
internal class USNChangeReason
|
||||
{
|
||||
public static Dictionary<string, UInt32> USN_REASONS = new Dictionary<string, UInt32> {
|
||||
{"USN_REASON_DATA_OVERWRITE", 0x00000001},
|
||||
{"USN_REASON_DATA_EXTEND", 0x00000002},
|
||||
{"USN_REASON_DATA_TRUNCATION", 0x00000004},
|
||||
{"USN_REASON_NAMED_DATA_OVERWRITE", 0x00000010},
|
||||
{"USN_REASON_NAMED_DATA_EXTEND", 0x00000020},
|
||||
{"USN_REASON_NAMED_DATA_TRUNCATION", 0x00000040},
|
||||
{"USN_REASON_FILE_CREATE", 0x00000100},
|
||||
{"USN_REASON_FILE_DELETE", 0x00000200},
|
||||
{"USN_REASON_EA_CHANGE", 0x00000400},
|
||||
{"USN_REASON_SECURITY_CHANGE", 0x00000800},
|
||||
{"USN_REASON_RENAME_OLD_NAME", 0x00001000},
|
||||
{"USN_REASON_RENAME_NEW_NAME", 0x00002000},
|
||||
{"USN_REASON_INDEXABLE_CHANGE", 0x00004000},
|
||||
{"USN_REASON_BASIC_INFO_CHANGE", 0x00008000},
|
||||
{"USN_REASON_HARD_LINK_CHANGE", 0x00010000},
|
||||
{"USN_REASON_COMPRESSION_CHANGE", 0x00020000},
|
||||
{"USN_REASON_ENCRYPTION_CHANGE", 0x00040000},
|
||||
{"USN_REASON_OBJECT_ID_CHANGE", 0x00080000},
|
||||
{"USN_REASON_REPARSE_POINT_CHANGE", 0x00100000},
|
||||
{"USN_REASON_STREAM_CHANGE", 0x00200000},
|
||||
{"USN_REASON_TRANSACTED_CHANGE", 0x00400000},
|
||||
{"USN_REASON_CLOSE", 0x80000000}
|
||||
};
|
||||
|
||||
public static string ReasonPrettyFormat(UInt32 rsn)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append("[");
|
||||
foreach (var rsnPair in USN_REASONS)
|
||||
{
|
||||
if ((rsnPair.Value & rsn) != 0)
|
||||
sb.Append(rsnPair.Key + " ");
|
||||
}
|
||||
sb.Append("]");
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Wox.Plugin.FindFile.MFTSearch
|
||||
{
|
||||
public class USNRecord
|
||||
{
|
||||
|
||||
public string Name { get; set; }
|
||||
public ulong FRN { get; set; }
|
||||
public UInt64 ParentFrn { get; set; }
|
||||
public string FullPath { get; set; }
|
||||
public bool IsVolumeRoot { get; set; }
|
||||
public bool IsFolder { get; set; }
|
||||
public string VolumeName { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.IsNullOrEmpty(FullPath) ? Name : FullPath;
|
||||
}
|
||||
|
||||
public static USNRecord ParseUSN(string volume, PInvokeWin32.USN_RECORD usn)
|
||||
{
|
||||
return new USNRecord
|
||||
{
|
||||
FRN = usn.FRN,
|
||||
Name = usn.FileName,
|
||||
ParentFrn = usn.ParentFRN,
|
||||
IsFolder = usn.IsFolder,
|
||||
VolumeName = volume
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -1,139 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace Wox.Plugin.FindFile.MFTSearch
|
||||
{
|
||||
internal class VolumeMonitor
|
||||
{
|
||||
public Action<USNRecord> RecordAddedEvent;
|
||||
public Action<USNRecord> RecordDeletedEvent;
|
||||
public Action<USNRecord, USNRecord> RecordRenameEvent;
|
||||
|
||||
public void Monitor(List<string> volumes, MFTSearcherCache db)
|
||||
{
|
||||
foreach (var volume in volumes)
|
||||
{
|
||||
Monitor(volume, db);
|
||||
}
|
||||
}
|
||||
|
||||
public void Monitor(string volume, MFTSearcherCache db)
|
||||
{
|
||||
if (string.IsNullOrEmpty(volume)) throw new InvalidOperationException("Volume cant't be null or empty string.");
|
||||
if (!db.ContainsVolume(volume)) throw new InvalidOperationException(string.Format("Volume {0} must be scaned first."));
|
||||
|
||||
ThreadPool.QueueUserWorkItem(o => MonitorThread(volume, db));
|
||||
}
|
||||
|
||||
private PInvokeWin32.READ_USN_JOURNAL_DATA SetupInputData4JournalRead(string volume, uint reason)
|
||||
{
|
||||
IntPtr pMonitorVolume = MFTSearcher.GetVolumeJournalHandle(volume);
|
||||
uint bytesReturned = 0;
|
||||
PInvokeWin32.USN_JOURNAL_DATA ujd = new PInvokeWin32.USN_JOURNAL_DATA();
|
||||
MFTSearcher.QueryUSNJournal(pMonitorVolume, out ujd, out bytesReturned);
|
||||
|
||||
// 构建输入参数
|
||||
PInvokeWin32.READ_USN_JOURNAL_DATA rujd = new PInvokeWin32.READ_USN_JOURNAL_DATA();
|
||||
rujd.StartUsn = ujd.NextUsn;
|
||||
rujd.ReasonMask = reason;
|
||||
rujd.ReturnOnlyOnClose = 1;
|
||||
rujd.Timeout = 0;
|
||||
rujd.BytesToWaitFor = 1;
|
||||
rujd.UsnJournalID = ujd.UsnJournalID;
|
||||
|
||||
return rujd;
|
||||
}
|
||||
|
||||
private void MonitorThread(string volume, MFTSearcherCache db)
|
||||
{
|
||||
IntPtr pbuffer = Marshal.AllocHGlobal(0x1000);
|
||||
PInvokeWin32.READ_USN_JOURNAL_DATA rujd = SetupInputData4JournalRead(volume, 0xFFFFFFFF);
|
||||
UInt32 cbRead;
|
||||
IntPtr prujd;
|
||||
|
||||
while (true)
|
||||
{
|
||||
prujd = Marshal.AllocHGlobal(Marshal.SizeOf(rujd));
|
||||
PInvokeWin32.ZeroMemory(prujd, Marshal.SizeOf(rujd));
|
||||
Marshal.StructureToPtr(rujd, prujd, true);
|
||||
|
||||
IntPtr pVolume = MFTSearcher.GetVolumeJournalHandle(volume);
|
||||
|
||||
bool fok = PInvokeWin32.DeviceIoControl(pVolume,
|
||||
PInvokeWin32.FSCTL_READ_USN_JOURNAL,
|
||||
prujd, Marshal.SizeOf(typeof(PInvokeWin32.READ_USN_JOURNAL_DATA)),
|
||||
pbuffer, 0x1000, out cbRead, IntPtr.Zero);
|
||||
|
||||
IntPtr pRealData = new IntPtr(pbuffer.ToInt32() + Marshal.SizeOf(typeof(Int64)));
|
||||
uint offset = 0;
|
||||
|
||||
if (fok)
|
||||
{
|
||||
while (offset + Marshal.SizeOf(typeof(Int64)) < cbRead)
|
||||
{
|
||||
PInvokeWin32.USN_RECORD usn = new PInvokeWin32.USN_RECORD(new IntPtr(pRealData.ToInt32() + (int)offset));
|
||||
ProcessUSN(usn, volume, db);
|
||||
offset += usn.RecordLength;
|
||||
}
|
||||
}
|
||||
|
||||
Marshal.FreeHGlobal(prujd);
|
||||
rujd.StartUsn = Marshal.ReadInt64(pbuffer);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessUSN(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db)
|
||||
{
|
||||
if (MaskEqual(usn.Reason, USNChangeReason.USN_REASONS["USN_REASON_RENAME_NEW_NAME"]))
|
||||
ProcessRenameNewName(usn, volume, db);
|
||||
if ((usn.Reason & USNChangeReason.USN_REASONS["USN_REASON_FILE_CREATE"]) != 0)
|
||||
ProcessFileCreate(usn, volume, db);
|
||||
if (MaskEqual(usn.Reason, USNChangeReason.USN_REASONS["USN_REASON_FILE_DELETE"]))
|
||||
ProcessFileDelete(usn, volume, db);
|
||||
}
|
||||
|
||||
private void ProcessFileDelete(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db)
|
||||
{
|
||||
var cached = db.FindByFrn(volume, usn.FRN);
|
||||
if (cached != null)
|
||||
{
|
||||
MFTSearcher.FillPath(volume, cached, db);
|
||||
var deleteok = db.DeleteRecord(volume, usn.FRN);
|
||||
Debug.WriteLine(string.Format(">>>> DeleteFIle {0} {1}.", cached.FullPath, deleteok ? "successful" : "fail"));
|
||||
if (RecordDeletedEvent != null)
|
||||
RecordDeletedEvent(cached);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessRenameNewName(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db)
|
||||
{
|
||||
USNRecord newRecord = USNRecord.ParseUSN(volume, usn);
|
||||
db.UpdateRecord(volume, newRecord);
|
||||
|
||||
var oldRecord = db.FindByFrn(volume, usn.FRN);
|
||||
if (oldRecord != null)
|
||||
{
|
||||
Debug.WriteLine(string.Format(">>>> RenameFile {0} to {1}", oldRecord.FullPath, newRecord.FullPath));
|
||||
if (RecordRenameEvent != null) RecordRenameEvent(oldRecord, newRecord);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessFileCreate(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db)
|
||||
{
|
||||
USNRecord record = USNRecord.ParseUSN(volume, usn);
|
||||
db.AddRecord(volume, record);
|
||||
Debug.WriteLine(string.Format(">>>> NewFile: {0}", record.FullPath));
|
||||
if (RecordAddedEvent != null)
|
||||
RecordAddedEvent(record);
|
||||
}
|
||||
|
||||
|
||||
private bool MaskEqual(uint target, uint compare)
|
||||
{
|
||||
return (target & compare) != 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,114 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.Text;
|
||||
using System.Windows.Controls;
|
||||
using Wox.Infrastructure;
|
||||
using Wox.Plugin.FindFile.MFTSearch;
|
||||
|
||||
namespace Wox.Plugin.FindFile
|
||||
{
|
||||
public class Main : IPlugin, ISettingProvider
|
||||
{
|
||||
private PluginInitContext context;
|
||||
private bool initial = false;
|
||||
|
||||
public List<Result> Query(Query query)
|
||||
{
|
||||
if (!initial)
|
||||
{
|
||||
return new List<Result>()
|
||||
{
|
||||
new Result("Wox is indexing your files, please try later.","Images/warning.png")
|
||||
};
|
||||
}
|
||||
|
||||
string q = query.GetAllRemainingParameter();
|
||||
return MFTSearcher.Search(q).Take(100).Select(t => ConvertMFTSearch(t, q)).ToList();
|
||||
}
|
||||
|
||||
public void Init(PluginInitContext context)
|
||||
{
|
||||
this.context = context;
|
||||
var searchtimestart = DateTime.Now;
|
||||
MFTSearcher.IndexAllVolumes();
|
||||
initial = true;
|
||||
var searchtimeend = DateTime.Now;
|
||||
Debug.WriteLine(string.Format("{0} file, indexed, {1}ms has spent.", MFTSearcher.IndexedFileCount, searchtimeend.Subtract(searchtimestart).TotalMilliseconds));
|
||||
}
|
||||
|
||||
private Result ConvertMFTSearch(MFTSearchRecord record, string query)
|
||||
{
|
||||
string icoPath = "Images/file.png";
|
||||
if (record.IsFolder)
|
||||
{
|
||||
icoPath = "Images/folder.png";
|
||||
}
|
||||
|
||||
string name = Path.GetFileName(record.FullPath);
|
||||
FuzzyMatcher matcher = FuzzyMatcher.Create(query);
|
||||
return new Result()
|
||||
{
|
||||
Title = name,
|
||||
Score = matcher.Evaluate(name).Score,
|
||||
SubTitle = record.FullPath,
|
||||
IcoPath = icoPath,
|
||||
Action = _ =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Process.Start(record.FullPath);
|
||||
}
|
||||
catch
|
||||
{
|
||||
context.API.ShowMsg("Can't open " + record.FullPath, string.Empty, string.Empty);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
ContextMenu = GetContextMenu(record)
|
||||
};
|
||||
}
|
||||
|
||||
private List<Result> GetContextMenu(MFTSearchRecord record)
|
||||
{
|
||||
List<Result> contextMenus = new List<Result>();
|
||||
|
||||
if (!record.IsFolder)
|
||||
{
|
||||
foreach (ContextMenu contextMenu in FindFileContextMenuStorage.Instance.ContextMenus)
|
||||
{
|
||||
contextMenus.Add(new Result()
|
||||
{
|
||||
Title = contextMenu.Name,
|
||||
Action = _ =>
|
||||
{
|
||||
string argument = contextMenu.Argument.Replace("{path}", record.FullPath);
|
||||
try
|
||||
{
|
||||
Process.Start(contextMenu.Command,argument);
|
||||
}
|
||||
catch
|
||||
{
|
||||
context.API.ShowMsg("Can't start " + record.FullPath, string.Empty, string.Empty);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
IcoPath = "Images/list.png"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return contextMenus;
|
||||
}
|
||||
|
||||
public Control CreateSettingPanel()
|
||||
{
|
||||
return new Setting();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// 有关程序集的常规信息通过以下
|
||||
// 特性集控制。更改这些特性值可修改
|
||||
// 与程序集关联的信息。
|
||||
[assembly: AssemblyTitle("Wox.Plugin.FindFile")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Wox.Plugin.FindFile")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2014")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// 将 ComVisible 设置为 false 使此程序集中的类型
|
||||
// 对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
|
||||
// 则将该类型上的 ComVisible 特性设置为 true。
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
|
||||
[assembly: Guid("93b857b4-07a4-4ac1-a3ee-d038ace03ce9")]
|
||||
|
||||
// 程序集的版本信息由下面四个值组成:
|
||||
//
|
||||
// 主版本
|
||||
// 次版本
|
||||
// 生成号
|
||||
// 修订号
|
||||
//
|
||||
// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
|
||||
// 方法是按如下所示使用“*”:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
@ -1,132 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{84EA88B4-71F2-4A3D-9771-D7B0244C0D81}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Wox.Plugin.FindFile</RootNamespace>
|
||||
<AssemblyName>Wox.Plugin.FindFile</AssemblyName>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile />
|
||||
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
|
||||
<RestorePackages>true</RestorePackages>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>..\..\Output\Debug\Plugins\Wox.Plugin.FindFile\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>..\..\Output\Release\Plugins\Wox.Plugin.FindFile\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="log4net, Version=1.2.13.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\packages\log4net.2.0.3\lib\net35-full\log4net.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\packages\Newtonsoft.Json.6.0.5\lib\net35\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="PresentationFramework" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Windows.Controls.Input.Toolkit">
|
||||
<HintPath>..\..\packages\WPFToolkit.3.5.50211.1\lib\System.Windows.Controls.Input.Toolkit.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Windows.Controls.Layout.Toolkit">
|
||||
<HintPath>..\..\packages\WPFToolkit.3.5.50211.1\lib\System.Windows.Controls.Layout.Toolkit.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="WindowsBase" />
|
||||
<Reference Include="WPFToolkit, Version=3.5.40128.1, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\WPFToolkit.3.5.50211.1\lib\WPFToolkit.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="FindFileContextMenuStorage.cs" />
|
||||
<Compile Include="Main.cs" />
|
||||
<Compile Include="MFTSearch\MFTSearcher.cs" />
|
||||
<Compile Include="MFTSearch\MFTSearcherCache.cs" />
|
||||
<Compile Include="MFTSearch\MFTSearchRecord.cs" />
|
||||
<Compile Include="MFTSearch\PInvokeWin32.cs" />
|
||||
<Compile Include="MFTSearch\USNChangeReason.cs" />
|
||||
<Compile Include="MFTSearch\USNRecord.cs" />
|
||||
<Compile Include="MFTSearch\VolumeMonitor.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Setting.xaml.cs">
|
||||
<DependentUpon>Setting.xaml</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Wox.Infrastructure\Wox.Infrastructure.csproj">
|
||||
<Project>{4fd29318-a8ab-4d8f-aa47-60bc241b8da3}</Project>
|
||||
<Name>Wox.Infrastructure</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Wox.Plugin\Wox.Plugin.csproj">
|
||||
<Project>{8451ecdd-2ea4-4966-bb0a-7bbc40138e80}</Project>
|
||||
<Name>Wox.Plugin</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Images\find.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Images\folder.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Images\file.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Images\list.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Images\open.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Images\warning.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
<None Include="plugin.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Include="Setting.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="log4net" version="2.0.3" targetFramework="net35" />
|
||||
<package id="Newtonsoft.Json" version="6.0.5" targetFramework="net35" />
|
||||
<package id="WPFToolkit" version="3.5.50211.1" targetFramework="net35" />
|
||||
</packages>
|
@ -1,12 +0,0 @@
|
||||
{
|
||||
"ID":"64EDFA42642446E5BBFF2546EE4549BB",
|
||||
"ActionKeyword":"f",
|
||||
"Name":"Find Files and Folders",
|
||||
"Description":"Search all your files and folders in your disk",
|
||||
"Author":"qianlifeng",
|
||||
"Version":"1.0",
|
||||
"Language":"csharp",
|
||||
"Website":"http://www.getwox.com/plugin",
|
||||
"ExecuteFileName":"Wox.Plugin.FindFile.dll",
|
||||
"IcoPath":"Images\\find.png"
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
<UserControl x:Class="Wox.Plugin.FindFile.Setting"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:controls="http://schemas.microsoft.com/wpf/2008/toolkit"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300" d:DesignWidth="600">
|
||||
<TabControl Height="auto" Margin="10" VerticalAlignment="Top">
|
||||
<TabItem Header="Context Menu">
|
||||
<controls:DataGrid x:Name="menuGrid" AutoGenerateColumns="False" CanUserAddRows="True" CanUserDeleteRows="True" Height="420">
|
||||
<controls:DataGrid.Columns>
|
||||
<controls:DataGridTextColumn Header="Name" Width="150" Binding="{Binding Name}" />
|
||||
<controls:DataGridTextColumn Header="Command" Width="250" Binding="{Binding Command}" />
|
||||
<controls:DataGridTextColumn Header="Arguments" Width="*" Binding="{Binding Argument}" />
|
||||
</controls:DataGrid.Columns>
|
||||
</controls:DataGrid>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
</UserControl>
|
@ -1,31 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace Wox.Plugin.FindFile
|
||||
{
|
||||
public partial class Setting : UserControl
|
||||
{
|
||||
public Setting()
|
||||
{
|
||||
InitializeComponent();
|
||||
menuGrid.ItemsSource = FindFileContextMenuStorage.Instance.ContextMenus;
|
||||
menuGrid.CurrentCellChanged += menuGrid_CurrentCellChanged;
|
||||
}
|
||||
|
||||
void menuGrid_CurrentCellChanged(object sender, EventArgs e)
|
||||
{
|
||||
FindFileContextMenuStorage.Instance.Save();
|
||||
}
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 7.4 KiB |
@ -1,34 +0,0 @@
|
||||
#encoding=utf8
|
||||
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
import webbrowser
|
||||
from wox import Wox,WoxAPI
|
||||
|
||||
class HackerNews(Wox):
|
||||
|
||||
def query(self,key):
|
||||
proxies = {}
|
||||
if self.proxy and self.proxy.get("enabled") and self.proxy.get("server"):
|
||||
proxies = {
|
||||
"http": "http://{}:{}".format(self.proxy.get("server"),self.proxy.get("port")),
|
||||
"http": "https://{}:{}".format(self.proxy.get("server"),self.proxy.get("port"))
|
||||
}
|
||||
#self.debug(proxies)
|
||||
r = requests.get('https://news.ycombinator.com/',proxies = proxies)
|
||||
bs = BeautifulSoup(r.text)
|
||||
results = []
|
||||
for i in bs.select(".comhead"):
|
||||
title = i.previous_sibling.text
|
||||
url = i.previous_sibling["href"]
|
||||
results.append({"Title": title ,"IcoPath":"Images/app.ico","JsonRPCAction":{"method": "openUrl","parameters":[url],"dontHideAfterAction":True}})
|
||||
|
||||
return results
|
||||
|
||||
def openUrl(self,url):
|
||||
webbrowser.open(url)
|
||||
#todo:doesn't work when move this line up
|
||||
WoxAPI.change_query(url)
|
||||
|
||||
if __name__ == "__main__":
|
||||
HackerNews()
|
@ -1,12 +0,0 @@
|
||||
{
|
||||
"ID":"D2D2C23B084D411DB66FE0C79D6C1B7H",
|
||||
"ActionKeyword":"hn",
|
||||
"Name":"Hacker News",
|
||||
"Description":"Hacker News@https://news.ycombinator.com",
|
||||
"Author":"qianlifeng",
|
||||
"Version":"1.0",
|
||||
"Language":"python",
|
||||
"Website":"http://www.getwox.com",
|
||||
"IcoPath":"Images\\app.ico",
|
||||
"ExecuteFileName":"main.py"
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
..\..\PythonHome\python.exe main.py "{\"jsonrpc\": \"2.0\", \"method\": \"query\", \"params\": \"l\", \"id\": 1}
|
||||
REM ..\..\PythonHome\python.exe main.py "{\"method\":\"openUrl\",\"parameters\":[\"https://blog.pinboard.in/2014/07/pinboard_turns_five/\",2]}"
|