From 8d2aa1fc099057f37f33c58483d73c0e819fb8c9 Mon Sep 17 00:00:00 2001 From: qianlifeng Date: Tue, 19 Aug 2014 13:09:44 +0800 Subject: [PATCH 01/19] Update README.md --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index da16335eaf..c44b0e0636 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,16 @@ Download from [release page](https://github.com/qianlifeng/Wox/releases). * **Windows XP users:** You have to install [.NET Framework 3.5](http://www.microsoft.com/download/details.aspx?id=22) if you have not installed yet. * **Windows 8 users:** You have to [enable the .NET Framework 3.5 in Control Panel](http://msdn.microsoft.com/library/hh506443.aspx). + +Contribute +========= + +If you are a developer, please feel free to send a pull request to **Dev** branch. We still have a lot functions and bugs need to do now. Just pick one from [issues page](https://github.com/qianlifeng/Wox/issues) that you think you can fix. + +If you are not a developer, you can also help Wox by contributing the Wox wiki page, for example [Wox Function Guide](https://github.com/qianlifeng/Wox/wiki/Wox-Function-Guide). + + + Create and Share Plugin ========= From 1573738584c4b574d3d26a09225da457fd9baae7 Mon Sep 17 00:00:00 2001 From: qianlifeng Date: Mon, 13 Oct 2014 17:13:35 +0800 Subject: [PATCH 02/19] Revert readme --- README.md | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e7ea29e58e..fe30839e80 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,62 @@ -Wox [![Build status](https://ci.appveyor.com/api/projects/status/bfktntbivg32e103/branch/dev)](https://ci.appveyor.com/project/qianlifeng/wox/branch/dev) +Wox [![Build status](https://ci.appveyor.com/api/projects/status/bfktntbivg32e103)](https://ci.appveyor.com/project/qianlifeng/wox) +========= +[Wox](http://www.getwox.com) is an effective launcher for windows, which was inspired by [Alfred](http://www.alfredapp.com/) and [Launchy](http://www.launchy.net/). Wox provide bundles of features let you access infomations quickly. + +Features +========= +1. Search applications, files (via everything plugin) and chrome bookmarks +2. Search web contents with shortcuts (e.g. search google with `g keyword` or `youtube keyword`) +3. Search clipboard history (via clipboard plugin) +4. Themes support, get more themes from [http://www.getwox.com/theme](http://www.getwox.com/theme) +5. Plugin support, get more plugins from [http://www.getwox.com/plugin](http://www.getwox.com/plugin) + +Screenshot ========= -This is Wox Dev branch. We will develop new feature here and merge to master when we want to release a new version. -**Please send pull request to this branch if you want to contribute codes** +More screenshot + + +Download +========= + +Download from [release page](https://github.com/qianlifeng/Wox/releases). + +* **Windows XP users:** You have to install [.NET Framework 3.5](http://www.microsoft.com/download/details.aspx?id=22) if you have not installed yet. +* **Windows 8 users:** You have to [enable the .NET Framework 3.5 in Control Panel](http://msdn.microsoft.com/library/hh506443.aspx). + + +Contribute +========= + +If you are a developer, please feel free to send a pull request to **Dev** branch. We still have a lot functions and bugs need to do now. Just pick one from [issues page](https://github.com/qianlifeng/Wox/issues) that you think you can fix. + +If you are not a developer, you can also help Wox by contributing the Wox wiki page, for example [Wox Function Guide](https://github.com/qianlifeng/Wox/wiki/Wox-Function-Guide). + + + +Create and Share Plugin +========= + +Currently, Wox support using C# and Python to write your plugins. Please refer to [Create-plugin](https://github.com/qianlifeng/Wox/wiki/Create-plugins) page for more infomation. +You can share your plugin with WoxPlugins. After you upload your plugin, other uses can download or search your plugin through `wpm install ` command (this is a plugin for plugin management, which is one of the default plugins inside Wox). Please refer to [How-to-share-your-plugins](https://github.com/qianlifeng/Wox/wiki/How-to-share-your-plugins-in--getwox.com-plugin-page%3F) for details. + + +Create and Share Theme +========= + +Wox provide an online theme editor [http://www.getwox.com/themebuilder](http://www.getwox.com/themebuilder), you build your own theme for wox. + + + +Most Asked Questions +========= + +1. **How to install plugin?** + + Refer to [https://github.com/qianlifeng/Wox/wiki/How-to-install-Plugins](https://github.com/qianlifeng/Wox/wiki/How-to-install-Plugins) + + +2. **How to open setting dialog?** + + Refer to [https://github.com/qianlifeng/Wox/wiki/How-to-open-setting-dialog](https://github.com/qianlifeng/Wox/wiki/How-to-open-setting-dialog) + From 581423a87cebc172f15a3f33086cb9e12528f6dc Mon Sep 17 00:00:00 2001 From: qianlifeng Date: Wed, 22 Oct 2014 18:36:49 +0800 Subject: [PATCH 03/19] Add MFT Searcher --- .../MFTSearch/MFTSearchRecord.cs | 27 ++ Wox.Infrastructure/MFTSearch/MFTSearcher.cs | 262 ++++++++++++++++++ .../MFTSearch/MFTSearcherCache.cs | 136 +++++++++ Wox.Infrastructure/MFTSearch/PInvokeWin32.cs | 165 +++++++++++ .../MFTSearch/USNChangeReason.cs | 47 ++++ Wox.Infrastructure/MFTSearch/USNRecord.cs | 34 +++ Wox.Infrastructure/MFTSearch/USNRecordType.cs | 8 + Wox.Infrastructure/MFTSearch/VolumeMonitor.cs | 158 +++++++++++ Wox.Infrastructure/Wox.Infrastructure.csproj | 9 + 9 files changed, 846 insertions(+) create mode 100644 Wox.Infrastructure/MFTSearch/MFTSearchRecord.cs create mode 100644 Wox.Infrastructure/MFTSearch/MFTSearcher.cs create mode 100644 Wox.Infrastructure/MFTSearch/MFTSearcherCache.cs create mode 100644 Wox.Infrastructure/MFTSearch/PInvokeWin32.cs create mode 100644 Wox.Infrastructure/MFTSearch/USNChangeReason.cs create mode 100644 Wox.Infrastructure/MFTSearch/USNRecord.cs create mode 100644 Wox.Infrastructure/MFTSearch/USNRecordType.cs create mode 100644 Wox.Infrastructure/MFTSearch/VolumeMonitor.cs diff --git a/Wox.Infrastructure/MFTSearch/MFTSearchRecord.cs b/Wox.Infrastructure/MFTSearch/MFTSearchRecord.cs new file mode 100644 index 0000000000..3186ec97f6 --- /dev/null +++ b/Wox.Infrastructure/MFTSearch/MFTSearchRecord.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Wox.Infrastructure.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; } + } + } +} diff --git a/Wox.Infrastructure/MFTSearch/MFTSearcher.cs b/Wox.Infrastructure/MFTSearch/MFTSearcher.cs new file mode 100644 index 0000000000..044969b6d8 --- /dev/null +++ b/Wox.Infrastructure/MFTSearch/MFTSearcher.cs @@ -0,0 +1,262 @@ +/* + * 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.Linq; +using System.Runtime.InteropServices; +using MyEverything; + +namespace Wox.Infrastructure.MFTSearch +{ + + public class MFTSearcher + { + private static MFTSearcherCache cache = new MFTSearcherCache(); + + public static void IndexVolume(string volume) + { + List files; + List folders; + EnumerateVolume(volume, out files, out folders); + cache.AddRecord(volume, files, USNRecordType.File); + cache.AddRecord(volume, folders, USNRecordType.Folder); + } + + public static void IndexAllVolumes() + { + foreach (DriveInfo drive in DriveInfo.GetDrives()) + { + IndexVolume(drive.VolumeLabel); + } + } + + public static List Search(string item) + { + return null; + } + + private static void AddVolumeRootRecord(string volumeName, ref List folders) + { + 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; + + folders.Add(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, out List files, out List flds) + { + files = new List(); + flds = new List(); + IntPtr medBuffer = IntPtr.Zero; + IntPtr pVolume = IntPtr.Zero; + try + { + AddVolumeRootRecord(volumeName, ref flds); + pVolume = GetVolumeJournalHandle(volumeName); + EnableVomuleJournal(pVolume); + + SetupMFTEnumInBuffer(ref medBuffer, pVolume); + EnumerateFiles(volumeName, pVolume, medBuffer, ref files, ref flds); + } + 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, ref List files, ref List folders) + { + 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); + + if (usn.IsFolder) + { + folders.Add(new USNRecord + { + Name = usn.FileName, + ParentFrn = usn.ParentFRN, + FRN = usn.FRN, + IsFolder = true, + VolumeName = volumeName + }); + } + else + { + files.Add(new USNRecord + { + Name = usn.FileName, + ParentFrn = usn.ParentFRN, + FRN = usn.FRN, + IsFolder = false, + 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.GetFolderSource(volume); + string fullpath = record.Name; + FindRecordPath(record, ref fullpath, fdSource); + record.FullPath = fullpath; + } + private static void FindRecordPath(USNRecord curRecord, ref string fullpath, Dictionary 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); + } + } +} diff --git a/Wox.Infrastructure/MFTSearch/MFTSearcherCache.cs b/Wox.Infrastructure/MFTSearch/MFTSearcherCache.cs new file mode 100644 index 0000000000..d6f19bb5bf --- /dev/null +++ b/Wox.Infrastructure/MFTSearch/MFTSearcherCache.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using MyEverything; + +namespace Wox.Infrastructure.MFTSearch +{ + internal class MFTSearcherCache + { + private Dictionary> _volumes_files = new Dictionary>(); + private Dictionary> _volumes_folders = new Dictionary>(); + + public MFTSearcherCache() { } + + public bool ContainsVolume(string volume) + { + return _volumes_files.ContainsKey(volume) && _volumes_folders.ContainsKey(volume); + } + public void AddRecord(string volume, List r, USNRecordType type) + { + if (type == USNRecordType.File) + { + CheckHashTableKey(_volumes_files, volume); + r.ForEach(x => _volumes_files[volume].Add(x.FRN, x)); + } + else + { + CheckHashTableKey(_volumes_folders, volume); + r.ForEach(x => _volumes_folders[volume].Add(x.FRN, x)); + } + } + public void AddRecord(string volume, USNRecord record, USNRecordType type) + { + if (type == USNRecordType.File) + { + CheckHashTableKey(_volumes_files, volume); + _volumes_files[volume].Add(record.FRN, record); + } + else + { + CheckHashTableKey(_volumes_folders, volume); + _volumes_folders[volume].Add(record.FRN, record); + } + } + private void CheckHashTableKey(Dictionary> hashtable, string key) + { + if (!hashtable.ContainsKey(key)) + hashtable.Add(key, new Dictionary()); + } + public bool DeleteRecord(string volume, ulong frn) + { + bool result = false; + result = DeleteRecordHashTableItem(_volumes_files, volume, frn); + if (!result) result = DeleteRecordHashTableItem(_volumes_folders, volume, frn); + return result; + } + private bool DeleteRecordHashTableItem(Dictionary> hashtable, string volume, ulong frn) + { + if (hashtable.ContainsKey(volume) && hashtable[volume].ContainsKey(frn)) + { + hashtable[volume].Remove(frn); + return true; + } + else + { + return false; + } + } + public void UpdateRecord(string volume, USNRecord record, USNRecordType type) + { + if (type == USNRecordType.File) + RealUpdateRecord(volume, _volumes_files, record); + else + RealUpdateRecord(volume, _volumes_folders, record); + } + private bool RealUpdateRecord(string volume, Dictionary> source, USNRecord record) + { + if (source.ContainsKey(volume) && source[volume].ContainsKey(record.FRN)) + { + source[volume][record.FRN] = record; + return true; + } + else + { + return false; + } + } + public List FindByName(string filename, out long foundFileCnt, out long fountFolderCnt) + { + + var fileQuery = from filesInVolumeDic in _volumes_files.Values + from eachFilePair in filesInVolumeDic + where eachFilePair.Value.Name.Contains(filename) + select eachFilePair.Value; + + var folderQuery = from fldsInVolumeDic in _volumes_folders.Values + from eachFldPair in fldsInVolumeDic + where eachFldPair.Value.Name.Contains(filename) + select eachFldPair.Value; + + foundFileCnt = fileQuery.Count(); + fountFolderCnt = folderQuery.Count(); + + List result = new List(); + + result.AddRange(fileQuery); + result.AddRange(folderQuery); + + return result; + } + public USNRecord FindByFrn(string volume, ulong frn) + { + if ((!_volumes_files.ContainsKey(volume)) || (!_volumes_folders.ContainsKey(volume))) + throw new Exception(string.Format("DB not contain the volume: {0}", volume)); + USNRecord result = null; + _volumes_files[volume].TryGetValue(frn, out result); + if (result != null) return result; + _volumes_folders[volume].TryGetValue(frn, out result); + return result; + } + public long FileCount + { + get { return _volumes_files.Sum(x => x.Value.Count); } + } + public long FolderCount + { + get { return _volumes_folders.Sum(x => x.Value.Count); } + } + public Dictionary GetFolderSource(string volume) + { + Dictionary result = null; + _volumes_folders.TryGetValue(volume, out result); + return result; + } + } +} diff --git a/Wox.Infrastructure/MFTSearch/PInvokeWin32.cs b/Wox.Infrastructure/MFTSearch/PInvokeWin32.cs new file mode 100644 index 0000000000..6d536c2455 --- /dev/null +++ b/Wox.Infrastructure/MFTSearch/PInvokeWin32.cs @@ -0,0 +1,165 @@ +using System; +using System.Runtime.InteropServices; + +namespace Wox.Infrastructure.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); } + } + } + } +} diff --git a/Wox.Infrastructure/MFTSearch/USNChangeReason.cs b/Wox.Infrastructure/MFTSearch/USNChangeReason.cs new file mode 100644 index 0000000000..61095a6a57 --- /dev/null +++ b/Wox.Infrastructure/MFTSearch/USNChangeReason.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Wox.Infrastructure.MFTSearch +{ + internal class USNChangeReason + { + public static Dictionary USN_REASONS = new Dictionary { + {"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(); + } + } +} diff --git a/Wox.Infrastructure/MFTSearch/USNRecord.cs b/Wox.Infrastructure/MFTSearch/USNRecord.cs new file mode 100644 index 0000000000..64c0ee05e7 --- /dev/null +++ b/Wox.Infrastructure/MFTSearch/USNRecord.cs @@ -0,0 +1,34 @@ +using System; +using MyEverything; + +namespace Wox.Infrastructure.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 + }; + } + } +} diff --git a/Wox.Infrastructure/MFTSearch/USNRecordType.cs b/Wox.Infrastructure/MFTSearch/USNRecordType.cs new file mode 100644 index 0000000000..41c68076cc --- /dev/null +++ b/Wox.Infrastructure/MFTSearch/USNRecordType.cs @@ -0,0 +1,8 @@ +namespace Wox.Infrastructure.MFTSearch +{ + internal enum USNRecordType + { + File, + Folder + } +} \ No newline at end of file diff --git a/Wox.Infrastructure/MFTSearch/VolumeMonitor.cs b/Wox.Infrastructure/MFTSearch/VolumeMonitor.cs new file mode 100644 index 0000000000..c65cf866d9 --- /dev/null +++ b/Wox.Infrastructure/MFTSearch/VolumeMonitor.cs @@ -0,0 +1,158 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; +using System.Threading; +using System.Diagnostics; +using System.IO; +using Wox.Infrastructure.MFTSearch; + +namespace MyEverything +{ + internal class VolumeMonitor + { + + public Action RecordAddedEvent; + public Action RecordDeletedEvent; + public Action RecordRenameEvent; + + public void Monitor(List volumes, MFTSearcherCache db) + { + foreach (var volume in volumes) + { + 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.")); + Thread th = new Thread(new ParameterizedThreadStart(MonitorThread)); + th.Start(new Dictionary { { "Volume", volume }, { "MFTSearcherCache", 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(); + Wox.Infrastructure.MFTSearch.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(object param) + { + + MFTSearcherCache db = (param as Dictionary)["MFTSearcherCache"] as MFTSearcherCache; + string volume = (param as Dictionary)["Volume"] as string; + 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); + + Debug.WriteLine(string.Format("\nMoniting on {0}......", volume)); + IntPtr pVolume = Wox.Infrastructure.MFTSearch.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) + { + var dbCached = db.FindByFrn(volume, usn.FRN); + Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, dbCached, db); + Debug.WriteLine(string.Format("------USN[frn={0}]------", usn.FRN)); + Debug.WriteLine(string.Format("FileName={0}, USNChangeReason={1}", usn.FileName, USNChangeReason.ReasonPrettyFormat(usn.Reason))); + Debug.WriteLine(string.Format("FileName[Cached]={0}", dbCached == null ? "NoCache" : dbCached.FullPath)); + Debug.WriteLine("--------------------------------------"); + + 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) + { + return; + } + else + { + Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, cached, db); + var deleteok = db.DeleteRecord(volume, usn.FRN); + Debug.WriteLine(string.Format(">>>> File {0} deleted {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); + //string fullpath = newRecord.Name; + //db.FindRecordPath(newRecord, ref fullpath, db.GetFolderSource(volume)); + //newRecord.FullPath = fullpath; + var oldRecord = db.FindByFrn(volume, usn.FRN); + Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, oldRecord, db); + Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, newRecord, db); + Debug.WriteLine(string.Format(">>>> RenameFile {0} to {1}", oldRecord.FullPath, newRecord.FullPath)); + db.UpdateRecord(volume, newRecord, + usn.IsFolder ? USNRecordType.Folder : USNRecordType.File); + if (RecordRenameEvent != null) RecordRenameEvent(oldRecord, newRecord); + if (newRecord.FullPath.Contains("$RECYCLE.BIN")) + { + Debug.WriteLine(string.Format(">>>> Means {0} moved to recycle.", oldRecord.FullPath)); + } + } + private void ProcessFileCreate(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db) + { + USNRecord record = USNRecord.ParseUSN(volume, usn); + //string fullpath = record.Name; + //db.FindRecordPath(record, ref fullpath, db.GetFolderSource(volume)); + //record.FullPath = fullpath; + db.AddRecord(volume, record, usn.IsFolder ? USNRecordType.Folder : USNRecordType.File); + Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, record, db); + Debug.WriteLine(string.Format(">>>> NewFile: {0}", record.FullPath)); + if (RecordAddedEvent != null) + RecordAddedEvent(record); + } + + + private bool MaskEqual(uint target, uint compare) + { + return (target & compare) != 0; + } + } +} diff --git a/Wox.Infrastructure/Wox.Infrastructure.csproj b/Wox.Infrastructure/Wox.Infrastructure.csproj index 040b9d2be4..ae41dfffaa 100644 --- a/Wox.Infrastructure/Wox.Infrastructure.csproj +++ b/Wox.Infrastructure/Wox.Infrastructure.csproj @@ -22,6 +22,7 @@ DEBUG;TRACE prompt 4 + true pdbonly @@ -55,6 +56,14 @@ + + + + + + + + From 80e38fc4307f8cb674cb894d63b155ae25c72560 Mon Sep 17 00:00:00 2001 From: qianlifeng Date: Wed, 22 Oct 2014 22:49:34 +0800 Subject: [PATCH 04/19] Add find file plugin. --- Plugins/Wox.Plugin.BrowserBookmark/Main.cs | 2 +- Plugins/Wox.Plugin.FindFile/Images/file.png | Bin 0 -> 1145 bytes Plugins/Wox.Plugin.FindFile/Images/find.png | Bin 0 -> 522 bytes Plugins/Wox.Plugin.FindFile/Images/folder.png | Bin 0 -> 4260 bytes .../Wox.Plugin.FindFile/Images/warning.png | Bin 0 -> 5247 bytes Plugins/Wox.Plugin.FindFile/Main.cs | 74 ++++++++ .../Properties/AssemblyInfo.cs | 36 ++++ .../Wox.Plugin.FindFile.csproj | 81 ++++++++ Plugins/Wox.Plugin.FindFile/plugin.json | 12 ++ .../Wox.Plugin.PluginManagement.csproj | 174 +++++++++--------- Wox.Infrastructure/MFTSearch/MFTSearcher.cs | 18 +- .../MFTSearch/MFTSearcherCache.cs | 11 +- Wox.Infrastructure/Properties/AssemblyInfo.cs | 74 ++++---- Wox.Test/MFTSearcherTest.cs | 32 ++++ Wox.Test/Wox.Test.csproj | 1 + Wox.sln | 9 +- Wox/Commands/CommandFactory.cs | 14 +- Wox/Commands/SystemCommand.cs | 4 +- Wox/MainWindow.xaml.cs | 1 + Wox/PluginLoader/Plugins.cs | 3 +- Wox/Properties/AssemblyInfo.cs | 108 +++++------ Wox/Wox.csproj | 12 ++ Wox/app.manifest | 15 ++ 23 files changed, 478 insertions(+), 203 deletions(-) create mode 100644 Plugins/Wox.Plugin.FindFile/Images/file.png create mode 100644 Plugins/Wox.Plugin.FindFile/Images/find.png create mode 100644 Plugins/Wox.Plugin.FindFile/Images/folder.png create mode 100644 Plugins/Wox.Plugin.FindFile/Images/warning.png create mode 100644 Plugins/Wox.Plugin.FindFile/Main.cs create mode 100644 Plugins/Wox.Plugin.FindFile/Properties/AssemblyInfo.cs create mode 100644 Plugins/Wox.Plugin.FindFile/Wox.Plugin.FindFile.csproj create mode 100644 Plugins/Wox.Plugin.FindFile/plugin.json create mode 100644 Wox.Test/MFTSearcherTest.cs create mode 100644 Wox/app.manifest diff --git a/Plugins/Wox.Plugin.BrowserBookmark/Main.cs b/Plugins/Wox.Plugin.BrowserBookmark/Main.cs index 11aa3f9f2f..9bf4c885b3 100644 --- a/Plugins/Wox.Plugin.BrowserBookmark/Main.cs +++ b/Plugins/Wox.Plugin.BrowserBookmark/Main.cs @@ -8,7 +8,7 @@ namespace Wox.Plugin.BrowserBookmark { private PluginInitContext context; - // TODO: periodically refresh the cache? + // TODO: periodically refresh the Cache? private List cachedBookmarks = new List(); public void Init(PluginInitContext context) diff --git a/Plugins/Wox.Plugin.FindFile/Images/file.png b/Plugins/Wox.Plugin.FindFile/Images/file.png new file mode 100644 index 0000000000000000000000000000000000000000..2913d69623b922f210b3910313ceb2fe97a706f0 GIT binary patch literal 1145 zcmV-<1cv*GP)3RSTBK}CXsAACVIT15yxDA*P&J}Q1FRg_9=vq+`JR z{Leji80M6B+kO**Gk89S5CUKf3gnIM49J=sDs@cTCNkL^Vo4pHdtYE!ps;fRYwx-> zsE0x-3WkfERY2bIVAw7u4FglU57TlG9XpGmvl-YXTM$wmmKuyR>AXbU3O6K2QIbyQ)zUZ=);{iUXRY9IDUQWS$19k-*sWaBY;XXc40YrSY$

CwA)bHW_E`%!FAmEP^-B;buym0@ zT6CNo3dVI^ATOMt{^zMtoJo#j@RL_60b84Y7MmZrV^#xBV$M9oN)Wk5a<+iyI>kV+ zIBDc!ENh^qM#G8d2=@KZjp634m4GcDelK2KdrtuH2;dN)sx&4_4-3*{nxe^ZTyU4P zkr76qbk@RUmsX?eR06vX{f?2(UaJIb+S@7`H#}Ul0MZp4(uNRSv^mdtz5<)uFgzP} zp1~Cs0Zgp8B8+2$aq>hvMh|YQ1gvXn5xbvj2ml7nPLKt3MKvXi5c$ZbI;T`oCF>rE z?vVvH^?EKQas{kfaV7rfi{qJnhmmUCUI}Q3d@4TJ{CEJ!7#376f|qLK7L_T*a3Y^6 zDp^E=_;i}wg-60q=mu`Sb{UTSJ%Y!Y4r1cV9hHF9JDNqymPZ4?WWEqMK8X52Y=#gy zs+wSq6ea{*B!M0yYe|Egi5spC<79Lc^^N5i zx#VIB(*)Ku9>C<+ivdu(s!D@PGgcLiT&ICkI#F0Loh%90pnE8Rhav|swHN>b3sj0C z0?-j6F{GEI106~yOKUFx;NKj>N-Ge-rety-SJhsE;{;f9ApmmLGK5(mzDy%NuDQH+ zVZcowYcoJ92{f58-kfQNMjZvfoB30ZX5FL-c&~((IPGm?HOvx=rsPeRyXj zptj+4(ciLd(J!AVtJdv;^~*c+1LWNm(kbG+UMfFx80D{-G6VPrGrycSN)dQN00000 LNkvXXu0mjfx$gec literal 0 HcmV?d00001 diff --git a/Plugins/Wox.Plugin.FindFile/Images/find.png b/Plugins/Wox.Plugin.FindFile/Images/find.png new file mode 100644 index 0000000000000000000000000000000000000000..f4a7b2a0007f3eaaf97c982f531608c6bb206eaa GIT binary patch literal 522 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UOiAAEE)4(M`_JqL@;D1TB8!2v z2N=7Z%(epwmK8Xr18D^?ZvQoBE&~Ijxu=U`h{y4zQ&*R@7zni4S1AbyY72CTifV_2 zeEB<{X(Ll$U}Hq1gNs5DpXi;UnQtb2nk}PdEI-rJNK@_H%f~5yDjR0CCvBe+vva|8 z{lgB&HQ4SegnP+_{S)_G0nT|>hVLqjW511kdyT>~>K1A}Vbk(CKhzbR0|{wM#WfEpM)UHx3vIVCg!0LdA@=Kufz literal 0 HcmV?d00001 diff --git a/Plugins/Wox.Plugin.FindFile/Images/folder.png b/Plugins/Wox.Plugin.FindFile/Images/folder.png new file mode 100644 index 0000000000000000000000000000000000000000..330cb2e4bf8ac344014dd3d22910de1ae884343a GIT binary patch literal 4260 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 literal 0 HcmV?d00001 diff --git a/Plugins/Wox.Plugin.FindFile/Images/warning.png b/Plugins/Wox.Plugin.FindFile/Images/warning.png new file mode 100644 index 0000000000000000000000000000000000000000..b1b5f0acd3b8d28f499b2fcc995711ce3b1cd585 GIT binary patch literal 5247 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 Query(Query query) + { + if (!initial) + { + return new List() + { + 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, {1} folder indexed, {2}ms has spent.", MFTSearcher.IndexedFileCount, MFTSearcher.IndexedFolderCount, 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; + } + }; + } + } +} diff --git a/Plugins/Wox.Plugin.FindFile/Properties/AssemblyInfo.cs b/Plugins/Wox.Plugin.FindFile/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..1484395d76 --- /dev/null +++ b/Plugins/Wox.Plugin.FindFile/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +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")] diff --git a/Plugins/Wox.Plugin.FindFile/Wox.Plugin.FindFile.csproj b/Plugins/Wox.Plugin.FindFile/Wox.Plugin.FindFile.csproj new file mode 100644 index 0000000000..d16a7a5783 --- /dev/null +++ b/Plugins/Wox.Plugin.FindFile/Wox.Plugin.FindFile.csproj @@ -0,0 +1,81 @@ + + + + + Debug + AnyCPU + {84EA88B4-71F2-4A3D-9771-D7B0244C0D81} + Library + Properties + Wox.Plugin.FindFile + Wox.Plugin.FindFile + v3.5 + 512 + + + + true + full + false + ..\..\Output\Debug\Plugins\Wox.Plugin.FindFile\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\Output\Release\Plugins\Wox.Plugin.FindFile\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + {4fd29318-a8ab-4d8f-aa47-60bc241b8da3} + Wox.Infrastructure + + + {8451ecdd-2ea4-4966-bb0a-7bbc40138e80} + Wox.Plugin + + + + + + Always + + + Always + + + Always + + + + + PreserveNewest + + + + + \ No newline at end of file diff --git a/Plugins/Wox.Plugin.FindFile/plugin.json b/Plugins/Wox.Plugin.FindFile/plugin.json new file mode 100644 index 0000000000..ed9c9f3930 --- /dev/null +++ b/Plugins/Wox.Plugin.FindFile/plugin.json @@ -0,0 +1,12 @@ +{ + "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" +} diff --git a/Plugins/Wox.Plugin.PluginManagement/Wox.Plugin.PluginManagement.csproj b/Plugins/Wox.Plugin.PluginManagement/Wox.Plugin.PluginManagement.csproj index 4b061e3dfd..d080cc10f8 100644 --- a/Plugins/Wox.Plugin.PluginManagement/Wox.Plugin.PluginManagement.csproj +++ b/Plugins/Wox.Plugin.PluginManagement/Wox.Plugin.PluginManagement.csproj @@ -1,88 +1,88 @@ - - - - - Debug - AnyCPU - {049490F0-ECD2-4148-9B39-2135EC346EBE} - Library - Properties - Wox.Plugin.PluginManagement - Wox.Plugin.PluginManagement - v3.5 - 512 - ..\..\ - true - - - true - full - false - ..\..\Output\Debug\Plugins\Wox.Plugin.PluginManagement\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - ..\..\Output\Release\Plugins\Wox.Plugin.PluginManagement\ - TRACE - prompt - 4 - - - - False - ..\..\packages\Newtonsoft.Json.6.0.5\lib\net35\Newtonsoft.Json.dll - - - - - - - - - - - - - - - - - {8451ecdd-2ea4-4966-bb0a-7bbc40138e80} - Wox.Plugin - - - - - - PreserveNewest - - - - - PreserveNewest - - - - - - - - - - - 这台计算机上缺少此项目引用的 NuGet 程序包。启用“NuGet 程序包还原”可下载这些程序包。有关详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。 - - - - + + + + + Debug + AnyCPU + {049490F0-ECD2-4148-9B39-2135EC346EBE} + Library + Properties + Wox.Plugin.PluginManagement + Wox.Plugin.PluginManagement + v3.5 + 512 + ..\..\ + true + + + true + full + false + ..\..\Output\Debug\Plugins\Wox.Plugin.PluginManagement\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\Output\Release\Plugins\Wox.Plugin.PluginManagement\ + TRACE + prompt + 4 + + + + False + ..\..\packages\Newtonsoft.Json.6.0.5\lib\net35\Newtonsoft.Json.dll + + + + + + + + + + + + + + + + + {8451ecdd-2ea4-4966-bb0a-7bbc40138e80} + Wox.Plugin + + + + + + PreserveNewest + + + + + PreserveNewest + + + + + + + + + + + 这台计算机上缺少此项目引用的 NuGet 程序包。启用“NuGet 程序包还原”可下载这些程序包。有关详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。 + + + + \ No newline at end of file diff --git a/Wox.Infrastructure/MFTSearch/MFTSearcher.cs b/Wox.Infrastructure/MFTSearch/MFTSearcher.cs index 044969b6d8..317468e885 100644 --- a/Wox.Infrastructure/MFTSearch/MFTSearcher.cs +++ b/Wox.Infrastructure/MFTSearch/MFTSearcher.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.Diagnostics; using System.IO; using System.Linq; using System.Runtime.InteropServices; @@ -30,13 +31,26 @@ namespace Wox.Infrastructure.MFTSearch { foreach (DriveInfo drive in DriveInfo.GetDrives()) { - IndexVolume(drive.VolumeLabel); + IndexVolume(drive.Name.Replace("\\", "")); } } + public static long IndexedFileCount + { + get { return cache.FileCount; } + } + public static long IndexedFolderCount + { + get { return cache.FolderCount; } + } + public static List Search(string item) { - return null; + if (string.IsNullOrEmpty(item)) return new List(); + + List found = cache.FindByName(item); + found.ForEach(x => FillPath(x.VolumeName, x, cache)); + return found.ConvertAll(o => new MFTSearchRecord(o)); } private static void AddVolumeRootRecord(string volumeName, ref List folders) diff --git a/Wox.Infrastructure/MFTSearch/MFTSearcherCache.cs b/Wox.Infrastructure/MFTSearch/MFTSearcherCache.cs index d6f19bb5bf..87c04aedde 100644 --- a/Wox.Infrastructure/MFTSearch/MFTSearcherCache.cs +++ b/Wox.Infrastructure/MFTSearch/MFTSearcherCache.cs @@ -85,22 +85,19 @@ namespace Wox.Infrastructure.MFTSearch return false; } } - public List FindByName(string filename, out long foundFileCnt, out long fountFolderCnt) + public List FindByName(string filename) { - + filename = filename.ToLower(); var fileQuery = from filesInVolumeDic in _volumes_files.Values from eachFilePair in filesInVolumeDic - where eachFilePair.Value.Name.Contains(filename) + where eachFilePair.Value.Name.ToLower().Contains(filename) select eachFilePair.Value; var folderQuery = from fldsInVolumeDic in _volumes_folders.Values from eachFldPair in fldsInVolumeDic - where eachFldPair.Value.Name.Contains(filename) + where eachFldPair.Value.Name.ToLower().Contains(filename) select eachFldPair.Value; - foundFileCnt = fileQuery.Count(); - fountFolderCnt = folderQuery.Count(); - List result = new List(); result.AddRange(fileQuery); diff --git a/Wox.Infrastructure/Properties/AssemblyInfo.cs b/Wox.Infrastructure/Properties/AssemblyInfo.cs index 1bffb5142d..cc1640d88f 100644 --- a/Wox.Infrastructure/Properties/AssemblyInfo.cs +++ b/Wox.Infrastructure/Properties/AssemblyInfo.cs @@ -1,37 +1,37 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// 有关程序集的常规信息通过以下 -// 特性集控制。更改这些特性值可修改 -// 与程序集关联的信息。 -[assembly: AssemblyTitle("Wox.Infrastructure")] -[assembly: AssemblyDescription("https://github.com/qianlifeng/Wox")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Wox.Infrastructure")] -[assembly: AssemblyCopyright("The MIT License (MIT)")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// 将 ComVisible 设置为 false 使此程序集中的类型 -// 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型, -// 则将该类型上的 ComVisible 特性设置为 true。 -[assembly: ComVisible(false)] - -// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID -[assembly: Guid("aee57a31-29e5-4f03-a41f-7917910fe90f")] - -// 程序集的版本信息由下面四个值组成: -// -// 主版本 -// 次版本 -// 生成号 -// 修订号 -// -// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, -// 方法是按如下所示使用“*”: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] -[assembly: log4net.Config.XmlConfigurator(Watch = true)] +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 有关程序集的常规信息通过以下 +// 特性集控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("Wox.Infrastructure")] +[assembly: AssemblyDescription("https://github.com/qianlifeng/Wox")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Wox.Infrastructure")] +[assembly: AssemblyCopyright("The MIT License (MIT)")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 使此程序集中的类型 +// 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型, +// 则将该类型上的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("aee57a31-29e5-4f03-a41f-7917910fe90f")] + +// 程序集的版本信息由下面四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, +// 方法是按如下所示使用“*”: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: log4net.Config.XmlConfigurator(Watch = true)] diff --git a/Wox.Test/MFTSearcherTest.cs b/Wox.Test/MFTSearcherTest.cs new file mode 100644 index 0000000000..b7f318c33d --- /dev/null +++ b/Wox.Test/MFTSearcherTest.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NUnit.Framework; +using Wox.Infrastructure.MFTSearch; + +namespace Wox.Test +{ + [TestFixture] + public class MFTSearcherTest + { + [Test] + public void MatchTest() + { + var searchtimestart = DateTime.Now; + MFTSearcher.IndexAllVolumes(); + var searchtimeend = DateTime.Now; + Console.WriteLine(string.Format("{0} file indexed, {1}ms has spent.", MFTSearcher.IndexedFileCount, searchtimeend.Subtract(searchtimestart).TotalMilliseconds)); + + searchtimestart = DateTime.Now; + List mftSearchRecords = MFTSearcher.Search("q"); + searchtimeend = DateTime.Now; + Console.WriteLine(string.Format("{0} file searched, {1}ms has spent.", mftSearchRecords.Count, searchtimeend.Subtract(searchtimestart).TotalMilliseconds)); + + searchtimestart = DateTime.Now; + mftSearchRecords = MFTSearcher.Search("ss"); + searchtimeend = DateTime.Now; + Console.WriteLine(string.Format("{0} file searched, {1}ms has spent.", mftSearchRecords.Count, searchtimeend.Subtract(searchtimestart).TotalMilliseconds)); + } + } +} diff --git a/Wox.Test/Wox.Test.csproj b/Wox.Test/Wox.Test.csproj index a7f47b1002..54cdca3d43 100644 --- a/Wox.Test/Wox.Test.csproj +++ b/Wox.Test/Wox.Test.csproj @@ -44,6 +44,7 @@ + diff --git a/Wox.sln b/Wox.sln index 1d805d99c7..5f2923c8bf 100644 --- a/Wox.sln +++ b/Wox.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 -VisualStudioVersion = 12.0.21005.1 +VisualStudioVersion = 12.0.30723.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wox.Test", "Wox.Test\Wox.Test.csproj", "{FF742965-9A80-41A5-B042-D6C7D3A21708}" EndProject @@ -19,6 +19,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wox.Plugin.PluginManagement EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wox.Plugin.BrowserBookmark", "Plugins\Wox.Plugin.BrowserBookmark\Wox.Plugin.BrowserBookmark.csproj", "{9B130CC5-14FB-41FF-B310-0A95B6894C37}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wox.Plugin.FindFile", "Plugins\Wox.Plugin.FindFile\Wox.Plugin.FindFile.csproj", "{84EA88B4-71F2-4A3D-9771-D7B0244C0D81}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -53,6 +55,10 @@ Global {9B130CC5-14FB-41FF-B310-0A95B6894C37}.Debug|Any CPU.Build.0 = Debug|Any CPU {9B130CC5-14FB-41FF-B310-0A95B6894C37}.Release|Any CPU.ActiveCfg = Release|Any CPU {9B130CC5-14FB-41FF-B310-0A95B6894C37}.Release|Any CPU.Build.0 = Release|Any CPU + {84EA88B4-71F2-4A3D-9771-D7B0244C0D81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {84EA88B4-71F2-4A3D-9771-D7B0244C0D81}.Debug|Any CPU.Build.0 = Debug|Any CPU + {84EA88B4-71F2-4A3D-9771-D7B0244C0D81}.Release|Any CPU.ActiveCfg = Release|Any CPU + {84EA88B4-71F2-4A3D-9771-D7B0244C0D81}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -60,5 +66,6 @@ Global GlobalSection(NestedProjects) = preSolution {049490F0-ECD2-4148-9B39-2135EC346EBE} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} {9B130CC5-14FB-41FF-B310-0A95B6894C37} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} + {84EA88B4-71F2-4A3D-9771-D7B0244C0D81} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} EndGlobalSection EndGlobal diff --git a/Wox/Commands/CommandFactory.cs b/Wox/Commands/CommandFactory.cs index b248afa716..fc18439b46 100644 --- a/Wox/Commands/CommandFactory.cs +++ b/Wox/Commands/CommandFactory.cs @@ -10,21 +10,11 @@ namespace Wox.Commands { internal static class CommandFactory { - private static PluginCommand pluginCmd; - private static SystemCommand systemCmd; + private static PluginCommand pluginCmd = new PluginCommand(); + private static SystemCommand systemCmd = new SystemCommand(); public static void DispatchCommand(Query query) { - //lazy init command instance. - if (pluginCmd == null) - { - pluginCmd = new PluginCommand(); - } - if (systemCmd == null) - { - systemCmd = new SystemCommand(); - } - if (Plugins.HitThirdpartyKeyword(query)) { pluginCmd.Dispatch(query); diff --git a/Wox/Commands/SystemCommand.cs b/Wox/Commands/SystemCommand.cs index 50b38959fd..162011f8a8 100644 --- a/Wox/Commands/SystemCommand.cs +++ b/Wox/Commands/SystemCommand.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; +using Wox.Infrastructure.MFTSearch; using Wox.Infrastructure.Storage.UserSettings; using Wox.Plugin; using Wox.Plugin.SystemPlugins; @@ -12,9 +13,10 @@ namespace Wox.Commands { public class SystemCommand : BaseCommand { + private IEnumerable allSytemPlugins = Plugins.AllPlugins.Where(o => o.Metadata.PluginType == PluginType.System); + public override void Dispatch(Query query) { - var allSytemPlugins = Plugins.AllPlugins.Where(o => o.Metadata.PluginType == PluginType.System); if (UserSettingStorage.Instance.WebSearches.Exists(o => o.ActionWord == query.ActionName && o.Enabled)) { //websearch mode diff --git a/Wox/MainWindow.xaml.cs b/Wox/MainWindow.xaml.cs index d0b5ca5318..e44a65d539 100644 --- a/Wox/MainWindow.xaml.cs +++ b/Wox/MainWindow.xaml.cs @@ -17,6 +17,7 @@ using NHotkey.Wpf; using Wox.Commands; using Wox.Helper; using Wox.Infrastructure; +using Wox.Infrastructure.MFTSearch; using Wox.Infrastructure.Storage; using Wox.Infrastructure.Storage.UserSettings; using Wox.Plugin; diff --git a/Wox/PluginLoader/Plugins.cs b/Wox/PluginLoader/Plugins.cs index ac373b8c93..102f7c4f70 100644 --- a/Wox/PluginLoader/Plugins.cs +++ b/Wox/PluginLoader/Plugins.cs @@ -32,7 +32,8 @@ namespace Wox.PluginLoader })); } - forker.Join(); + //if plugin init do heavy works, join here will block the UI + //forker.Join(); } public static List AllPlugins diff --git a/Wox/Properties/AssemblyInfo.cs b/Wox/Properties/AssemblyInfo.cs index a96441ba2a..0d694b4f83 100644 --- a/Wox/Properties/AssemblyInfo.cs +++ b/Wox/Properties/AssemblyInfo.cs @@ -1,55 +1,55 @@ -using System.Reflection; -using System.Resources; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Windows; - -// 有关程序集的常规信息通过以下 -// 特性集控制。更改这些特性值可修改 -// 与程序集关联的信息。 -[assembly: AssemblyTitle("Wox")] -[assembly: AssemblyDescription("https://github.com/qianlifeng/Wox")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Wox")] -[assembly: AssemblyCopyright("The MIT License (MIT)")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// 将 ComVisible 设置为 false 使此程序集中的类型 -// 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型, -// 则将该类型上的 ComVisible 特性设置为 true。 -[assembly: ComVisible(false)] - -//若要开始生成可本地化的应用程序,请在 -// 中的 .csproj 文件中 -//设置 CultureYouAreCodingWith。例如,如果您在源文件中 -//使用的是美国英语,请将 设置为 en-US。然后取消 -//对以下 NeutralResourceLanguage 特性的注释。更新 -//以下行中的“en-US”以匹配项目文件中的 UICulture 设置。 - -//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] - - -[assembly: ThemeInfo( - ResourceDictionaryLocation.None, //主题特定资源词典所处位置 - //(在页面或应用程序资源词典中 - // 未找到某个资源的情况下使用) - ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置 - //(在页面、应用程序或任何主题特定资源词典中 - // 未找到某个资源的情况下使用) -)] - - -// 程序集的版本信息由下面四个值组成: -// -// 主版本 -// 次版本 -// 生成号 -// 修订号 -// -// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, -// 方法是按如下所示使用“*”: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// 有关程序集的常规信息通过以下 +// 特性集控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("Wox")] +[assembly: AssemblyDescription("https://github.com/qianlifeng/Wox")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Wox")] +[assembly: AssemblyCopyright("The MIT License (MIT)")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 使此程序集中的类型 +// 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型, +// 则将该类型上的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +//若要开始生成可本地化的应用程序,请在 +// 中的 .csproj 文件中 +//设置 CultureYouAreCodingWith。例如,如果您在源文件中 +//使用的是美国英语,请将 设置为 en-US。然后取消 +//对以下 NeutralResourceLanguage 特性的注释。更新 +//以下行中的“en-US”以匹配项目文件中的 UICulture 设置。 + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //主题特定资源词典所处位置 + //(在页面或应用程序资源词典中 + // 未找到某个资源的情况下使用) + ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置 + //(在页面、应用程序或任何主题特定资源词典中 + // 未找到某个资源的情况下使用) +)] + + +// 程序集的版本信息由下面四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, +// 方法是按如下所示使用“*”: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/Wox/Wox.csproj b/Wox/Wox.csproj index 14f4194d30..6dbd0ac08f 100644 --- a/Wox/Wox.csproj +++ b/Wox/Wox.csproj @@ -58,6 +58,9 @@ Wox.EntryPoint + + app.manifest + @@ -202,6 +205,7 @@ Designer MSBuild:Compile + MSBuild:Compile Designer @@ -380,6 +384,14 @@ + + + + + + + + diff --git a/Wox/app.manifest b/Wox/app.manifest new file mode 100644 index 0000000000..1eb9c6c494 --- /dev/null +++ b/Wox/app.manifest @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + From 755e7bc2324cc72b7c7cb82c9e86444975bdc968 Mon Sep 17 00:00:00 2001 From: qianlifeng Date: Thu, 23 Oct 2014 18:39:11 +0800 Subject: [PATCH 05/19] Add Context menu --- Plugins/Wox.Plugin.FindFile/Images/edit.png | Bin 0 -> 5765 bytes Plugins/Wox.Plugin.FindFile/Main.cs | 53 +++- .../Wox.Plugin.FindFile.csproj | 7 +- Wox.Infrastructure/MFTSearch/MFTSearcher.cs | 21 +- .../MFTSearch/MFTSearcherCache.cs | 139 ++------- Wox.Infrastructure/MFTSearch/USNRecord.cs | 1 - Wox.Infrastructure/MFTSearch/VolumeMonitor.cs | 286 +++++++++--------- Wox.Plugin/Result.cs | 107 ++++--- Wox.Test/MFTSearcherTest.cs | 16 +- Wox/Commands/SystemCommand.cs | 5 +- Wox/MainWindow.xaml | 3 +- Wox/MainWindow.xaml.cs | 115 +++++-- Wox/ResultPanel.xaml | 2 +- Wox/ResultPanel.xaml.cs | 21 +- 14 files changed, 433 insertions(+), 343 deletions(-) create mode 100644 Plugins/Wox.Plugin.FindFile/Images/edit.png diff --git a/Plugins/Wox.Plugin.FindFile/Images/edit.png b/Plugins/Wox.Plugin.FindFile/Images/edit.png new file mode 100644 index 0000000000000000000000000000000000000000..f1710b7c89c33e8a083dbec8c25ec8de38e4971a GIT binary patch literal 5765 zcmV;07JBK4P)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z000ZHNkl+H%1fH2O-65!8Yqzhndl@%;|S!f zWrA@43sOlDl%|dWZ0l&P%GknWrV_%7h;`zCu|jQ?3h6K@fk~)fZrX$!llykw&ppq6 z_Fk(WPBNn(yd;o&sq4!==fgQ?{ht4St+mhIq^kH$K}0wkF=!0#9~gkiWRO_f z{r&j2p&?w9N}cg{(`+m7$xH^T`ub3g<0bREyZ66-^r(i+N~(NLZ!bFX`F#_m(#l*E zO%_z~-LWy;TP&Wo0<#M6=QrMn6?^xhQ7WN3l{#^FY^=`!2$(^tAXP-E6yCjH0g9#4 zCNMwT7KRwF)$qwT-oO!&cg{j9R;SXX-v2U3m0O= z3omfz^5v)%i|j=>QH2n3A_5^|A>vxIiGzm^=L-4!GhqS}L4 zJ~lBi{Nd5jV{-;D`s2IM*O`U$at*;fE_MvZf)&ziUjZa#Mi@xwJ$`cSwOo4nWr^C_ zI50+t2)_!W02eYDK=rA$qob?m#6sI|xeD{^u2(9Etz}Vd*{ZcNh)``dF>UR6GyUdS16XoFKknZ8K{U%%Fw7qD z6&70-@fA4r!qpcfxBpUvwHKtj_k2mFrm*22iYb7_n1INc3GWv_d(z9d<)*Lt>J(ph& z)7iPzbafqeC#UhObs_!ld(o^_0R&$XU*GEDqIg$ipA<#x1XPuoBXMpLV#}=R1yB$N zoGC03Nse($-SWTf_ac^d?(fNK*wLX!fADl+;=uKx**zQ@|FP)W@f-~I=>hqF{?%h>?ogq{6pMP`wreXF-^rIuU~i0 zC6_ep=FJ#+lN{bMz^2tpaOv_vG@4C5nu(!0b} zy46>quEx&Q;M^3#u!qSQh;2f=WvGKfVS+pd*+FPhf~sRx5Al{sJsju%wGjWuJsp`C zTetrwMvoqy9e~%qe-n~Y2>}1G_{KVM6%kiqu@wQo6agI9NC8u;qYJ$UqCJ*`~M*g|*RupC2!1tivGq52(hC3UV0=gJT% z!}}tlwxv+1L&ZXU6RH;K9iqbT14>Zupx#2@L2!UNf?#cEF#U^B!nTL>wDUP5fQ5ry zxbJgUpjN5^WS$aN4#m|-U5(Y%ki-+5&M#t+LL_1JmIVnQF^B1H4x{-{jalJX;6Z9x z#DSm>Gt&OEAGNugjMax&>SKtnBhzsapdP9Yq88*m)O(1=APQEdL*Qoz9KP|r z)TD1kZHF0Q)B*@`$@5wR7x=D4J? z=SvvPhq!4`#B#EDMG2DaxESKu8oq2eGuhWa{k9hX3*2~h`vZ*?Q}Boc!Wtjwf= ze||2;v-{jz-VMAdz?FY^5$ZMz!2i&>GQ`zLT#Y5Eva@4opMMRDZ}3Uqvr3c2*AZsV zV+z|Cnt;@D%U&MhV}jyVHgv=$z{fscd0U&wHyvbcxeOXj`crT;K=wJfWKz7ZBC%u0 z_guy%>=r-$ODJMiaU$M=IL%REv4|@{)v|got-f!W)ISFfzuwpBF}!8sZExjgR3MuP z5#@3KQt#EE8|YpOgkA8{Zy*c{$n{(W?Uy9bWwGi(?zO@Gub!BjPZAXsrnSU5Zu_|W`U`7SrHLn*c z02xytHXs-f3=<4m?>*2l%$yrSF#ZfklGfAq9t6vR*0cq9britwKh(gNADud@r+_mm z(A(7pA)W^qD2%`us3CzNQIG%zs$NXGSNPnIL)y+0aTOtrq3T5>20_0@Y@W+!faN!h z;B3c?0Pi2Z5MJqA7zPXhpp&8n1QS4w0UHBl0${=YSHhgX8D1U4RT<)rfK#99X%DdO z^Zx_qbZ!Cm?mvuby*U)6BQOOZ6SNXGMi~a&QU-tl*g%nhbAyP6zYNp97?hcJRg^aP z;oc&i_;Gnwj`3#%c>1RYu;a0RANtvUji9}wz}ajTAj1s9WDKhzupwqcOf4WLC=+xt zb>U5yMe{!JnkeCex4%AX*H<$htGsvV@8I}YdB-nLOm1##%g7gQU(cVq>2?e+`2*~GWn{)%mRVC^Y_bjz4Gr{n!*Ia2ZF>+4 zmtD`IhJ$pPPuhvugbL6dP-)Lb;r*GeUhI5iH;DSM@0AhEX3Pi>MQKD)bZ!`ih@!Og z_IBauu?ZPi^bw6?k90aM1l}&KC*2oa%QO?utBb^4Afux!~fNs{E- zt5&Ugd|+T;gqd?9;zgvoe*OAiOK#V$U33z_Ff)mW?%cUkm{~*wn>KCIIalDZ#~urV zAm~hzBrPH}0ObuEHVFP71 GetContextMenu(MFTSearchRecord record) + { + List contextMenus = new List(); + + contextMenus.Add(new Result() + { + Title = "Open", + Action = _ => + { + try + { + Process.Start(record.FullPath); + } + catch + { + context.API.ShowMsg("Can't open " + record.FullPath, string.Empty, string.Empty); + return false; + } + return true; + }, + IcoPath = "Images/edit.png" + }); + + if (!record.IsFolder) + { + contextMenus.Add(new Result() + { + Title = "Open Containing Folder", + Action = _ => + { + try + { + Process.Start("explorer.exe", string.Format("/select, \"{0}\"", record.FullPath)); + } + catch + { + context.API.ShowMsg("Can't open " + record.FullPath, string.Empty, string.Empty); + return false; + } + return true; + }, + IcoPath = "Images/folder.png" + }); + } + + return contextMenus; + } } } diff --git a/Plugins/Wox.Plugin.FindFile/Wox.Plugin.FindFile.csproj b/Plugins/Wox.Plugin.FindFile/Wox.Plugin.FindFile.csproj index d16a7a5783..707e2744f4 100644 --- a/Plugins/Wox.Plugin.FindFile/Wox.Plugin.FindFile.csproj +++ b/Plugins/Wox.Plugin.FindFile/Wox.Plugin.FindFile.csproj @@ -54,7 +54,12 @@ - + + Always + + + Always + Always diff --git a/Wox.Infrastructure/MFTSearch/MFTSearcher.cs b/Wox.Infrastructure/MFTSearch/MFTSearcher.cs index 317468e885..7d4b603e86 100644 --- a/Wox.Infrastructure/MFTSearch/MFTSearcher.cs +++ b/Wox.Infrastructure/MFTSearch/MFTSearcher.cs @@ -9,7 +9,6 @@ using System.Diagnostics; using System.IO; using System.Linq; using System.Runtime.InteropServices; -using MyEverything; namespace Wox.Infrastructure.MFTSearch { @@ -23,8 +22,8 @@ namespace Wox.Infrastructure.MFTSearch List files; List folders; EnumerateVolume(volume, out files, out folders); - cache.AddRecord(volume, files, USNRecordType.File); - cache.AddRecord(volume, folders, USNRecordType.Folder); + //cache.AddRecord(files); + //cache.AddRecord(folders); } public static void IndexAllVolumes() @@ -35,13 +34,9 @@ namespace Wox.Infrastructure.MFTSearch } } - public static long IndexedFileCount + public static long IndexedRecordsCount { - get { return cache.FileCount; } - } - public static long IndexedFolderCount - { - get { return cache.FolderCount; } + get { return cache.RecordsCount; } } public static List Search(string item) @@ -49,7 +44,7 @@ namespace Wox.Infrastructure.MFTSearch if (string.IsNullOrEmpty(item)) return new List(); List found = cache.FindByName(item); - found.ForEach(x => FillPath(x.VolumeName, x, cache)); + found.ForEach(x => FillPath(x, cache)); return found.ConvertAll(o => new MFTSearchRecord(o)); } @@ -255,14 +250,16 @@ namespace Wox.Infrastructure.MFTSearch } Marshal.FreeHGlobal(pData); } - internal static void FillPath(string volume, USNRecord record, MFTSearcherCache db) + + internal static void FillPath(USNRecord record, MFTSearcherCache db) { if (record == null) return; - var fdSource = db.GetFolderSource(volume); + var fdSource = db.GetAllRecords(); string fullpath = record.Name; FindRecordPath(record, ref fullpath, fdSource); record.FullPath = fullpath; } + private static void FindRecordPath(USNRecord curRecord, ref string fullpath, Dictionary fdSource) { if (curRecord.IsVolumeRoot) return; diff --git a/Wox.Infrastructure/MFTSearch/MFTSearcherCache.cs b/Wox.Infrastructure/MFTSearch/MFTSearcherCache.cs index 87c04aedde..1ea9335a6e 100644 --- a/Wox.Infrastructure/MFTSearch/MFTSearcherCache.cs +++ b/Wox.Infrastructure/MFTSearch/MFTSearcherCache.cs @@ -1,133 +1,60 @@ using System; using System.Collections.Generic; using System.Linq; -using MyEverything; namespace Wox.Infrastructure.MFTSearch { internal class MFTSearcherCache { - private Dictionary> _volumes_files = new Dictionary>(); - private Dictionary> _volumes_folders = new Dictionary>(); + private Dictionary records = new Dictionary(100000); + private Lookup recordsLookup; public MFTSearcherCache() { } - public bool ContainsVolume(string volume) + public void AddRecord(List record) { - return _volumes_files.ContainsKey(volume) && _volumes_folders.ContainsKey(volume); + record.ForEach(AddRecord); } - public void AddRecord(string volume, List r, USNRecordType type) + + public void AddRecord(USNRecord record) { - if (type == USNRecordType.File) + if(!records.ContainsKey(record.FRN)) records.Add(record.FRN, record); + } + + public bool DeleteRecord(ulong frn) + { + return records.Remove(frn); + } + + public void UpdateRecord(USNRecord record) + { + USNRecord firstOrDefault = records[record.FRN]; + if (firstOrDefault != null) { - CheckHashTableKey(_volumes_files, volume); - r.ForEach(x => _volumes_files[volume].Add(x.FRN, x)); - } - else - { - CheckHashTableKey(_volumes_folders, volume); - r.ForEach(x => _volumes_folders[volume].Add(x.FRN, x)); - } - } - public void AddRecord(string volume, USNRecord record, USNRecordType type) - { - if (type == USNRecordType.File) - { - CheckHashTableKey(_volumes_files, volume); - _volumes_files[volume].Add(record.FRN, record); - } - else - { - CheckHashTableKey(_volumes_folders, volume); - _volumes_folders[volume].Add(record.FRN, record); - } - } - private void CheckHashTableKey(Dictionary> hashtable, string key) - { - if (!hashtable.ContainsKey(key)) - hashtable.Add(key, new Dictionary()); - } - public bool DeleteRecord(string volume, ulong frn) - { - bool result = false; - result = DeleteRecordHashTableItem(_volumes_files, volume, frn); - if (!result) result = DeleteRecordHashTableItem(_volumes_folders, volume, frn); - return result; - } - private bool DeleteRecordHashTableItem(Dictionary> hashtable, string volume, ulong frn) - { - if (hashtable.ContainsKey(volume) && hashtable[volume].ContainsKey(frn)) - { - hashtable[volume].Remove(frn); - return true; - } - else - { - return false; - } - } - public void UpdateRecord(string volume, USNRecord record, USNRecordType type) - { - if (type == USNRecordType.File) - RealUpdateRecord(volume, _volumes_files, record); - else - RealUpdateRecord(volume, _volumes_folders, record); - } - private bool RealUpdateRecord(string volume, Dictionary> source, USNRecord record) - { - if (source.ContainsKey(volume) && source[volume].ContainsKey(record.FRN)) - { - source[volume][record.FRN] = record; - return true; - } - else - { - return false; + firstOrDefault.Name = record.Name; + firstOrDefault.FullPath = record.FullPath; + firstOrDefault.VolumeName = record.VolumeName; } } + + public List FindByName(string filename) { filename = filename.ToLower(); - var fileQuery = from filesInVolumeDic in _volumes_files.Values - from eachFilePair in filesInVolumeDic - where eachFilePair.Value.Name.ToLower().Contains(filename) - select eachFilePair.Value; - - var folderQuery = from fldsInVolumeDic in _volumes_folders.Values - from eachFldPair in fldsInVolumeDic - where eachFldPair.Value.Name.ToLower().Contains(filename) - select eachFldPair.Value; - - List result = new List(); - - result.AddRange(fileQuery); - result.AddRange(folderQuery); - - return result; + var query = from file in records.Values + where file.Name.ToLower().Contains(filename) + select file; + return query.ToList(); } - public USNRecord FindByFrn(string volume, ulong frn) + + public long RecordsCount { - if ((!_volumes_files.ContainsKey(volume)) || (!_volumes_folders.ContainsKey(volume))) - throw new Exception(string.Format("DB not contain the volume: {0}", volume)); - USNRecord result = null; - _volumes_files[volume].TryGetValue(frn, out result); - if (result != null) return result; - _volumes_folders[volume].TryGetValue(frn, out result); - return result; + get { return records.Count; } } - public long FileCount + + public Dictionary GetAllRecords() { - get { return _volumes_files.Sum(x => x.Value.Count); } - } - public long FolderCount - { - get { return _volumes_folders.Sum(x => x.Value.Count); } - } - public Dictionary GetFolderSource(string volume) - { - Dictionary result = null; - _volumes_folders.TryGetValue(volume, out result); - return result; + return records; } } } diff --git a/Wox.Infrastructure/MFTSearch/USNRecord.cs b/Wox.Infrastructure/MFTSearch/USNRecord.cs index 64c0ee05e7..fe9e85ab30 100644 --- a/Wox.Infrastructure/MFTSearch/USNRecord.cs +++ b/Wox.Infrastructure/MFTSearch/USNRecord.cs @@ -1,5 +1,4 @@ using System; -using MyEverything; namespace Wox.Infrastructure.MFTSearch { diff --git a/Wox.Infrastructure/MFTSearch/VolumeMonitor.cs b/Wox.Infrastructure/MFTSearch/VolumeMonitor.cs index c65cf866d9..772c307b9e 100644 --- a/Wox.Infrastructure/MFTSearch/VolumeMonitor.cs +++ b/Wox.Infrastructure/MFTSearch/VolumeMonitor.cs @@ -1,158 +1,158 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Runtime.InteropServices; -using System.Threading; -using System.Diagnostics; -using System.IO; -using Wox.Infrastructure.MFTSearch; +//using System; +//using System.Collections.Generic; +//using System.Linq; +//using System.Text; +//using System.Runtime.InteropServices; +//using System.Threading; +//using System.Diagnostics; +//using System.IO; +//using Wox.Infrastructure.MFTSearch; -namespace MyEverything -{ - internal class VolumeMonitor - { +//namespace MyEverything +//{ +// internal class VolumeMonitor +// { - public Action RecordAddedEvent; - public Action RecordDeletedEvent; - public Action RecordRenameEvent; +// public Action RecordAddedEvent; +// public Action RecordDeletedEvent; +// public Action RecordRenameEvent; - public void Monitor(List volumes, MFTSearcherCache db) - { - foreach (var volume in volumes) - { - 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.")); - Thread th = new Thread(new ParameterizedThreadStart(MonitorThread)); - th.Start(new Dictionary { { "Volume", volume }, { "MFTSearcherCache", 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(); - Wox.Infrastructure.MFTSearch.MFTSearcher.QueryUSNJournal(pMonitorVolume, out ujd, out bytesReturned); +// public void Monitor(List volumes, MFTSearcherCache db) +// { +// foreach (var volume in volumes) +// { +// 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.")); +// Thread th = new Thread(new ParameterizedThreadStart(MonitorThread)); +// th.Start(new Dictionary { { "Volume", volume }, { "MFTSearcherCache", 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(); +// Wox.Infrastructure.MFTSearch.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; +// // 构建输入参数 +// 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(object param) - { +// return rujd; +// } +// private void MonitorThread(object param) +// { - MFTSearcherCache db = (param as Dictionary)["MFTSearcherCache"] as MFTSearcherCache; - string volume = (param as Dictionary)["Volume"] as string; - IntPtr pbuffer = Marshal.AllocHGlobal(0x1000); - PInvokeWin32.READ_USN_JOURNAL_DATA rujd = SetupInputData4JournalRead(volume, 0xFFFFFFFF); - UInt32 cbRead; - IntPtr prujd; +// MFTSearcherCache db = (param as Dictionary)["MFTSearcherCache"] as MFTSearcherCache; +// string volume = (param as Dictionary)["Volume"] as string; +// 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); +// while (true) +// { +// prujd = Marshal.AllocHGlobal(Marshal.SizeOf(rujd)); +// PInvokeWin32.ZeroMemory(prujd, Marshal.SizeOf(rujd)); +// Marshal.StructureToPtr(rujd, prujd, true); - Debug.WriteLine(string.Format("\nMoniting on {0}......", volume)); - IntPtr pVolume = Wox.Infrastructure.MFTSearch.MFTSearcher.GetVolumeJournalHandle(volume); +// Debug.WriteLine(string.Format("\nMoniting on {0}......", volume)); +// IntPtr pVolume = Wox.Infrastructure.MFTSearch.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); +// 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; +// 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; - } - } +// 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) - { - var dbCached = db.FindByFrn(volume, usn.FRN); - Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, dbCached, db); - Debug.WriteLine(string.Format("------USN[frn={0}]------", usn.FRN)); - Debug.WriteLine(string.Format("FileName={0}, USNChangeReason={1}", usn.FileName, USNChangeReason.ReasonPrettyFormat(usn.Reason))); - Debug.WriteLine(string.Format("FileName[Cached]={0}", dbCached == null ? "NoCache" : dbCached.FullPath)); - Debug.WriteLine("--------------------------------------"); +// Marshal.FreeHGlobal(prujd); +// rujd.StartUsn = Marshal.ReadInt64(pbuffer); +// } +// } +// private void ProcessUSN(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db) +// { +// var dbCached = db.FindByFrn(volume, usn.FRN); +// Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, dbCached, db); +// Debug.WriteLine(string.Format("------USN[frn={0}]------", usn.FRN)); +// Debug.WriteLine(string.Format("FileName={0}, USNChangeReason={1}", usn.FileName, USNChangeReason.ReasonPrettyFormat(usn.Reason))); +// Debug.WriteLine(string.Format("FileName[Cached]={0}", dbCached == null ? "NoCache" : dbCached.FullPath)); +// Debug.WriteLine("--------------------------------------"); - 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) - { - return; - } - else - { - Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, cached, db); - var deleteok = db.DeleteRecord(volume, usn.FRN); - Debug.WriteLine(string.Format(">>>> File {0} deleted {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); - //string fullpath = newRecord.Name; - //db.FindRecordPath(newRecord, ref fullpath, db.GetFolderSource(volume)); - //newRecord.FullPath = fullpath; - var oldRecord = db.FindByFrn(volume, usn.FRN); - Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, oldRecord, db); - Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, newRecord, db); - Debug.WriteLine(string.Format(">>>> RenameFile {0} to {1}", oldRecord.FullPath, newRecord.FullPath)); - db.UpdateRecord(volume, newRecord, - usn.IsFolder ? USNRecordType.Folder : USNRecordType.File); - if (RecordRenameEvent != null) RecordRenameEvent(oldRecord, newRecord); - if (newRecord.FullPath.Contains("$RECYCLE.BIN")) - { - Debug.WriteLine(string.Format(">>>> Means {0} moved to recycle.", oldRecord.FullPath)); - } - } - private void ProcessFileCreate(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db) - { - USNRecord record = USNRecord.ParseUSN(volume, usn); - //string fullpath = record.Name; - //db.FindRecordPath(record, ref fullpath, db.GetFolderSource(volume)); - //record.FullPath = fullpath; - db.AddRecord(volume, record, usn.IsFolder ? USNRecordType.Folder : USNRecordType.File); - Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, record, db); - Debug.WriteLine(string.Format(">>>> NewFile: {0}", record.FullPath)); - if (RecordAddedEvent != null) - RecordAddedEvent(record); - } +// 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) +// { +// return; +// } +// else +// { +// Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, cached, db); +// var deleteok = db.DeleteRecord(volume, usn.FRN); +// Debug.WriteLine(string.Format(">>>> File {0} deleted {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); +// //string fullpath = newRecord.Name; +// //db.FindRecordPath(newRecord, ref fullpath, db.GetFolderSource(volume)); +// //newRecord.FullPath = fullpath; +// var oldRecord = db.FindByFrn(volume, usn.FRN); +// Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, oldRecord, db); +// Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, newRecord, db); +// Debug.WriteLine(string.Format(">>>> RenameFile {0} to {1}", oldRecord.FullPath, newRecord.FullPath)); +// db.UpdateRecord(volume, newRecord, +// usn.IsFolder ? USNRecordType.Folder : USNRecordType.File); +// if (RecordRenameEvent != null) RecordRenameEvent(oldRecord, newRecord); +// if (newRecord.FullPath.Contains("$RECYCLE.BIN")) +// { +// Debug.WriteLine(string.Format(">>>> Means {0} moved to recycle.", oldRecord.FullPath)); +// } +// } +// private void ProcessFileCreate(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db) +// { +// USNRecord record = USNRecord.ParseUSN(volume, usn); +// //string fullpath = record.Name; +// //db.FindRecordPath(record, ref fullpath, db.GetFolderSource(volume)); +// //record.FullPath = fullpath; +// db.AddRecord(volume, record, usn.IsFolder ? USNRecordType.Folder : USNRecordType.File); +// Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, record, db); +// Debug.WriteLine(string.Format(">>>> NewFile: {0}", record.FullPath)); +// if (RecordAddedEvent != null) +// RecordAddedEvent(record); +// } - private bool MaskEqual(uint target, uint compare) - { - return (target & compare) != 0; - } - } -} +// private bool MaskEqual(uint target, uint compare) +// { +// return (target & compare) != 0; +// } +// } +//} diff --git a/Wox.Plugin/Result.cs b/Wox.Plugin/Result.cs index 3a7904b2e9..db0bd309c0 100644 --- a/Wox.Plugin/Result.cs +++ b/Wox.Plugin/Result.cs @@ -3,71 +3,78 @@ using System.Collections; using System.Collections.Generic; using System.IO; -namespace Wox.Plugin { +namespace Wox.Plugin +{ - public class Result { - public string Title { get; set; } - public string SubTitle { get; set; } - public string IcoPath { get; set; } + public class Result + { - public string FullIcoPath - { - get - { + public string Title { get; set; } + public string SubTitle { get; set; } + public string IcoPath { get; set; } + + public string FullIcoPath + { + get + { if (string.IsNullOrEmpty(IcoPath)) return string.Empty; - if (IcoPath.StartsWith("data:")) - { - return IcoPath; - } + if (IcoPath.StartsWith("data:")) + { + return IcoPath; + } return Path.Combine(PluginDirectory, IcoPath); - } - } + } + } - ///

- /// return true to hide wox after select result - /// - public Func Action { get; set; } - public int Score { get; set; } + /// + /// return true to hide wox after select result + /// + public Func Action { get; set; } - /// - /// Auto add scores for MRU items - /// - public bool AutoAjustScore { get; set; } + public int Score { get; set; } - //todo: this should be controlled by system, not visible to users - /// - /// Only resulsts that originQuery match with curren query will be displayed in the panel - /// - public Query OriginQuery { get; set; } + /// + /// Auto add scores for MRU items + /// + public bool AutoAjustScore { get; set; } - /// - /// Don't set this property if you are developing a plugin - /// - public string PluginDirectory { get; set; } + //todo: this should be controlled by system, not visible to users + /// + /// Only resulsts that originQuery match with curren query will be displayed in the panel + /// + public Query OriginQuery { get; set; } - public new bool Equals(object obj) { - if (obj == null || !(obj is Result)) return false; + /// + /// Don't set this property if you are developing a plugin + /// + public string PluginDirectory { get; set; } - Result r = (Result)obj; - return r.Title == Title && r.SubTitle == SubTitle; - } + public new bool Equals(object obj) + { + if (obj == null || !(obj is Result)) return false; + Result r = (Result)obj; + return r.Title == Title && r.SubTitle == SubTitle; + } + public override string ToString() + { + return Title + SubTitle; + } - public override string ToString() { - return Title + SubTitle; - } + public Result() + { - public Result() { + } - } + public Result(string Title = null, string IcoPath = null, string SubTitle = null) + { + this.Title = Title; + this.IcoPath = IcoPath; + this.SubTitle = SubTitle; + } - public Result(string Title = null, string IcoPath = null, string SubTitle = null) { - this.Title = Title; - this.IcoPath = IcoPath; - this.SubTitle = SubTitle; - } - - } + public List ContextMenu { get; set; } + } } \ No newline at end of file diff --git a/Wox.Test/MFTSearcherTest.cs b/Wox.Test/MFTSearcherTest.cs index b7f318c33d..c7a9ec5841 100644 --- a/Wox.Test/MFTSearcherTest.cs +++ b/Wox.Test/MFTSearcherTest.cs @@ -16,7 +16,7 @@ namespace Wox.Test var searchtimestart = DateTime.Now; MFTSearcher.IndexAllVolumes(); var searchtimeend = DateTime.Now; - Console.WriteLine(string.Format("{0} file indexed, {1}ms has spent.", MFTSearcher.IndexedFileCount, searchtimeend.Subtract(searchtimestart).TotalMilliseconds)); + Console.WriteLine(string.Format("{0} file indexed, {1}ms has spent.", MFTSearcher.IndexedRecordsCount, searchtimeend.Subtract(searchtimestart).TotalMilliseconds)); searchtimestart = DateTime.Now; List mftSearchRecords = MFTSearcher.Search("q"); @@ -28,5 +28,19 @@ namespace Wox.Test searchtimeend = DateTime.Now; Console.WriteLine(string.Format("{0} file searched, {1}ms has spent.", mftSearchRecords.Count, searchtimeend.Subtract(searchtimestart).TotalMilliseconds)); } + + [Test] + public void MemoryTest() + { + long oldWorkingSet = System.Diagnostics.Process.GetCurrentProcess().WorkingSet64; + MFTSearcher.IndexAllVolumes(); + long newWorkingSet = System.Diagnostics.Process.GetCurrentProcess().WorkingSet64; + Console.WriteLine(string.Format("Index: {0}M", (newWorkingSet - oldWorkingSet)/(1024*1024))); + + oldWorkingSet = System.Diagnostics.Process.GetCurrentProcess().WorkingSet64; + MFTSearcher.Search("q"); + newWorkingSet = System.Diagnostics.Process.GetCurrentProcess().WorkingSet64; + Console.WriteLine(string.Format("Search: {0}M", (newWorkingSet - oldWorkingSet) / (1024 * 1024))); + } } } diff --git a/Wox/Commands/SystemCommand.cs b/Wox/Commands/SystemCommand.cs index 162011f8a8..1a5a1949b7 100644 --- a/Wox/Commands/SystemCommand.cs +++ b/Wox/Commands/SystemCommand.cs @@ -17,16 +17,17 @@ namespace Wox.Commands public override void Dispatch(Query query) { + var queryPlugins = allSytemPlugins; if (UserSettingStorage.Instance.WebSearches.Exists(o => o.ActionWord == query.ActionName && o.Enabled)) { //websearch mode - allSytemPlugins = new List() + queryPlugins = new List() { allSytemPlugins.First(o => ((ISystemPlugin)o.Plugin).ID == "565B73353DBF4806919830B9202EE3BF") }; } - foreach (PluginPair pair in allSytemPlugins) + foreach (PluginPair pair in queryPlugins) { PluginPair pair1 = pair; ThreadPool.QueueUserWorkItem(state => diff --git a/Wox/MainWindow.xaml b/Wox/MainWindow.xaml index 71ef2bfd54..448680b218 100644 --- a/Wox/MainWindow.xaml +++ b/Wox/MainWindow.xaml @@ -22,7 +22,8 @@ - + + \ No newline at end of file diff --git a/Wox/MainWindow.xaml.cs b/Wox/MainWindow.xaml.cs index e44a65d539..bce6c69777 100644 --- a/Wox/MainWindow.xaml.cs +++ b/Wox/MainWindow.xaml.cs @@ -141,6 +141,13 @@ namespace Wox results.ForEach(o => { o.PluginDirectory = plugin.PluginDirectory; + if (o.ContextMenu != null) + { + o.ContextMenu.ForEach(t => + { + t.PluginDirectory = plugin.PluginDirectory; + }); + } o.OriginQuery = query; }); OnUpdateResultView(results); @@ -148,7 +155,6 @@ namespace Wox #endregion - public MainWindow() { InitializeComponent(); @@ -160,7 +166,9 @@ namespace Wox progressBar.ToolTip = toolTip; InitialTray(); - resultCtrl.OnMouseClickItem += AcceptSelect; + pnlResult.LeftMouseClickEvent += SelectResult; + pnlContextMenu.LeftMouseClickEvent += SelectResult; + pnlResult.RightMouseClickEvent += pnlResult_RightMouseClickEvent; ThreadPool.SetMaxThreads(30, 10); try @@ -180,6 +188,11 @@ namespace Wox this.Closing += MainWindow_Closing; } + void pnlResult_RightMouseClickEvent(Result result) + { + ShowContextMenu(result); + } + void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e) { UserSettingStorage.Instance.WindowLeft = Left; @@ -300,21 +313,22 @@ namespace Wox lastQuery = tbQuery.Text; toolTip.IsOpen = false; - resultCtrl.Dirty = true; + pnlResult.Dirty = true; Dispatcher.DelayInvoke("UpdateSearch", o => { Dispatcher.DelayInvoke("ClearResults", i => { - // first try to use clear method inside resultCtrl, which is more closer to the add new results + // first try to use clear method inside pnlResult, which is more closer to the add new results // and this will not bring splash issues.After waiting 30ms, if there still no results added, we // must clear the result. otherwise, it will be confused why the query changed, but the results // didn't. - if (resultCtrl.Dirty) resultCtrl.Clear(); + if (pnlResult.Dirty) pnlResult.Clear(); }, TimeSpan.FromMilliseconds(100), null); queryHasReturn = false; var q = new Query(lastQuery); CommandFactory.DispatchCommand(q); + BackToResultMode(); if (Plugins.HitThirdpartyKeyword(q)) { Dispatcher.DelayInvoke("ShowProgressbar", originQuery => @@ -328,6 +342,12 @@ namespace Wox }, TimeSpan.FromMilliseconds(ShouldNotDelayQuery ? 0 : 150)); } + private void BackToResultMode() + { + pnlResult.Visibility = Visibility.Visible; + pnlContextMenu.Visibility = Visibility.Collapsed; + } + private bool ShouldNotDelayQuery { get @@ -463,7 +483,7 @@ namespace Wox ShowWox(false); if (!tbQuery.Text.StartsWith(">")) { - resultCtrl.Clear(); + pnlResult.Clear(); ChangeQuery(">"); } tbQuery.CaretIndex = tbQuery.Text.Length; @@ -473,7 +493,7 @@ namespace Wox private void updateCmdMode() { - var currentSelectedItem = resultCtrl.GetActiveResult(); + var currentSelectedItem = pnlResult.GetActiveResult(); if (currentSelectedItem != null) { ignoreTextChange = true; @@ -489,7 +509,14 @@ namespace Wox switch (key) { case Key.Escape: - HideWox(); + if (IsInContextMenuMode) + { + BackToResultMode(); + } + else + { + HideWox(); + } e.Handled = true; break; @@ -516,14 +543,14 @@ namespace Wox break; case Key.PageDown: - resultCtrl.SelectNextPage(); + pnlResult.SelectNextPage(); if (IsCMDMode) updateCmdMode(); toolTip.IsOpen = false; e.Handled = true; break; case Key.PageUp: - resultCtrl.SelectPrevPage(); + pnlResult.SelectPrevPage(); if (IsCMDMode) updateCmdMode(); toolTip.IsOpen = false; e.Handled = true; @@ -545,29 +572,68 @@ namespace Wox break; case Key.Enter: - AcceptSelect(resultCtrl.GetActiveResult()); + Result activeResult = GetActiveResult(); + if (globalHotkey.CheckModifiers().ShiftPressed) + { + ShowContextMenu(activeResult); + } + else + { + SelectResult(activeResult); + } e.Handled = true; break; } } + private bool IsInContextMenuMode + { + get { return pnlContextMenu.Visibility == Visibility.Visible; } + } + + private Result GetActiveResult() + { + if (IsInContextMenuMode) + { + return pnlContextMenu.GetActiveResult(); + } + else + { + return pnlResult.GetActiveResult(); + } + } + private void SelectPrevItem() { - resultCtrl.SelectPrev(); - if (IsCMDMode) updateCmdMode(); + if (IsInContextMenuMode) + { + pnlContextMenu.SelectPrev(); + } + else + { + pnlResult.SelectPrev(); + if (IsCMDMode) updateCmdMode(); + } toolTip.IsOpen = false; } private void SelectNextItem() { - resultCtrl.SelectNext(); - if (IsCMDMode) updateCmdMode(); + if (IsInContextMenuMode) + { + pnlContextMenu.SelectNext(); + } + else + { + pnlResult.SelectNext(); + if (IsCMDMode) updateCmdMode(); + } toolTip.IsOpen = false; } - private void AcceptSelect(Result result) + private void SelectResult(Result result) { - if (!resultCtrl.Dirty && result != null) + if (result != null) { if (result.Action != null) { @@ -599,7 +665,20 @@ namespace Wox if (o.AutoAjustScore) o.Score += UserSelectedRecordStorage.Instance.GetSelectedCount(o); }); List l = list.Where(o => o.OriginQuery != null && o.OriginQuery.RawQuery == lastQuery).ToList(); - Dispatcher.Invoke(new Action(() => resultCtrl.AddResults(l))); + Dispatcher.Invoke(new Action(() => + pnlResult.AddResults(l)) + ); + } + } + + private void ShowContextMenu(Result result) + { + if (result.ContextMenu != null && result.ContextMenu.Count > 0) + { + pnlContextMenu.Clear(); + pnlContextMenu.AddResults(result.ContextMenu); + pnlContextMenu.Visibility = Visibility.Visible; + pnlResult.Visibility = Visibility.Collapsed; } } diff --git a/Wox/ResultPanel.xaml b/Wox/ResultPanel.xaml index 03927ce29d..d1a8e28afd 100644 --- a/Wox/ResultPanel.xaml +++ b/Wox/ResultPanel.xaml @@ -17,7 +17,7 @@ - + diff --git a/Wox/ResultPanel.xaml.cs b/Wox/ResultPanel.xaml.cs index 690a48de69..736d5d262c 100644 --- a/Wox/ResultPanel.xaml.cs +++ b/Wox/ResultPanel.xaml.cs @@ -14,11 +14,18 @@ namespace Wox { public partial class ResultPanel : UserControl { - public event Action OnMouseClickItem; + public event Action LeftMouseClickEvent; + public event Action RightMouseClickEvent; - protected virtual void OnOnMouseClickItem(Result result) + protected virtual void OnRightMouseClick(Result result) { - Action handler = OnMouseClickItem; + Action handler = RightMouseClickEvent; + if (handler != null) handler(result); + } + + protected virtual void OnLeftMouseClick(Result result) + { + Action handler = LeftMouseClickEvent; if (handler != null) handler(result); } @@ -133,9 +140,13 @@ namespace Wox private void LbResults_OnPreviewMouseDown(object sender, MouseButtonEventArgs e) { var item = ItemsControl.ContainerFromElement(lbResults, e.OriginalSource as DependencyObject) as ListBoxItem; - if (item != null) + if (item != null && e.ChangedButton == MouseButton.Left) { - OnOnMouseClickItem(item.DataContext as Result); + OnLeftMouseClick(item.DataContext as Result); + } + if (item != null && e.ChangedButton == MouseButton.Right) + { + OnRightMouseClick(item.DataContext as Result); } } From 30afc095b98e263d07aefebaf513764be14f0163 Mon Sep 17 00:00:00 2001 From: qianlifeng Date: Thu, 23 Oct 2014 23:23:40 +0800 Subject: [PATCH 06/19] Revert MFTSearch changes. --- Plugins/Wox.Plugin.FindFile/Main.cs | 2 +- Wox.Infrastructure/MFTSearch/MFTSearcher.cs | 21 +- .../MFTSearch/MFTSearcherCache.cs | 141 ++++++--- Wox.Infrastructure/MFTSearch/USNRecord.cs | 1 + Wox.Infrastructure/MFTSearch/VolumeMonitor.cs | 286 +++++++++--------- Wox.Test/MFTSearcherTest.cs | 3 +- 6 files changed, 266 insertions(+), 188 deletions(-) diff --git a/Plugins/Wox.Plugin.FindFile/Main.cs b/Plugins/Wox.Plugin.FindFile/Main.cs index 5cad15015b..f53522f852 100644 --- a/Plugins/Wox.Plugin.FindFile/Main.cs +++ b/Plugins/Wox.Plugin.FindFile/Main.cs @@ -36,7 +36,7 @@ namespace Wox.Plugin.FindFile MFTSearcher.IndexAllVolumes(); initial = true; var searchtimeend = DateTime.Now; - Debug.WriteLine(string.Format("{0} file, indexed, {1}ms has spent.", MFTSearcher.IndexedRecordsCount, searchtimeend.Subtract(searchtimestart).TotalMilliseconds)); + Debug.WriteLine(string.Format("{0} file, indexed, {1}ms has spent.", MFTSearcher.IndexedFileCount, searchtimeend.Subtract(searchtimestart).TotalMilliseconds)); } private Result ConvertMFTSearch(MFTSearchRecord record, string query) diff --git a/Wox.Infrastructure/MFTSearch/MFTSearcher.cs b/Wox.Infrastructure/MFTSearch/MFTSearcher.cs index 7d4b603e86..317468e885 100644 --- a/Wox.Infrastructure/MFTSearch/MFTSearcher.cs +++ b/Wox.Infrastructure/MFTSearch/MFTSearcher.cs @@ -9,6 +9,7 @@ using System.Diagnostics; using System.IO; using System.Linq; using System.Runtime.InteropServices; +using MyEverything; namespace Wox.Infrastructure.MFTSearch { @@ -22,8 +23,8 @@ namespace Wox.Infrastructure.MFTSearch List files; List folders; EnumerateVolume(volume, out files, out folders); - //cache.AddRecord(files); - //cache.AddRecord(folders); + cache.AddRecord(volume, files, USNRecordType.File); + cache.AddRecord(volume, folders, USNRecordType.Folder); } public static void IndexAllVolumes() @@ -34,9 +35,13 @@ namespace Wox.Infrastructure.MFTSearch } } - public static long IndexedRecordsCount + public static long IndexedFileCount { - get { return cache.RecordsCount; } + get { return cache.FileCount; } + } + public static long IndexedFolderCount + { + get { return cache.FolderCount; } } public static List Search(string item) @@ -44,7 +49,7 @@ namespace Wox.Infrastructure.MFTSearch if (string.IsNullOrEmpty(item)) return new List(); List found = cache.FindByName(item); - found.ForEach(x => FillPath(x, cache)); + found.ForEach(x => FillPath(x.VolumeName, x, cache)); return found.ConvertAll(o => new MFTSearchRecord(o)); } @@ -250,16 +255,14 @@ namespace Wox.Infrastructure.MFTSearch } Marshal.FreeHGlobal(pData); } - - internal static void FillPath(USNRecord record, MFTSearcherCache db) + internal static void FillPath(string volume, USNRecord record, MFTSearcherCache db) { if (record == null) return; - var fdSource = db.GetAllRecords(); + var fdSource = db.GetFolderSource(volume); string fullpath = record.Name; FindRecordPath(record, ref fullpath, fdSource); record.FullPath = fullpath; } - private static void FindRecordPath(USNRecord curRecord, ref string fullpath, Dictionary fdSource) { if (curRecord.IsVolumeRoot) return; diff --git a/Wox.Infrastructure/MFTSearch/MFTSearcherCache.cs b/Wox.Infrastructure/MFTSearch/MFTSearcherCache.cs index 1ea9335a6e..87c04aedde 100644 --- a/Wox.Infrastructure/MFTSearch/MFTSearcherCache.cs +++ b/Wox.Infrastructure/MFTSearch/MFTSearcherCache.cs @@ -1,60 +1,133 @@ using System; using System.Collections.Generic; using System.Linq; +using MyEverything; namespace Wox.Infrastructure.MFTSearch { internal class MFTSearcherCache { - private Dictionary records = new Dictionary(100000); - private Lookup recordsLookup; + private Dictionary> _volumes_files = new Dictionary>(); + private Dictionary> _volumes_folders = new Dictionary>(); public MFTSearcherCache() { } - public void AddRecord(List record) + public bool ContainsVolume(string volume) { - record.ForEach(AddRecord); + return _volumes_files.ContainsKey(volume) && _volumes_folders.ContainsKey(volume); } - - public void AddRecord(USNRecord record) + public void AddRecord(string volume, List r, USNRecordType type) { - if(!records.ContainsKey(record.FRN)) records.Add(record.FRN, record); - } - - public bool DeleteRecord(ulong frn) - { - return records.Remove(frn); - } - - public void UpdateRecord(USNRecord record) - { - USNRecord firstOrDefault = records[record.FRN]; - if (firstOrDefault != null) + if (type == USNRecordType.File) { - firstOrDefault.Name = record.Name; - firstOrDefault.FullPath = record.FullPath; - firstOrDefault.VolumeName = record.VolumeName; + CheckHashTableKey(_volumes_files, volume); + r.ForEach(x => _volumes_files[volume].Add(x.FRN, x)); + } + else + { + CheckHashTableKey(_volumes_folders, volume); + r.ForEach(x => _volumes_folders[volume].Add(x.FRN, x)); + } + } + public void AddRecord(string volume, USNRecord record, USNRecordType type) + { + if (type == USNRecordType.File) + { + CheckHashTableKey(_volumes_files, volume); + _volumes_files[volume].Add(record.FRN, record); + } + else + { + CheckHashTableKey(_volumes_folders, volume); + _volumes_folders[volume].Add(record.FRN, record); + } + } + private void CheckHashTableKey(Dictionary> hashtable, string key) + { + if (!hashtable.ContainsKey(key)) + hashtable.Add(key, new Dictionary()); + } + public bool DeleteRecord(string volume, ulong frn) + { + bool result = false; + result = DeleteRecordHashTableItem(_volumes_files, volume, frn); + if (!result) result = DeleteRecordHashTableItem(_volumes_folders, volume, frn); + return result; + } + private bool DeleteRecordHashTableItem(Dictionary> hashtable, string volume, ulong frn) + { + if (hashtable.ContainsKey(volume) && hashtable[volume].ContainsKey(frn)) + { + hashtable[volume].Remove(frn); + return true; + } + else + { + return false; + } + } + public void UpdateRecord(string volume, USNRecord record, USNRecordType type) + { + if (type == USNRecordType.File) + RealUpdateRecord(volume, _volumes_files, record); + else + RealUpdateRecord(volume, _volumes_folders, record); + } + private bool RealUpdateRecord(string volume, Dictionary> source, USNRecord record) + { + if (source.ContainsKey(volume) && source[volume].ContainsKey(record.FRN)) + { + source[volume][record.FRN] = record; + return true; + } + else + { + return false; } } - - public List FindByName(string filename) { filename = filename.ToLower(); - var query = from file in records.Values - where file.Name.ToLower().Contains(filename) - select file; - return query.ToList(); - } + var fileQuery = from filesInVolumeDic in _volumes_files.Values + from eachFilePair in filesInVolumeDic + where eachFilePair.Value.Name.ToLower().Contains(filename) + select eachFilePair.Value; - public long RecordsCount - { - get { return records.Count; } + var folderQuery = from fldsInVolumeDic in _volumes_folders.Values + from eachFldPair in fldsInVolumeDic + where eachFldPair.Value.Name.ToLower().Contains(filename) + select eachFldPair.Value; + + List result = new List(); + + result.AddRange(fileQuery); + result.AddRange(folderQuery); + + return result; } - - public Dictionary GetAllRecords() + public USNRecord FindByFrn(string volume, ulong frn) { - return records; + if ((!_volumes_files.ContainsKey(volume)) || (!_volumes_folders.ContainsKey(volume))) + throw new Exception(string.Format("DB not contain the volume: {0}", volume)); + USNRecord result = null; + _volumes_files[volume].TryGetValue(frn, out result); + if (result != null) return result; + _volumes_folders[volume].TryGetValue(frn, out result); + return result; + } + public long FileCount + { + get { return _volumes_files.Sum(x => x.Value.Count); } + } + public long FolderCount + { + get { return _volumes_folders.Sum(x => x.Value.Count); } + } + public Dictionary GetFolderSource(string volume) + { + Dictionary result = null; + _volumes_folders.TryGetValue(volume, out result); + return result; } } } diff --git a/Wox.Infrastructure/MFTSearch/USNRecord.cs b/Wox.Infrastructure/MFTSearch/USNRecord.cs index fe9e85ab30..64c0ee05e7 100644 --- a/Wox.Infrastructure/MFTSearch/USNRecord.cs +++ b/Wox.Infrastructure/MFTSearch/USNRecord.cs @@ -1,4 +1,5 @@ using System; +using MyEverything; namespace Wox.Infrastructure.MFTSearch { diff --git a/Wox.Infrastructure/MFTSearch/VolumeMonitor.cs b/Wox.Infrastructure/MFTSearch/VolumeMonitor.cs index 772c307b9e..c65cf866d9 100644 --- a/Wox.Infrastructure/MFTSearch/VolumeMonitor.cs +++ b/Wox.Infrastructure/MFTSearch/VolumeMonitor.cs @@ -1,158 +1,158 @@ -//using System; -//using System.Collections.Generic; -//using System.Linq; -//using System.Text; -//using System.Runtime.InteropServices; -//using System.Threading; -//using System.Diagnostics; -//using System.IO; -//using Wox.Infrastructure.MFTSearch; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; +using System.Threading; +using System.Diagnostics; +using System.IO; +using Wox.Infrastructure.MFTSearch; -//namespace MyEverything -//{ -// internal class VolumeMonitor -// { +namespace MyEverything +{ + internal class VolumeMonitor + { -// public Action RecordAddedEvent; -// public Action RecordDeletedEvent; -// public Action RecordRenameEvent; + public Action RecordAddedEvent; + public Action RecordDeletedEvent; + public Action RecordRenameEvent; -// public void Monitor(List volumes, MFTSearcherCache db) -// { -// foreach (var volume in volumes) -// { -// 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.")); -// Thread th = new Thread(new ParameterizedThreadStart(MonitorThread)); -// th.Start(new Dictionary { { "Volume", volume }, { "MFTSearcherCache", 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(); -// Wox.Infrastructure.MFTSearch.MFTSearcher.QueryUSNJournal(pMonitorVolume, out ujd, out bytesReturned); + public void Monitor(List volumes, MFTSearcherCache db) + { + foreach (var volume in volumes) + { + 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.")); + Thread th = new Thread(new ParameterizedThreadStart(MonitorThread)); + th.Start(new Dictionary { { "Volume", volume }, { "MFTSearcherCache", 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(); + Wox.Infrastructure.MFTSearch.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; + // 构建输入参数 + 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(object param) -// { + return rujd; + } + private void MonitorThread(object param) + { -// MFTSearcherCache db = (param as Dictionary)["MFTSearcherCache"] as MFTSearcherCache; -// string volume = (param as Dictionary)["Volume"] as string; -// IntPtr pbuffer = Marshal.AllocHGlobal(0x1000); -// PInvokeWin32.READ_USN_JOURNAL_DATA rujd = SetupInputData4JournalRead(volume, 0xFFFFFFFF); -// UInt32 cbRead; -// IntPtr prujd; + MFTSearcherCache db = (param as Dictionary)["MFTSearcherCache"] as MFTSearcherCache; + string volume = (param as Dictionary)["Volume"] as string; + 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); + while (true) + { + prujd = Marshal.AllocHGlobal(Marshal.SizeOf(rujd)); + PInvokeWin32.ZeroMemory(prujd, Marshal.SizeOf(rujd)); + Marshal.StructureToPtr(rujd, prujd, true); -// Debug.WriteLine(string.Format("\nMoniting on {0}......", volume)); -// IntPtr pVolume = Wox.Infrastructure.MFTSearch.MFTSearcher.GetVolumeJournalHandle(volume); + Debug.WriteLine(string.Format("\nMoniting on {0}......", volume)); + IntPtr pVolume = Wox.Infrastructure.MFTSearch.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); + 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; + 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; -// } -// } + 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) -// { -// var dbCached = db.FindByFrn(volume, usn.FRN); -// Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, dbCached, db); -// Debug.WriteLine(string.Format("------USN[frn={0}]------", usn.FRN)); -// Debug.WriteLine(string.Format("FileName={0}, USNChangeReason={1}", usn.FileName, USNChangeReason.ReasonPrettyFormat(usn.Reason))); -// Debug.WriteLine(string.Format("FileName[Cached]={0}", dbCached == null ? "NoCache" : dbCached.FullPath)); -// Debug.WriteLine("--------------------------------------"); + Marshal.FreeHGlobal(prujd); + rujd.StartUsn = Marshal.ReadInt64(pbuffer); + } + } + private void ProcessUSN(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db) + { + var dbCached = db.FindByFrn(volume, usn.FRN); + Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, dbCached, db); + Debug.WriteLine(string.Format("------USN[frn={0}]------", usn.FRN)); + Debug.WriteLine(string.Format("FileName={0}, USNChangeReason={1}", usn.FileName, USNChangeReason.ReasonPrettyFormat(usn.Reason))); + Debug.WriteLine(string.Format("FileName[Cached]={0}", dbCached == null ? "NoCache" : dbCached.FullPath)); + Debug.WriteLine("--------------------------------------"); -// 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) -// { -// return; -// } -// else -// { -// Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, cached, db); -// var deleteok = db.DeleteRecord(volume, usn.FRN); -// Debug.WriteLine(string.Format(">>>> File {0} deleted {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); -// //string fullpath = newRecord.Name; -// //db.FindRecordPath(newRecord, ref fullpath, db.GetFolderSource(volume)); -// //newRecord.FullPath = fullpath; -// var oldRecord = db.FindByFrn(volume, usn.FRN); -// Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, oldRecord, db); -// Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, newRecord, db); -// Debug.WriteLine(string.Format(">>>> RenameFile {0} to {1}", oldRecord.FullPath, newRecord.FullPath)); -// db.UpdateRecord(volume, newRecord, -// usn.IsFolder ? USNRecordType.Folder : USNRecordType.File); -// if (RecordRenameEvent != null) RecordRenameEvent(oldRecord, newRecord); -// if (newRecord.FullPath.Contains("$RECYCLE.BIN")) -// { -// Debug.WriteLine(string.Format(">>>> Means {0} moved to recycle.", oldRecord.FullPath)); -// } -// } -// private void ProcessFileCreate(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db) -// { -// USNRecord record = USNRecord.ParseUSN(volume, usn); -// //string fullpath = record.Name; -// //db.FindRecordPath(record, ref fullpath, db.GetFolderSource(volume)); -// //record.FullPath = fullpath; -// db.AddRecord(volume, record, usn.IsFolder ? USNRecordType.Folder : USNRecordType.File); -// Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, record, db); -// Debug.WriteLine(string.Format(">>>> NewFile: {0}", record.FullPath)); -// if (RecordAddedEvent != null) -// RecordAddedEvent(record); -// } + 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) + { + return; + } + else + { + Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, cached, db); + var deleteok = db.DeleteRecord(volume, usn.FRN); + Debug.WriteLine(string.Format(">>>> File {0} deleted {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); + //string fullpath = newRecord.Name; + //db.FindRecordPath(newRecord, ref fullpath, db.GetFolderSource(volume)); + //newRecord.FullPath = fullpath; + var oldRecord = db.FindByFrn(volume, usn.FRN); + Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, oldRecord, db); + Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, newRecord, db); + Debug.WriteLine(string.Format(">>>> RenameFile {0} to {1}", oldRecord.FullPath, newRecord.FullPath)); + db.UpdateRecord(volume, newRecord, + usn.IsFolder ? USNRecordType.Folder : USNRecordType.File); + if (RecordRenameEvent != null) RecordRenameEvent(oldRecord, newRecord); + if (newRecord.FullPath.Contains("$RECYCLE.BIN")) + { + Debug.WriteLine(string.Format(">>>> Means {0} moved to recycle.", oldRecord.FullPath)); + } + } + private void ProcessFileCreate(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db) + { + USNRecord record = USNRecord.ParseUSN(volume, usn); + //string fullpath = record.Name; + //db.FindRecordPath(record, ref fullpath, db.GetFolderSource(volume)); + //record.FullPath = fullpath; + db.AddRecord(volume, record, usn.IsFolder ? USNRecordType.Folder : USNRecordType.File); + Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, record, db); + Debug.WriteLine(string.Format(">>>> NewFile: {0}", record.FullPath)); + if (RecordAddedEvent != null) + RecordAddedEvent(record); + } -// private bool MaskEqual(uint target, uint compare) -// { -// return (target & compare) != 0; -// } -// } -//} + private bool MaskEqual(uint target, uint compare) + { + return (target & compare) != 0; + } + } +} diff --git a/Wox.Test/MFTSearcherTest.cs b/Wox.Test/MFTSearcherTest.cs index c7a9ec5841..6008788a6d 100644 --- a/Wox.Test/MFTSearcherTest.cs +++ b/Wox.Test/MFTSearcherTest.cs @@ -16,7 +16,7 @@ namespace Wox.Test var searchtimestart = DateTime.Now; MFTSearcher.IndexAllVolumes(); var searchtimeend = DateTime.Now; - Console.WriteLine(string.Format("{0} file indexed, {1}ms has spent.", MFTSearcher.IndexedRecordsCount, searchtimeend.Subtract(searchtimestart).TotalMilliseconds)); + Console.WriteLine(string.Format("{0} file indexed, {1}ms has spent.", MFTSearcher.IndexedFileCount, searchtimeend.Subtract(searchtimestart).TotalMilliseconds)); searchtimestart = DateTime.Now; List mftSearchRecords = MFTSearcher.Search("q"); @@ -34,6 +34,7 @@ namespace Wox.Test { long oldWorkingSet = System.Diagnostics.Process.GetCurrentProcess().WorkingSet64; MFTSearcher.IndexAllVolumes(); + GC.Collect(); long newWorkingSet = System.Diagnostics.Process.GetCurrentProcess().WorkingSet64; Console.WriteLine(string.Format("Index: {0}M", (newWorkingSet - oldWorkingSet)/(1024*1024))); From c61db8c9572d4d4d10560314e5f18af62df0d636 Mon Sep 17 00:00:00 2001 From: qianlifeng Date: Fri, 24 Oct 2014 09:43:43 +0800 Subject: [PATCH 07/19] Revert MFT Changes. --- Plugins/Wox.Plugin.FindFile/Main.cs | 2 +- Wox.Infrastructure/MFTSearch/MFTSearcher.cs | 20 +-- .../MFTSearch/MFTSearcherCache.cs | 140 +++++++++++++----- Wox.Test/MFTSearcherTest.cs | 2 +- 4 files changed, 119 insertions(+), 45 deletions(-) diff --git a/Plugins/Wox.Plugin.FindFile/Main.cs b/Plugins/Wox.Plugin.FindFile/Main.cs index 5cad15015b..f53522f852 100644 --- a/Plugins/Wox.Plugin.FindFile/Main.cs +++ b/Plugins/Wox.Plugin.FindFile/Main.cs @@ -36,7 +36,7 @@ namespace Wox.Plugin.FindFile MFTSearcher.IndexAllVolumes(); initial = true; var searchtimeend = DateTime.Now; - Debug.WriteLine(string.Format("{0} file, indexed, {1}ms has spent.", MFTSearcher.IndexedRecordsCount, searchtimeend.Subtract(searchtimestart).TotalMilliseconds)); + Debug.WriteLine(string.Format("{0} file, indexed, {1}ms has spent.", MFTSearcher.IndexedFileCount, searchtimeend.Subtract(searchtimestart).TotalMilliseconds)); } private Result ConvertMFTSearch(MFTSearchRecord record, string query) diff --git a/Wox.Infrastructure/MFTSearch/MFTSearcher.cs b/Wox.Infrastructure/MFTSearch/MFTSearcher.cs index 7d4b603e86..dbc31fdee6 100644 --- a/Wox.Infrastructure/MFTSearch/MFTSearcher.cs +++ b/Wox.Infrastructure/MFTSearch/MFTSearcher.cs @@ -22,8 +22,8 @@ namespace Wox.Infrastructure.MFTSearch List files; List folders; EnumerateVolume(volume, out files, out folders); - //cache.AddRecord(files); - //cache.AddRecord(folders); + cache.AddRecord(volume, files, USNRecordType.File); + cache.AddRecord(volume, folders, USNRecordType.Folder); } public static void IndexAllVolumes() @@ -34,9 +34,13 @@ namespace Wox.Infrastructure.MFTSearch } } - public static long IndexedRecordsCount + public static long IndexedFileCount { - get { return cache.RecordsCount; } + get { return cache.FileCount; } + } + public static long IndexedFolderCount + { + get { return cache.FolderCount; } } public static List Search(string item) @@ -44,7 +48,7 @@ namespace Wox.Infrastructure.MFTSearch if (string.IsNullOrEmpty(item)) return new List(); List found = cache.FindByName(item); - found.ForEach(x => FillPath(x, cache)); + found.ForEach(x => FillPath(x.VolumeName, x, cache)); return found.ConvertAll(o => new MFTSearchRecord(o)); } @@ -250,16 +254,14 @@ namespace Wox.Infrastructure.MFTSearch } Marshal.FreeHGlobal(pData); } - - internal static void FillPath(USNRecord record, MFTSearcherCache db) + internal static void FillPath(string volume, USNRecord record, MFTSearcherCache db) { if (record == null) return; - var fdSource = db.GetAllRecords(); + var fdSource = db.GetFolderSource(volume); string fullpath = record.Name; FindRecordPath(record, ref fullpath, fdSource); record.FullPath = fullpath; } - private static void FindRecordPath(USNRecord curRecord, ref string fullpath, Dictionary fdSource) { if (curRecord.IsVolumeRoot) return; diff --git a/Wox.Infrastructure/MFTSearch/MFTSearcherCache.cs b/Wox.Infrastructure/MFTSearch/MFTSearcherCache.cs index 1ea9335a6e..72fce782e1 100644 --- a/Wox.Infrastructure/MFTSearch/MFTSearcherCache.cs +++ b/Wox.Infrastructure/MFTSearch/MFTSearcherCache.cs @@ -6,55 +6,127 @@ namespace Wox.Infrastructure.MFTSearch { internal class MFTSearcherCache { - private Dictionary records = new Dictionary(100000); - private Lookup recordsLookup; + private Dictionary> _volumes_files = new Dictionary>(); + private Dictionary> _volumes_folders = new Dictionary>(); public MFTSearcherCache() { } - public void AddRecord(List record) + public bool ContainsVolume(string volume) { - record.ForEach(AddRecord); + return _volumes_files.ContainsKey(volume) && _volumes_folders.ContainsKey(volume); } - - public void AddRecord(USNRecord record) + public void AddRecord(string volume, List r, USNRecordType type) { - if(!records.ContainsKey(record.FRN)) records.Add(record.FRN, record); - } - - public bool DeleteRecord(ulong frn) - { - return records.Remove(frn); - } - - public void UpdateRecord(USNRecord record) - { - USNRecord firstOrDefault = records[record.FRN]; - if (firstOrDefault != null) + if (type == USNRecordType.File) { - firstOrDefault.Name = record.Name; - firstOrDefault.FullPath = record.FullPath; - firstOrDefault.VolumeName = record.VolumeName; + CheckHashTableKey(_volumes_files, volume); + r.ForEach(x => _volumes_files[volume].Add(x.FRN, x)); + } + else + { + CheckHashTableKey(_volumes_folders, volume); + r.ForEach(x => _volumes_folders[volume].Add(x.FRN, x)); + } + } + public void AddRecord(string volume, USNRecord record, USNRecordType type) + { + if (type == USNRecordType.File) + { + CheckHashTableKey(_volumes_files, volume); + _volumes_files[volume].Add(record.FRN, record); + } + else + { + CheckHashTableKey(_volumes_folders, volume); + _volumes_folders[volume].Add(record.FRN, record); + } + } + private void CheckHashTableKey(Dictionary> hashtable, string key) + { + if (!hashtable.ContainsKey(key)) + hashtable.Add(key, new Dictionary()); + } + public bool DeleteRecord(string volume, ulong frn) + { + bool result = false; + result = DeleteRecordHashTableItem(_volumes_files, volume, frn); + if (!result) result = DeleteRecordHashTableItem(_volumes_folders, volume, frn); + return result; + } + private bool DeleteRecordHashTableItem(Dictionary> hashtable, string volume, ulong frn) + { + if (hashtable.ContainsKey(volume) && hashtable[volume].ContainsKey(frn)) + { + hashtable[volume].Remove(frn); + return true; + } + else + { + return false; + } + } + public void UpdateRecord(string volume, USNRecord record, USNRecordType type) + { + if (type == USNRecordType.File) + RealUpdateRecord(volume, _volumes_files, record); + else + RealUpdateRecord(volume, _volumes_folders, record); + } + private bool RealUpdateRecord(string volume, Dictionary> source, USNRecord record) + { + if (source.ContainsKey(volume) && source[volume].ContainsKey(record.FRN)) + { + source[volume][record.FRN] = record; + return true; + } + else + { + return false; } } - - public List FindByName(string filename) { filename = filename.ToLower(); - var query = from file in records.Values - where file.Name.ToLower().Contains(filename) - select file; - return query.ToList(); - } + var fileQuery = from filesInVolumeDic in _volumes_files.Values + from eachFilePair in filesInVolumeDic + where eachFilePair.Value.Name.ToLower().Contains(filename) + select eachFilePair.Value; - public long RecordsCount - { - get { return records.Count; } + var folderQuery = from fldsInVolumeDic in _volumes_folders.Values + from eachFldPair in fldsInVolumeDic + where eachFldPair.Value.Name.ToLower().Contains(filename) + select eachFldPair.Value; + + List result = new List(); + + result.AddRange(fileQuery); + result.AddRange(folderQuery); + + return result; } - - public Dictionary GetAllRecords() + public USNRecord FindByFrn(string volume, ulong frn) { - return records; + if ((!_volumes_files.ContainsKey(volume)) || (!_volumes_folders.ContainsKey(volume))) + throw new Exception(string.Format("DB not contain the volume: {0}", volume)); + USNRecord result = null; + _volumes_files[volume].TryGetValue(frn, out result); + if (result != null) return result; + _volumes_folders[volume].TryGetValue(frn, out result); + return result; + } + public long FileCount + { + get { return _volumes_files.Sum(x => x.Value.Count); } + } + public long FolderCount + { + get { return _volumes_folders.Sum(x => x.Value.Count); } + } + public Dictionary GetFolderSource(string volume) + { + Dictionary result = null; + _volumes_folders.TryGetValue(volume, out result); + return result; } } } diff --git a/Wox.Test/MFTSearcherTest.cs b/Wox.Test/MFTSearcherTest.cs index c7a9ec5841..a496a18ce2 100644 --- a/Wox.Test/MFTSearcherTest.cs +++ b/Wox.Test/MFTSearcherTest.cs @@ -16,7 +16,7 @@ namespace Wox.Test var searchtimestart = DateTime.Now; MFTSearcher.IndexAllVolumes(); var searchtimeend = DateTime.Now; - Console.WriteLine(string.Format("{0} file indexed, {1}ms has spent.", MFTSearcher.IndexedRecordsCount, searchtimeend.Subtract(searchtimestart).TotalMilliseconds)); + Console.WriteLine(string.Format("{0} file indexed, {1}ms has spent.", MFTSearcher.IndexedFileCount, searchtimeend.Subtract(searchtimestart).TotalMilliseconds)); searchtimestart = DateTime.Now; List mftSearchRecords = MFTSearcher.Search("q"); From f399ef8f693a003d25587c052e247032dbd13deb Mon Sep 17 00:00:00 2001 From: qianlifeng Date: Fri, 24 Oct 2014 13:09:51 +0800 Subject: [PATCH 08/19] fix #151 Add context menu for programs --- Plugins/Wox.Plugin.FindFile/Images/edit.png | Bin 5765 -> 0 bytes Plugins/Wox.Plugin.FindFile/Images/open.png | Bin 0 -> 941 bytes Plugins/Wox.Plugin.FindFile/Main.cs | 2 +- .../Wox.Plugin.FindFile.csproj | 6 ++-- Wox.Infrastructure/WindowsShellRun.cs | 17 ++++------ Wox.Plugin.SystemPlugins/Program/Programs.cs | 31 ++++++++++++++++-- Wox.Plugin/IPublicAPI.cs | 2 +- .../StringNullOrEmptyToVisibilityConverter.cs | 21 ++++++++++++ Wox/Images/menu.png | Bin 0 -> 346 bytes Wox/Images/open.png | Bin 0 -> 941 bytes Wox/MainWindow.xaml.cs | 4 +-- Wox/ResultPanel.xaml | 7 ++-- Wox/Wox.csproj | 8 +++++ 13 files changed, 76 insertions(+), 22 deletions(-) delete mode 100644 Plugins/Wox.Plugin.FindFile/Images/edit.png create mode 100644 Plugins/Wox.Plugin.FindFile/Images/open.png create mode 100644 Wox/Images/menu.png create mode 100644 Wox/Images/open.png diff --git a/Plugins/Wox.Plugin.FindFile/Images/edit.png b/Plugins/Wox.Plugin.FindFile/Images/edit.png deleted file mode 100644 index f1710b7c89c33e8a083dbec8c25ec8de38e4971a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5765 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 I=akR{03N=HV*mgE literal 0 HcmV?d00001 diff --git a/Plugins/Wox.Plugin.FindFile/Main.cs b/Plugins/Wox.Plugin.FindFile/Main.cs index f53522f852..6d35e1ac45 100644 --- a/Plugins/Wox.Plugin.FindFile/Main.cs +++ b/Plugins/Wox.Plugin.FindFile/Main.cs @@ -92,7 +92,7 @@ namespace Wox.Plugin.FindFile } return true; }, - IcoPath = "Images/edit.png" + IcoPath = "Images/open.png" }); if (!record.IsFolder) diff --git a/Plugins/Wox.Plugin.FindFile/Wox.Plugin.FindFile.csproj b/Plugins/Wox.Plugin.FindFile/Wox.Plugin.FindFile.csproj index 707e2744f4..4db15cf579 100644 --- a/Plugins/Wox.Plugin.FindFile/Wox.Plugin.FindFile.csproj +++ b/Plugins/Wox.Plugin.FindFile/Wox.Plugin.FindFile.csproj @@ -54,9 +54,6 @@
- - Always - Always @@ -66,6 +63,9 @@ Always + + Always + Always diff --git a/Wox.Infrastructure/WindowsShellRun.cs b/Wox.Infrastructure/WindowsShellRun.cs index 054802cc52..f8ec456b4a 100644 --- a/Wox.Infrastructure/WindowsShellRun.cs +++ b/Wox.Infrastructure/WindowsShellRun.cs @@ -78,7 +78,7 @@ namespace Wox.Infrastructure [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)] static extern bool UrlIs(string pszUrl, int UrlIs); - static void ShellExecCmdLine(IntPtr hInstance, IntPtr hwnd, string command, string startDir, global::System.Diagnostics.ProcessWindowStyle nShow, ShellExecCmdLineFlags dwSeclFlags) + static void ShellExecCmdLine(IntPtr hInstance, IntPtr hwnd, string command, string startDir, global::System.Diagnostics.ProcessWindowStyle nShow, ShellExecCmdLineFlags dwSeclFlags,bool runAsAdministrator = false) { string cmd = command; string args = null; @@ -143,6 +143,7 @@ namespace Wox.Infrastructure startInfo.UseShellExecute = true; startInfo.Arguments = args; startInfo.FileName = cmd; + if (runAsAdministrator) startInfo.Verb = "runas"; startInfo.WindowStyle = global::System.Diagnostics.ProcessWindowStyle.Normal; startInfo.ErrorDialog = (dwSeclFlags | ShellExecCmdLineFlags.SECL_NO_UI) == 0; startInfo.ErrorDialogParentHandle = hwnd; @@ -280,17 +281,12 @@ namespace Wox.Infrastructure hresult); } - public static void Start(string cmd) + public static void Start(string cmd, bool runAsAdministrator = false) { - Start(cmd, false); + Start(cmd, false, IntPtr.Zero,runAsAdministrator); } - public static void Start(string cmd, bool showErrorDialog) - { - Start(cmd, false, IntPtr.Zero); - } - - public static void Start(string cmd, bool showErrorDialog, IntPtr errorDialogHwnd) + public static void Start(string cmd, bool showErrorDialog, IntPtr errorDialogHwnd, bool runAsAdministrator = false) { cmd = cmd.Trim(); // PathRemoveBlanks cmd = Environment.ExpandEnvironmentVariables(cmd); // SHExpandEnvironmentStrings @@ -306,7 +302,8 @@ namespace Wox.Infrastructure cmd, null, // i have no ideas about this field global::System.Diagnostics.ProcessWindowStyle.Normal, - ShellExecCmdLineFlags.SECL__IGNORE_ERROR | ShellExecCmdLineFlags.SECL_USE_IDLIST | ShellExecCmdLineFlags.SECL_LOG_USAGE | (showErrorDialog ? 0 : ShellExecCmdLineFlags.SECL_NO_UI) + ShellExecCmdLineFlags.SECL__IGNORE_ERROR | ShellExecCmdLineFlags.SECL_USE_IDLIST | ShellExecCmdLineFlags.SECL_LOG_USAGE | (showErrorDialog ? 0 : ShellExecCmdLineFlags.SECL_NO_UI), + runAsAdministrator ); if (!string.IsNullOrEmpty(home) && Directory.Exists(home)) Environment.CurrentDirectory = oldCwd; } diff --git a/Wox.Plugin.SystemPlugins/Program/Programs.cs b/Wox.Plugin.SystemPlugins/Program/Programs.cs index ff87a84667..75432d8b5d 100644 --- a/Wox.Plugin.SystemPlugins/Program/Programs.cs +++ b/Wox.Plugin.SystemPlugins/Program/Programs.cs @@ -42,6 +42,31 @@ namespace Wox.Plugin.SystemPlugins.Program context.API.HideApp(); context.API.ShellRun(c.ExecutePath); return true; + }, + ContextMenu = new List() + { + new Result() + { + Title = "Open", + Action = _ => + { + context.API.HideApp(); + context.API.ShellRun(c.ExecutePath); + return true; + }, + IcoPath = "Images/open.png" + }, + new Result() + { + Title = "Open With Administrator", + Action = _ => + { + context.API.HideApp(); + context.API.ShellRun(c.ExecutePath,true); + return true; + }, + IcoPath = "Images/cmd.png" + } } }).ToList(); } @@ -84,11 +109,11 @@ namespace Wox.Plugin.SystemPlugins.Program Type sourceClass; if (SourceTypes.TryGetValue(source.Type, out sourceClass)) { - ConstructorInfo constructorInfo = sourceClass.GetConstructor(new[] {typeof (ProgramSource)}); + ConstructorInfo constructorInfo = sourceClass.GetConstructor(new[] { typeof(ProgramSource) }); if (constructorInfo != null) { IProgramSource programSource = - constructorInfo.Invoke(new object[] {source}) as IProgramSource; + constructorInfo.Invoke(new object[] { source }) as IProgramSource; sources.Add(programSource); } } @@ -106,7 +131,7 @@ namespace Wox.Plugin.SystemPlugins.Program } // filter duplicate program - tempPrograms = tempPrograms.GroupBy(x => new {x.ExecutePath, x.ExecuteName}) + tempPrograms = tempPrograms.GroupBy(x => new { x.ExecutePath, x.ExecuteName }) .Select(g => g.First()).ToList(); programs = tempPrograms; diff --git a/Wox.Plugin/IPublicAPI.cs b/Wox.Plugin/IPublicAPI.cs index 85e501b651..64ff13ab08 100644 --- a/Wox.Plugin/IPublicAPI.cs +++ b/Wox.Plugin/IPublicAPI.cs @@ -9,7 +9,7 @@ namespace Wox.Plugin void PushResults(Query query,PluginMetadata plugin, List results); - bool ShellRun(string cmd); + bool ShellRun(string cmd, bool runAsAdministrator = false); void ChangeQuery(string query, bool requery = false); diff --git a/Wox/Converters/StringNullOrEmptyToVisibilityConverter.cs b/Wox/Converters/StringNullOrEmptyToVisibilityConverter.cs index d6d01f0714..f536e74735 100644 --- a/Wox/Converters/StringNullOrEmptyToVisibilityConverter.cs +++ b/Wox/Converters/StringNullOrEmptyToVisibilityConverter.cs @@ -1,6 +1,8 @@ using System; +using System.Collections.Generic; using System.Globalization; using System.Windows; +using Wox.Plugin; namespace Wox.Converters { @@ -21,4 +23,23 @@ namespace Wox.Converters return this; } } + + public class ContextMenuEmptyToWidthConverter : ConvertorBase + { + public override object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + List results = value as List; + return results == null || results.Count == 0 ? 0 : 17; + } + + public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return null; + } + + public override object ProvideValue(IServiceProvider serviceProvider) + { + return this; + } + } } \ No newline at end of file diff --git a/Wox/Images/menu.png b/Wox/Images/menu.png new file mode 100644 index 0000000000000000000000000000000000000000..d7395f4d9fbc9552f63ae80b8e9dc81a69b108d7 GIT binary patch literal 346 zcmV-g0j2(lP)_i805%p8yo?|oB#pKyMEoD$5(D2??fPI~X5lx?yjd1S(T#}CbWF9F zrs)#L@$(2B1i^#P^GxfyQkG@3EQ@l00V~FFWGGzMm5(|CE6TE@JkKSJ&ghER^KHdH z^`0ZDsycBbkmq^Y9)Oh|K=43U(gVw~499V3pF~xhb84FA&4*!N*fR`6>ib?fzReZ$`bwr$gHrm76XpfpVxZ`)RS;QKyxU8fviz>2!A1sqM1MEeS0 snQ5B$?S$7O9&AlsO!xo)*GGT>03%omcdi7(3jhEB07*qoM6N<$f@>X-X#fBK literal 0 HcmV?d00001 diff --git a/Wox/Images/open.png b/Wox/Images/open.png new file mode 100644 index 0000000000000000000000000000000000000000..6006d12104249ddab4cf3141602310260f23e79c GIT binary patch literal 941 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzwj^(N7l!{JxM1({$v_d#0*}aI zAngIhZYQ(tK!Rljj_E*J0gT&!&6&%}W%Q|8xKRNt$gE7qd%* z>*nUNg6TYsm-+*}rZw2R?sv@a-*gntM@Wm zL`pwfA1>l)USFf;BD}N_Wp{GQ8td zD7oe$$KoK($#A6g>3rrJM;MZw5AJ9dV7>0o)L_ebP-#thm2f9xcx>)NO@;-o3zQj7 z8K1frb85#YhRx~Q1sS$&l@(;j)$L?zVGMe0+2wRq&S+D|svF+#8D;eo9W*m|1q@xZ z8+gTYr?!Z(h2lNZ2Sw zbD!e<*49!F^B7mFkK2O_4=yQpI>E5qtMHA+)WDk`dT;%FVYX%+GtWvJPOY73cb9X; zL~thhIlYqjb@Bsed8Gfx2eZ7LbQyNM_&dG#dQi%*&Yh(SHXAN+FkI4HajMQ|`+Eb1 z(`|Qu1<5dPxc1tsP}XDnel5uY6V@(Wy(X)z$Ep>UzPQ))Z??g;MOJ^U7()Gxx_XZB zB|B*Tjbiv)xBquWx_ZUMf4(ojSH1XJ#rQ74K(2qjnCnNa^Pi7rd}ql}nd{fSZrwUN z<{$qQ1n;^2W03wGwC}-3<#oWMu3F+6QIe8al4_M)lnSI6j0_A7bPbGj4GlsJ46O_- ztxSMiGb;mw`x7p4qG-s?PsvQH1Zpra(={;EH3Didurjf*GPZzd;8AJp25MmNboFyt I=akR{03N=HV*mgE literal 0 HcmV?d00001 diff --git a/Wox/MainWindow.xaml.cs b/Wox/MainWindow.xaml.cs index bce6c69777..dc3e617dd2 100644 --- a/Wox/MainWindow.xaml.cs +++ b/Wox/MainWindow.xaml.cs @@ -720,14 +720,14 @@ namespace Wox this.Opacity = this.AllowsTransparency ? UserSettingStorage.Instance.Opacity : 1; } - public bool ShellRun(string cmd) + public bool ShellRun(string cmd, bool runAsAdministrator = false) { try { if (string.IsNullOrEmpty(cmd)) throw new ArgumentNullException(); - Wox.Infrastructure.WindowsShellRun.Start(cmd); + WindowsShellRun.Start(cmd, runAsAdministrator); return true; } catch (Exception ex) diff --git a/Wox/ResultPanel.xaml b/Wox/ResultPanel.xaml index d1a8e28afd..a156d6fc18 100644 --- a/Wox/ResultPanel.xaml +++ b/Wox/ResultPanel.xaml @@ -7,7 +7,7 @@ mc:Ignorable="d" d:DesignWidth="100" d:DesignHeight="100"> - + @@ -24,6 +24,7 @@ + @@ -32,14 +33,16 @@ - + + + diff --git a/Wox/Wox.csproj b/Wox/Wox.csproj index 6dbd0ac08f..e969c37806 100644 --- a/Wox/Wox.csproj +++ b/Wox/Wox.csproj @@ -392,6 +392,14 @@ + + + PreserveNewest + + + + + From 225d46b228e80a342374864777702b1fead31cac Mon Sep 17 00:00:00 2001 From: qianlifeng Date: Fri, 24 Oct 2014 16:14:36 +0800 Subject: [PATCH 09/19] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c44b0e0636..7b02d14d21 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Features ========= 1. Search applications, files (via everything plugin) and chrome bookmarks 2. Search web contents with shortcuts (e.g. search google with `g keyword` or `youtube keyword`) -3. Search clipboard history (via clipboard plugin) +3. Search clipboard history (via clipboard plugin) 4. Themes support, get more themes from [http://www.getwox.com/theme](http://www.getwox.com/theme) 5. Plugin support, get more plugins from [http://www.getwox.com/plugin](http://www.getwox.com/plugin) From a7dfb9cb97bfce1fb49c500956777e4a537573be Mon Sep 17 00:00:00 2001 From: qianlifeng Date: Fri, 24 Oct 2014 16:48:14 +0800 Subject: [PATCH 10/19] Allow unsafe codes in Release build. --- Plugins/Wox.Plugin.FindFile/Main.cs | 19 ------------------- Wox.Infrastructure/Wox.Infrastructure.csproj | 1 + Wox.Plugin.SystemPlugins/Program/Programs.cs | 13 +------------ 3 files changed, 2 insertions(+), 31 deletions(-) diff --git a/Plugins/Wox.Plugin.FindFile/Main.cs b/Plugins/Wox.Plugin.FindFile/Main.cs index 6d35e1ac45..5f0518235d 100644 --- a/Plugins/Wox.Plugin.FindFile/Main.cs +++ b/Plugins/Wox.Plugin.FindFile/Main.cs @@ -76,25 +76,6 @@ namespace Wox.Plugin.FindFile { List contextMenus = new List(); - contextMenus.Add(new Result() - { - Title = "Open", - Action = _ => - { - try - { - Process.Start(record.FullPath); - } - catch - { - context.API.ShowMsg("Can't open " + record.FullPath, string.Empty, string.Empty); - return false; - } - return true; - }, - IcoPath = "Images/open.png" - }); - if (!record.IsFolder) { contextMenus.Add(new Result() diff --git a/Wox.Infrastructure/Wox.Infrastructure.csproj b/Wox.Infrastructure/Wox.Infrastructure.csproj index ae41dfffaa..fb42df5417 100644 --- a/Wox.Infrastructure/Wox.Infrastructure.csproj +++ b/Wox.Infrastructure/Wox.Infrastructure.csproj @@ -31,6 +31,7 @@ TRACE prompt 4 + true diff --git a/Wox.Plugin.SystemPlugins/Program/Programs.cs b/Wox.Plugin.SystemPlugins/Program/Programs.cs index 75432d8b5d..649ce9acde 100644 --- a/Wox.Plugin.SystemPlugins/Program/Programs.cs +++ b/Wox.Plugin.SystemPlugins/Program/Programs.cs @@ -47,18 +47,7 @@ namespace Wox.Plugin.SystemPlugins.Program { new Result() { - Title = "Open", - Action = _ => - { - context.API.HideApp(); - context.API.ShellRun(c.ExecutePath); - return true; - }, - IcoPath = "Images/open.png" - }, - new Result() - { - Title = "Open With Administrator", + Title = "Run As Administrator", Action = _ => { context.API.HideApp(); From 970c9e70e4f004d694f41a37acc42a6d353e8a50 Mon Sep 17 00:00:00 2001 From: qianlifeng Date: Mon, 27 Oct 2014 14:53:44 +0800 Subject: [PATCH 11/19] Move MFTSearch to find file plugin. --- .../Wox.Plugin.FindFile}/MFTSearch/MFTSearchRecord.cs | 0 .../Wox.Plugin.FindFile}/MFTSearch/MFTSearcher.cs | 0 .../Wox.Plugin.FindFile}/MFTSearch/MFTSearcherCache.cs | 0 .../Wox.Plugin.FindFile}/MFTSearch/PInvokeWin32.cs | 0 .../Wox.Plugin.FindFile}/MFTSearch/USNChangeReason.cs | 0 .../Wox.Plugin.FindFile}/MFTSearch/USNRecord.cs | 0 .../Wox.Plugin.FindFile}/MFTSearch/USNRecordType.cs | 0 .../Wox.Plugin.FindFile}/MFTSearch/VolumeMonitor.cs | 0 Plugins/Wox.Plugin.FindFile/Wox.Plugin.FindFile.csproj | 10 ++++++++++ Wox.Infrastructure/Wox.Infrastructure.csproj | 10 +--------- Wox.Test/Wox.Test.csproj | 4 ++++ Wox/Commands/SystemCommand.cs | 1 - Wox/MainWindow.xaml.cs | 1 - 13 files changed, 15 insertions(+), 11 deletions(-) rename {Wox.Infrastructure => Plugins/Wox.Plugin.FindFile}/MFTSearch/MFTSearchRecord.cs (100%) rename {Wox.Infrastructure => Plugins/Wox.Plugin.FindFile}/MFTSearch/MFTSearcher.cs (100%) rename {Wox.Infrastructure => Plugins/Wox.Plugin.FindFile}/MFTSearch/MFTSearcherCache.cs (100%) rename {Wox.Infrastructure => Plugins/Wox.Plugin.FindFile}/MFTSearch/PInvokeWin32.cs (100%) rename {Wox.Infrastructure => Plugins/Wox.Plugin.FindFile}/MFTSearch/USNChangeReason.cs (100%) rename {Wox.Infrastructure => Plugins/Wox.Plugin.FindFile}/MFTSearch/USNRecord.cs (100%) rename {Wox.Infrastructure => Plugins/Wox.Plugin.FindFile}/MFTSearch/USNRecordType.cs (100%) rename {Wox.Infrastructure => Plugins/Wox.Plugin.FindFile}/MFTSearch/VolumeMonitor.cs (100%) diff --git a/Wox.Infrastructure/MFTSearch/MFTSearchRecord.cs b/Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearchRecord.cs similarity index 100% rename from Wox.Infrastructure/MFTSearch/MFTSearchRecord.cs rename to Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearchRecord.cs diff --git a/Wox.Infrastructure/MFTSearch/MFTSearcher.cs b/Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearcher.cs similarity index 100% rename from Wox.Infrastructure/MFTSearch/MFTSearcher.cs rename to Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearcher.cs diff --git a/Wox.Infrastructure/MFTSearch/MFTSearcherCache.cs b/Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearcherCache.cs similarity index 100% rename from Wox.Infrastructure/MFTSearch/MFTSearcherCache.cs rename to Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearcherCache.cs diff --git a/Wox.Infrastructure/MFTSearch/PInvokeWin32.cs b/Plugins/Wox.Plugin.FindFile/MFTSearch/PInvokeWin32.cs similarity index 100% rename from Wox.Infrastructure/MFTSearch/PInvokeWin32.cs rename to Plugins/Wox.Plugin.FindFile/MFTSearch/PInvokeWin32.cs diff --git a/Wox.Infrastructure/MFTSearch/USNChangeReason.cs b/Plugins/Wox.Plugin.FindFile/MFTSearch/USNChangeReason.cs similarity index 100% rename from Wox.Infrastructure/MFTSearch/USNChangeReason.cs rename to Plugins/Wox.Plugin.FindFile/MFTSearch/USNChangeReason.cs diff --git a/Wox.Infrastructure/MFTSearch/USNRecord.cs b/Plugins/Wox.Plugin.FindFile/MFTSearch/USNRecord.cs similarity index 100% rename from Wox.Infrastructure/MFTSearch/USNRecord.cs rename to Plugins/Wox.Plugin.FindFile/MFTSearch/USNRecord.cs diff --git a/Wox.Infrastructure/MFTSearch/USNRecordType.cs b/Plugins/Wox.Plugin.FindFile/MFTSearch/USNRecordType.cs similarity index 100% rename from Wox.Infrastructure/MFTSearch/USNRecordType.cs rename to Plugins/Wox.Plugin.FindFile/MFTSearch/USNRecordType.cs diff --git a/Wox.Infrastructure/MFTSearch/VolumeMonitor.cs b/Plugins/Wox.Plugin.FindFile/MFTSearch/VolumeMonitor.cs similarity index 100% rename from Wox.Infrastructure/MFTSearch/VolumeMonitor.cs rename to Plugins/Wox.Plugin.FindFile/MFTSearch/VolumeMonitor.cs diff --git a/Plugins/Wox.Plugin.FindFile/Wox.Plugin.FindFile.csproj b/Plugins/Wox.Plugin.FindFile/Wox.Plugin.FindFile.csproj index 4db15cf579..3cabda2b97 100644 --- a/Plugins/Wox.Plugin.FindFile/Wox.Plugin.FindFile.csproj +++ b/Plugins/Wox.Plugin.FindFile/Wox.Plugin.FindFile.csproj @@ -21,6 +21,7 @@ DEBUG;TRACE prompt 4 + true
pdbonly @@ -29,6 +30,7 @@ TRACE prompt 4 + true @@ -41,6 +43,14 @@ + + + + + + + + diff --git a/Wox.Infrastructure/Wox.Infrastructure.csproj b/Wox.Infrastructure/Wox.Infrastructure.csproj index fb42df5417..df363b7421 100644 --- a/Wox.Infrastructure/Wox.Infrastructure.csproj +++ b/Wox.Infrastructure/Wox.Infrastructure.csproj @@ -31,7 +31,7 @@ TRACE prompt 4 - true + false @@ -57,14 +57,6 @@ - - - - - - - - diff --git a/Wox.Test/Wox.Test.csproj b/Wox.Test/Wox.Test.csproj index 54cdca3d43..c34a3ec954 100644 --- a/Wox.Test/Wox.Test.csproj +++ b/Wox.Test/Wox.Test.csproj @@ -52,6 +52,10 @@ + + {84EA88B4-71F2-4A3D-9771-D7B0244C0D81} + Wox.Plugin.FindFile + {4FD29318-A8AB-4D8F-AA47-60BC241B8DA3} Wox.Infrastructure diff --git a/Wox/Commands/SystemCommand.cs b/Wox/Commands/SystemCommand.cs index 1a5a1949b7..a1fc477a82 100644 --- a/Wox/Commands/SystemCommand.cs +++ b/Wox/Commands/SystemCommand.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; -using Wox.Infrastructure.MFTSearch; using Wox.Infrastructure.Storage.UserSettings; using Wox.Plugin; using Wox.Plugin.SystemPlugins; diff --git a/Wox/MainWindow.xaml.cs b/Wox/MainWindow.xaml.cs index dc3e617dd2..e6ecf4cb53 100644 --- a/Wox/MainWindow.xaml.cs +++ b/Wox/MainWindow.xaml.cs @@ -17,7 +17,6 @@ using NHotkey.Wpf; using Wox.Commands; using Wox.Helper; using Wox.Infrastructure; -using Wox.Infrastructure.MFTSearch; using Wox.Infrastructure.Storage; using Wox.Infrastructure.Storage.UserSettings; using Wox.Plugin; From 07ed6a64168c695acf1036885a2f71672c51efef Mon Sep 17 00:00:00 2001 From: qianlifeng Date: Mon, 27 Oct 2014 15:08:32 +0800 Subject: [PATCH 12/19] fix #189 startup is too slow --- Wox/Helper/Forker.cs | 145 ------------------------------------ Wox/PluginLoader/Plugins.cs | 6 +- Wox/Wox.csproj | 1 - 3 files changed, 2 insertions(+), 150 deletions(-) delete mode 100644 Wox/Helper/Forker.cs diff --git a/Wox/Helper/Forker.cs b/Wox/Helper/Forker.cs deleted file mode 100644 index 658e2e5b86..0000000000 --- a/Wox/Helper/Forker.cs +++ /dev/null @@ -1,145 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; - -namespace Wox.Helper -{ - /// - /// Provides a caller-friendly wrapper around parallel actions. - /// http://stackoverflow.com/a/540380 - /// - public sealed class Forker - { - int running; - private readonly object joinLock = new object(), eventLock = new object(); - - /// Raised when all operations have completed. - public event EventHandler AllComplete - { - add { lock (eventLock) { allComplete += value; } } - remove { lock (eventLock) { allComplete -= value; } } - } - private EventHandler allComplete; - /// Raised when each operation completes. - public event EventHandler ItemComplete - { - add { lock (eventLock) { itemComplete += value; } } - remove { lock (eventLock) { itemComplete -= value; } } - } - private EventHandler itemComplete; - - private void OnItemComplete(object state, Exception exception) - { - EventHandler itemHandler = itemComplete; // don't need to lock - if (itemHandler != null) itemHandler(this, new ParallelEventArgs(state, exception)); - if (Interlocked.Decrement(ref running) == 0) - { - EventHandler allHandler = allComplete; // don't need to lock - if (allHandler != null) allHandler(this, EventArgs.Empty); - lock (joinLock) - { - Monitor.PulseAll(joinLock); - } - } - } - - /// Adds a callback to invoke when each operation completes. - /// Current instance (for fluent API). - public Forker OnItemComplete(EventHandler handler) - { - if (handler == null) throw new ArgumentNullException("handler"); - ItemComplete += handler; - return this; - } - - /// Adds a callback to invoke when all operations are complete. - /// Current instance (for fluent API). - public Forker OnAllComplete(EventHandler handler) - { - if (handler == null) throw new ArgumentNullException("handler"); - AllComplete += handler; - return this; - } - - /// Waits for all operations to complete. - public void Join() - { - Join(-1); - } - - /// Waits (with timeout) for all operations to complete. - /// Whether all operations had completed before the timeout. - public bool Join(int millisecondsTimeout) - { - lock (joinLock) - { - if (CountRunning() == 0) return true; - Thread.SpinWait(1); // try our luck... - return (CountRunning() == 0) || - Monitor.Wait(joinLock, millisecondsTimeout); - } - } - - /// Indicates the number of incomplete operations. - /// The number of incomplete operations. - public int CountRunning() - { - return Interlocked.CompareExchange(ref running, 0, 0); - } - - /// Enqueues an operation. - /// The operation to perform. - /// The current instance (for fluent API). - public Forker Fork(ThreadStart action) { return Fork(action, null); } - - /// Enqueues an operation. - /// The operation to perform. - /// An opaque object, allowing the caller to identify operations. - /// The current instance (for fluent API). - public Forker Fork(ThreadStart action, object state) - { - if (action == null) throw new ArgumentNullException("action"); - Interlocked.Increment(ref running); - ThreadPool.QueueUserWorkItem(delegate - { - Exception exception = null; - try - { - action(); - } - catch (Exception ex) - { - exception = ex; -#if (DEBUG) - { - throw; - } -#endif - } - OnItemComplete(state, exception); - }); - return this; - } - - - /// Event arguments representing the completion of a parallel action. - public class ParallelEventArgs : EventArgs - { - private readonly object state; - private readonly Exception exception; - internal ParallelEventArgs(object state, Exception exception) - { - this.state = state; - this.exception = exception; - } - - /// The opaque state object that identifies the action (null otherwise). - public object State { get { return state; } } - - /// The exception thrown by the parallel action, or null if it completed without exception. - public Exception Exception { get { return exception; } } - } - } -} diff --git a/Wox/PluginLoader/Plugins.cs b/Wox/PluginLoader/Plugins.cs index ac373b8c93..fce1a82309 100644 --- a/Wox/PluginLoader/Plugins.cs +++ b/Wox/PluginLoader/Plugins.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using Wox.Helper; using Wox.Infrastructure.Storage.UserSettings; using Wox.Plugin; @@ -20,19 +21,16 @@ namespace Wox.PluginLoader plugins.AddRange(new CSharpPluginLoader().LoadPlugin(pluginMetadatas)); plugins.AddRange(new BasePluginLoader().LoadPlugin(pluginMetadatas)); - Forker forker = new Forker(); foreach (PluginPair pluginPair in plugins) { PluginPair pair = pluginPair; - forker.Fork(() => pair.Plugin.Init(new PluginInitContext() + ThreadPool.QueueUserWorkItem(o => pair.Plugin.Init(new PluginInitContext() { CurrentPluginMetadata = pair.Metadata, Proxy = HttpProxy.Instance, API = App.Window })); } - - forker.Join(); } public static List AllPlugins diff --git a/Wox/Wox.csproj b/Wox/Wox.csproj index 68211d8da7..fbf3ae6aee 100644 --- a/Wox/Wox.csproj +++ b/Wox/Wox.csproj @@ -129,7 +129,6 @@ WPFErrorReportingDialog.xaml - From 304561145296c03752243aec49e2b4877f3a7995 Mon Sep 17 00:00:00 2001 From: qianlifeng Date: Mon, 27 Oct 2014 18:22:25 +0800 Subject: [PATCH 13/19] Reduce memory usage. --- .../MFTSearch/MFTSearchRecord.cs | 7 +- .../MFTSearch/MFTSearcher.cs | 70 ++++++--------- .../MFTSearch/MFTSearcherCache.cs | 89 +++++++------------ .../MFTSearch/PInvokeWin32.cs | 2 +- .../MFTSearch/USNChangeReason.cs | 2 +- .../MFTSearch/USNRecord.cs | 3 +- .../MFTSearch/USNRecordType.cs | 8 -- .../MFTSearch/VolumeMonitor.cs | 32 +++---- Plugins/Wox.Plugin.FindFile/Main.cs | 2 +- .../Wox.Plugin.FindFile.csproj | 1 - Wox.Test/MFTSearcherTest.cs | 2 +- 11 files changed, 77 insertions(+), 141 deletions(-) delete mode 100644 Plugins/Wox.Plugin.FindFile/MFTSearch/USNRecordType.cs diff --git a/Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearchRecord.cs b/Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearchRecord.cs index 3186ec97f6..cc3a7ba76c 100644 --- a/Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearchRecord.cs +++ b/Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearchRecord.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Wox.Infrastructure.MFTSearch +namespace Wox.Plugin.FindFile.MFTSearch { public class MFTSearchRecord { diff --git a/Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearcher.cs b/Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearcher.cs index 317468e885..870aef9cd8 100644 --- a/Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearcher.cs +++ b/Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearcher.cs @@ -2,29 +2,24 @@ * 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.Diagnostics; using System.IO; -using System.Linq; using System.Runtime.InteropServices; -using MyEverything; -namespace Wox.Infrastructure.MFTSearch +namespace Wox.Plugin.FindFile.MFTSearch { public class MFTSearcher { private static MFTSearcherCache cache = new MFTSearcherCache(); - public static void IndexVolume(string volume) + private static void IndexVolume(string volume) { - List files; - List folders; - EnumerateVolume(volume, out files, out folders); - cache.AddRecord(volume, files, USNRecordType.File); - cache.AddRecord(volume, folders, USNRecordType.Folder); + cache.CheckHashTableKey(volume); + EnumerateVolume(volume,cache.VolumeRecords[volume]); } public static void IndexAllVolumes() @@ -37,11 +32,7 @@ namespace Wox.Infrastructure.MFTSearch public static long IndexedFileCount { - get { return cache.FileCount; } - } - public static long IndexedFolderCount - { - get { return cache.FolderCount; } + get { return cache.RecordsCount; } } public static List Search(string item) @@ -53,7 +44,7 @@ namespace Wox.Infrastructure.MFTSearch return found.ConvertAll(o => new MFTSearchRecord(o)); } - private static void AddVolumeRootRecord(string volumeName, ref List folders) + private static void AddVolumeRootRecord(string volumeName, Dictionary files) { string rightVolumeName = string.Concat("\\\\.\\", volumeName); rightVolumeName = string.Concat(rightVolumeName, Path.DirectorySeparatorChar); @@ -74,7 +65,7 @@ namespace Wox.Infrastructure.MFTSearch UInt64 fileIndexHigh = (UInt64)fi.FileIndexHigh; UInt64 indexRoot = (fileIndexHigh << 32) | fi.FileIndexLow; - folders.Add(new USNRecord + files.Add(indexRoot,new USNRecord { FRN = indexRoot, Name = volumeName, @@ -96,20 +87,19 @@ namespace Wox.Infrastructure.MFTSearch throw new IOException("Unable to get root frn entry", new Win32Exception(Marshal.GetLastWin32Error())); } } - private static void EnumerateVolume(string volumeName, out List files, out List flds) + + private static void EnumerateVolume(string volumeName, Dictionary files) { - files = new List(); - flds = new List(); IntPtr medBuffer = IntPtr.Zero; IntPtr pVolume = IntPtr.Zero; try { - AddVolumeRootRecord(volumeName, ref flds); + AddVolumeRootRecord(volumeName,files); pVolume = GetVolumeJournalHandle(volumeName); EnableVomuleJournal(pVolume); SetupMFTEnumInBuffer(ref medBuffer, pVolume); - EnumerateFiles(volumeName, pVolume, medBuffer, ref files, ref flds); + EnumerateFiles(volumeName, pVolume, medBuffer, files); } catch (Exception e) { @@ -134,6 +124,7 @@ namespace Wox.Infrastructure.MFTSearch } } } + internal static IntPtr GetVolumeJournalHandle(string volumeName) { string vol = string.Concat("\\\\.\\", volumeName); @@ -210,7 +201,8 @@ namespace Wox.Infrastructure.MFTSearch throw new IOException("DeviceIoControl() returned false", new Win32Exception(Marshal.GetLastWin32Error())); } } - unsafe private static void EnumerateFiles(string volumeName, IntPtr pVolume, IntPtr medBuffer, ref List files, ref List folders) + + unsafe private static void EnumerateFiles(string volumeName, IntPtr pVolume, IntPtr medBuffer, Dictionary files) { IntPtr pData = Marshal.AllocHGlobal(sizeof(UInt64) + 0x10000); PInvokeWin32.ZeroMemory(pData, sizeof(UInt64) + 0x10000); @@ -225,28 +217,14 @@ namespace Wox.Infrastructure.MFTSearch { PInvokeWin32.USN_RECORD usn = new PInvokeWin32.USN_RECORD(pUsnRecord); - if (usn.IsFolder) + files.Add(usn.FRN,new USNRecord { - folders.Add(new USNRecord - { - Name = usn.FileName, - ParentFrn = usn.ParentFRN, - FRN = usn.FRN, - IsFolder = true, - VolumeName = volumeName - }); - } - else - { - files.Add(new USNRecord - { - Name = usn.FileName, - ParentFrn = usn.ParentFRN, - FRN = usn.FRN, - IsFolder = false, - VolumeName = volumeName - }); - } + Name = usn.FileName, + ParentFrn = usn.ParentFRN, + FRN = usn.FRN, + IsFolder = usn.IsFolder, + VolumeName = volumeName + }); pUsnRecord = new IntPtr(pUsnRecord.ToInt32() + usn.RecordLength); outBytesReturned -= usn.RecordLength; @@ -255,14 +233,16 @@ namespace Wox.Infrastructure.MFTSearch } Marshal.FreeHGlobal(pData); } + internal static void FillPath(string volume, USNRecord record, MFTSearcherCache db) { if (record == null) return; - var fdSource = db.GetFolderSource(volume); + 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 fdSource) { if (curRecord.IsVolumeRoot) return; diff --git a/Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearcherCache.cs b/Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearcherCache.cs index 87c04aedde..849279ff48 100644 --- a/Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearcherCache.cs +++ b/Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearcherCache.cs @@ -1,59 +1,45 @@ using System; using System.Collections.Generic; using System.Linq; -using MyEverything; -namespace Wox.Infrastructure.MFTSearch +namespace Wox.Plugin.FindFile.MFTSearch { internal class MFTSearcherCache { - private Dictionary> _volumes_files = new Dictionary>(); - private Dictionary> _volumes_folders = new Dictionary>(); + public Dictionary> VolumeRecords = new Dictionary>(); public MFTSearcherCache() { } public bool ContainsVolume(string volume) { - return _volumes_files.ContainsKey(volume) && _volumes_folders.ContainsKey(volume); + return VolumeRecords.ContainsKey(volume); } - public void AddRecord(string volume, List r, USNRecordType type) + + public void AddRecord(string volume, List r) { - if (type == USNRecordType.File) - { - CheckHashTableKey(_volumes_files, volume); - r.ForEach(x => _volumes_files[volume].Add(x.FRN, x)); - } - else - { - CheckHashTableKey(_volumes_folders, volume); - r.ForEach(x => _volumes_folders[volume].Add(x.FRN, x)); - } + CheckHashTableKey(volume); + r.ForEach(x => VolumeRecords[volume].Add(x.FRN, x)); } - public void AddRecord(string volume, USNRecord record, USNRecordType type) + + public void AddRecord(string volume, USNRecord record) { - if (type == USNRecordType.File) - { - CheckHashTableKey(_volumes_files, volume); - _volumes_files[volume].Add(record.FRN, record); - } - else - { - CheckHashTableKey(_volumes_folders, volume); - _volumes_folders[volume].Add(record.FRN, record); - } + CheckHashTableKey(volume); + VolumeRecords[volume].Add(record.FRN, record); } - private void CheckHashTableKey(Dictionary> hashtable, string key) + + public void CheckHashTableKey(string volume) { - if (!hashtable.ContainsKey(key)) - hashtable.Add(key, new Dictionary()); + if (!VolumeRecords.ContainsKey(volume)) + VolumeRecords.Add(volume, new Dictionary()); } + public bool DeleteRecord(string volume, ulong frn) { bool result = false; - result = DeleteRecordHashTableItem(_volumes_files, volume, frn); - if (!result) result = DeleteRecordHashTableItem(_volumes_folders, volume, frn); + result = DeleteRecordHashTableItem(VolumeRecords, volume, frn); return result; } + private bool DeleteRecordHashTableItem(Dictionary> hashtable, string volume, ulong frn) { if (hashtable.ContainsKey(volume) && hashtable[volume].ContainsKey(frn)) @@ -66,13 +52,12 @@ namespace Wox.Infrastructure.MFTSearch return false; } } - public void UpdateRecord(string volume, USNRecord record, USNRecordType type) + + public void UpdateRecord(string volume, USNRecord record) { - if (type == USNRecordType.File) - RealUpdateRecord(volume, _volumes_files, record); - else - RealUpdateRecord(volume, _volumes_folders, record); + RealUpdateRecord(volume, VolumeRecords, record); } + private bool RealUpdateRecord(string volume, Dictionary> source, USNRecord record) { if (source.ContainsKey(volume) && source[volume].ContainsKey(record.FRN)) @@ -85,48 +70,40 @@ namespace Wox.Infrastructure.MFTSearch return false; } } + public List FindByName(string filename) { filename = filename.ToLower(); - var fileQuery = from filesInVolumeDic in _volumes_files.Values + var fileQuery = from filesInVolumeDic in VolumeRecords.Values from eachFilePair in filesInVolumeDic where eachFilePair.Value.Name.ToLower().Contains(filename) select eachFilePair.Value; - var folderQuery = from fldsInVolumeDic in _volumes_folders.Values - from eachFldPair in fldsInVolumeDic - where eachFldPair.Value.Name.ToLower().Contains(filename) - select eachFldPair.Value; - List result = new List(); result.AddRange(fileQuery); - result.AddRange(folderQuery); return result; } + public USNRecord FindByFrn(string volume, ulong frn) { - if ((!_volumes_files.ContainsKey(volume)) || (!_volumes_folders.ContainsKey(volume))) + if ((!VolumeRecords.ContainsKey(volume))) throw new Exception(string.Format("DB not contain the volume: {0}", volume)); USNRecord result = null; - _volumes_files[volume].TryGetValue(frn, out result); - if (result != null) return result; - _volumes_folders[volume].TryGetValue(frn, out result); + VolumeRecords[volume].TryGetValue(frn, out result); return result; } - public long FileCount + + public long RecordsCount { - get { return _volumes_files.Sum(x => x.Value.Count); } + get { return VolumeRecords.Sum(x => x.Value.Count); } } - public long FolderCount - { - get { return _volumes_folders.Sum(x => x.Value.Count); } - } - public Dictionary GetFolderSource(string volume) + + public Dictionary GetVolumeRecords(string volume) { Dictionary result = null; - _volumes_folders.TryGetValue(volume, out result); + VolumeRecords.TryGetValue(volume, out result); return result; } } diff --git a/Plugins/Wox.Plugin.FindFile/MFTSearch/PInvokeWin32.cs b/Plugins/Wox.Plugin.FindFile/MFTSearch/PInvokeWin32.cs index 6d536c2455..dd5a7735d9 100644 --- a/Plugins/Wox.Plugin.FindFile/MFTSearch/PInvokeWin32.cs +++ b/Plugins/Wox.Plugin.FindFile/MFTSearch/PInvokeWin32.cs @@ -1,7 +1,7 @@ using System; using System.Runtime.InteropServices; -namespace Wox.Infrastructure.MFTSearch { +namespace Wox.Plugin.FindFile.MFTSearch { public class PInvokeWin32 { diff --git a/Plugins/Wox.Plugin.FindFile/MFTSearch/USNChangeReason.cs b/Plugins/Wox.Plugin.FindFile/MFTSearch/USNChangeReason.cs index 61095a6a57..c550208eb0 100644 --- a/Plugins/Wox.Plugin.FindFile/MFTSearch/USNChangeReason.cs +++ b/Plugins/Wox.Plugin.FindFile/MFTSearch/USNChangeReason.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace Wox.Infrastructure.MFTSearch +namespace Wox.Plugin.FindFile.MFTSearch { internal class USNChangeReason { diff --git a/Plugins/Wox.Plugin.FindFile/MFTSearch/USNRecord.cs b/Plugins/Wox.Plugin.FindFile/MFTSearch/USNRecord.cs index 64c0ee05e7..8fbad7b231 100644 --- a/Plugins/Wox.Plugin.FindFile/MFTSearch/USNRecord.cs +++ b/Plugins/Wox.Plugin.FindFile/MFTSearch/USNRecord.cs @@ -1,7 +1,6 @@ using System; -using MyEverything; -namespace Wox.Infrastructure.MFTSearch +namespace Wox.Plugin.FindFile.MFTSearch { public class USNRecord { diff --git a/Plugins/Wox.Plugin.FindFile/MFTSearch/USNRecordType.cs b/Plugins/Wox.Plugin.FindFile/MFTSearch/USNRecordType.cs deleted file mode 100644 index 41c68076cc..0000000000 --- a/Plugins/Wox.Plugin.FindFile/MFTSearch/USNRecordType.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Wox.Infrastructure.MFTSearch -{ - internal enum USNRecordType - { - File, - Folder - } -} \ No newline at end of file diff --git a/Plugins/Wox.Plugin.FindFile/MFTSearch/VolumeMonitor.cs b/Plugins/Wox.Plugin.FindFile/MFTSearch/VolumeMonitor.cs index c65cf866d9..a29aa05afa 100644 --- a/Plugins/Wox.Plugin.FindFile/MFTSearch/VolumeMonitor.cs +++ b/Plugins/Wox.Plugin.FindFile/MFTSearch/VolumeMonitor.cs @@ -1,18 +1,13 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Diagnostics; using System.Runtime.InteropServices; using System.Threading; -using System.Diagnostics; -using System.IO; -using Wox.Infrastructure.MFTSearch; -namespace MyEverything +namespace Wox.Plugin.FindFile.MFTSearch { internal class VolumeMonitor { - public Action RecordAddedEvent; public Action RecordDeletedEvent; public Action RecordRenameEvent; @@ -32,7 +27,7 @@ namespace MyEverything IntPtr pMonitorVolume = MFTSearcher.GetVolumeJournalHandle(volume); uint bytesReturned = 0; PInvokeWin32.USN_JOURNAL_DATA ujd = new PInvokeWin32.USN_JOURNAL_DATA(); - Wox.Infrastructure.MFTSearch.MFTSearcher.QueryUSNJournal(pMonitorVolume, out ujd, out bytesReturned); + MFTSearcher.QueryUSNJournal(pMonitorVolume, out ujd, out bytesReturned); // 构建输入参数 PInvokeWin32.READ_USN_JOURNAL_DATA rujd = new PInvokeWin32.READ_USN_JOURNAL_DATA(); @@ -62,7 +57,7 @@ namespace MyEverything Marshal.StructureToPtr(rujd, prujd, true); Debug.WriteLine(string.Format("\nMoniting on {0}......", volume)); - IntPtr pVolume = Wox.Infrastructure.MFTSearch.MFTSearcher.GetVolumeJournalHandle(volume); + IntPtr pVolume = MFTSearcher.GetVolumeJournalHandle(volume); bool fok = PInvokeWin32.DeviceIoControl(pVolume, PInvokeWin32.FSCTL_READ_USN_JOURNAL, @@ -89,7 +84,7 @@ namespace MyEverything private void ProcessUSN(PInvokeWin32.USN_RECORD usn, string volume, MFTSearcherCache db) { var dbCached = db.FindByFrn(volume, usn.FRN); - Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, dbCached, db); + MFTSearcher.FillPath(volume, dbCached, db); Debug.WriteLine(string.Format("------USN[frn={0}]------", usn.FRN)); Debug.WriteLine(string.Format("FileName={0}, USNChangeReason={1}", usn.FileName, USNChangeReason.ReasonPrettyFormat(usn.Reason))); Debug.WriteLine(string.Format("FileName[Cached]={0}", dbCached == null ? "NoCache" : dbCached.FullPath)); @@ -111,7 +106,7 @@ namespace MyEverything } else { - Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, cached, db); + MFTSearcher.FillPath(volume, cached, db); var deleteok = db.DeleteRecord(volume, usn.FRN); Debug.WriteLine(string.Format(">>>> File {0} deleted {1}.", cached.FullPath, deleteok ? "successful" : "fail")); if (RecordDeletedEvent != null) @@ -122,14 +117,13 @@ namespace MyEverything { USNRecord newRecord = USNRecord.ParseUSN(volume, usn); //string fullpath = newRecord.Name; - //db.FindRecordPath(newRecord, ref fullpath, db.GetFolderSource(volume)); + //db.FindRecordPath(newRecord, ref fullpath, db.GetVolumeRecords(volume)); //newRecord.FullPath = fullpath; var oldRecord = db.FindByFrn(volume, usn.FRN); - Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, oldRecord, db); - Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, newRecord, db); + MFTSearcher.FillPath(volume, oldRecord, db); + MFTSearcher.FillPath(volume, newRecord, db); Debug.WriteLine(string.Format(">>>> RenameFile {0} to {1}", oldRecord.FullPath, newRecord.FullPath)); - db.UpdateRecord(volume, newRecord, - usn.IsFolder ? USNRecordType.Folder : USNRecordType.File); + db.UpdateRecord(volume, newRecord); if (RecordRenameEvent != null) RecordRenameEvent(oldRecord, newRecord); if (newRecord.FullPath.Contains("$RECYCLE.BIN")) { @@ -140,10 +134,10 @@ namespace MyEverything { USNRecord record = USNRecord.ParseUSN(volume, usn); //string fullpath = record.Name; - //db.FindRecordPath(record, ref fullpath, db.GetFolderSource(volume)); + //db.FindRecordPath(record, ref fullpath, db.GetVolumeRecords(volume)); //record.FullPath = fullpath; - db.AddRecord(volume, record, usn.IsFolder ? USNRecordType.Folder : USNRecordType.File); - Wox.Infrastructure.MFTSearch.MFTSearcher.FillPath(volume, record, db); + db.AddRecord(volume, record); + MFTSearcher.FillPath(volume, record, db); Debug.WriteLine(string.Format(">>>> NewFile: {0}", record.FullPath)); if (RecordAddedEvent != null) RecordAddedEvent(record); diff --git a/Plugins/Wox.Plugin.FindFile/Main.cs b/Plugins/Wox.Plugin.FindFile/Main.cs index 5f0518235d..5311191bfc 100644 --- a/Plugins/Wox.Plugin.FindFile/Main.cs +++ b/Plugins/Wox.Plugin.FindFile/Main.cs @@ -6,7 +6,7 @@ using System.Linq; using System.Runtime.Serialization.Formatters.Binary; using System.Text; using Wox.Infrastructure; -using Wox.Infrastructure.MFTSearch; +using Wox.Plugin.FindFile.MFTSearch; namespace Wox.Plugin.FindFile { diff --git a/Plugins/Wox.Plugin.FindFile/Wox.Plugin.FindFile.csproj b/Plugins/Wox.Plugin.FindFile/Wox.Plugin.FindFile.csproj index 3cabda2b97..81ecab8d62 100644 --- a/Plugins/Wox.Plugin.FindFile/Wox.Plugin.FindFile.csproj +++ b/Plugins/Wox.Plugin.FindFile/Wox.Plugin.FindFile.csproj @@ -49,7 +49,6 @@ - diff --git a/Wox.Test/MFTSearcherTest.cs b/Wox.Test/MFTSearcherTest.cs index 6008788a6d..dac4e23dee 100644 --- a/Wox.Test/MFTSearcherTest.cs +++ b/Wox.Test/MFTSearcherTest.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using NUnit.Framework; -using Wox.Infrastructure.MFTSearch; +using Wox.Plugin.FindFile.MFTSearch; namespace Wox.Test { From 9481d04a19138599cdbec6d515514bef83cb3b78 Mon Sep 17 00:00:00 2001 From: qianlifeng Date: Mon, 3 Nov 2014 17:30:48 +0800 Subject: [PATCH 14/19] Add custom context menu setting for findfile plugin and improve the search speed. --- .../FindFileContextMenuStorage.cs | 46 ++++++++++++++++++ Plugins/Wox.Plugin.FindFile/Images/list.png | Bin 0 -> 1775 bytes .../MFTSearch/MFTSearcher.cs | 2 +- .../MFTSearch/MFTSearcherCache.cs | 21 +++++--- Plugins/Wox.Plugin.FindFile/Main.cs | 42 ++++++++++------ .../Wox.Plugin.FindFile.csproj | 37 ++++++++++++++ Plugins/Wox.Plugin.FindFile/packages.config | 6 +++ Plugins/Wox.Plugin.FindFile/setting.xaml | 20 ++++++++ Plugins/Wox.Plugin.FindFile/setting.xaml.cs | 31 ++++++++++++ Wox.Test/MFTSearcherTest.cs | 3 +- 10 files changed, 182 insertions(+), 26 deletions(-) create mode 100644 Plugins/Wox.Plugin.FindFile/FindFileContextMenuStorage.cs create mode 100644 Plugins/Wox.Plugin.FindFile/Images/list.png create mode 100644 Plugins/Wox.Plugin.FindFile/packages.config create mode 100644 Plugins/Wox.Plugin.FindFile/setting.xaml create mode 100644 Plugins/Wox.Plugin.FindFile/setting.xaml.cs diff --git a/Plugins/Wox.Plugin.FindFile/FindFileContextMenuStorage.cs b/Plugins/Wox.Plugin.FindFile/FindFileContextMenuStorage.cs new file mode 100644 index 0000000000..7bb3b61a7f --- /dev/null +++ b/Plugins/Wox.Plugin.FindFile/FindFileContextMenuStorage.cs @@ -0,0 +1,46 @@ +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 + { + [JsonProperty] + public List ContextMenus = new List(); + + protected override string ConfigName + { + get { return "FindFileContextMenu"; } + } + + protected override FindFileContextMenuStorage LoadDefaultConfig() + { + ContextMenus = new List() + { + 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; } + } +} diff --git a/Plugins/Wox.Plugin.FindFile/Images/list.png b/Plugins/Wox.Plugin.FindFile/Images/list.png new file mode 100644 index 0000000000000000000000000000000000000000..ab96e07812b12479ad11a2bd6ed66bf430df671e GIT binary patch literal 1775 zcmVM`18+|b`#y1m9G-elHjPcR9>x1~BPbQk^KAC9rMUzcXAJEn4df7y| zCM%a^xri*caw)W(nNH{8`Tuh1l$K80X=i5fBtOGUXWE|gpZ`1GcV=o+6a|j6+2NSm zu@8VV-#7Sitk+NnE_PkZ>w2433_wTganqQ1tc3A14x7tnwpmp`W-pxS8_hcaH%2de zaq~WoXOf+FIm>`?`b?bM3Xgw=(ZAPw+TR(>IsoW=3vPZ*cANr-%?Td&339m=mU&E3 zq*r>{`##SK1Tiq5;%FoRQV)pFyh2a1!oW3Z|L~8Aw;$9TfbWMdb>g*;r+Po9qYN{E zv54>c!-tdiS{7A6X-gR`Ont`bh4}Pa&6Ez!0l;W6sg5(Qid~eoUH~u)m}~-Y=$Ok< z3U<32tje6zfqj|)B$W!A9m}2%tSlSSeRoY6;HIf>1LZ!9K*j(#9VOtjd%&vGFDoJl zVi-h;<8umt%UMqM9S%1%*Ik54Zwv6kHq5OI0Luqd*Oiu>K%8ISai-Q(*Ohr{Q9iqKM0ye5cME)FB{^Ns;&&p~ z7oZF(bab^o4~@0w=&?#~6OL2x)8M#VNPpamp! z&;ciFx>Vwh$1PqWRiSEz- z`wQ%Zm!Jw2ABVJbadjx6{UpH8gYQ9&?=*NzYc&BL>DuU7T>@KED8^>>uL4p66I|Q8 zLq|%JM3l&rbR1jtkPzs*(@Ul*dTv3Na(E~@?b{O)Dxr~B3o`<5spVmD}=$Umaz=( z>4A95Im>27j0Kk40yA62p5Pu1xLqaC+4>w(-ZqG!Rv(-C3bw;5s`Gr_dU`K0UhZNj zme!Fn7w18$FdLvGNOug_qsHgYz68yU7wCSquNkToFua-`>26%c2^5@huBwS1Bs9TRyJ)*AjR#mSd61<-|D7$2|$uU+=;Bg{qT#kbWe+~ zsF#4cg+)Y8F>hb#MHRBa0K#&Jw5pD0zySu3C&O4iWW~wu*Gz@qx;(^TdS5wsR#4i1 zW-y-ma$34+(s3Pq(jEX}S9*s(#tr#RTzGG-lkSe$nwlEyOB^q!6;PRgtnZWVdQ@3Y zRhBnA77Q&}spgO4`0eVeBSS|j$b69;17xU|=wN;l`u`tKA9FkQ0r*dV0RR!F$#kTn RHR=EW002ovPDHLkV1l4JGhzS$ literal 0 HcmV?d00001 diff --git a/Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearcher.cs b/Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearcher.cs index 870aef9cd8..6ce6f51e69 100644 --- a/Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearcher.cs +++ b/Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearcher.cs @@ -39,7 +39,7 @@ namespace Wox.Plugin.FindFile.MFTSearch { if (string.IsNullOrEmpty(item)) return new List(); - List found = cache.FindByName(item); + List found = cache.FindByName(item,100); found.ForEach(x => FillPath(x.VolumeName, x, cache)); return found.ConvertAll(o => new MFTSearchRecord(o)); } diff --git a/Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearcherCache.cs b/Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearcherCache.cs index 849279ff48..1e1f4e65fe 100644 --- a/Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearcherCache.cs +++ b/Plugins/Wox.Plugin.FindFile/MFTSearch/MFTSearcherCache.cs @@ -71,17 +71,22 @@ namespace Wox.Plugin.FindFile.MFTSearch } } - public List FindByName(string filename) + public List FindByName(string filename, long maxResult = -1) { - filename = filename.ToLower(); - var fileQuery = from filesInVolumeDic in VolumeRecords.Values - from eachFilePair in filesInVolumeDic - where eachFilePair.Value.Name.ToLower().Contains(filename) - select eachFilePair.Value; - List result = new List(); - result.AddRange(fileQuery); + foreach (Dictionary 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; } diff --git a/Plugins/Wox.Plugin.FindFile/Main.cs b/Plugins/Wox.Plugin.FindFile/Main.cs index 5311191bfc..917712b033 100644 --- a/Plugins/Wox.Plugin.FindFile/Main.cs +++ b/Plugins/Wox.Plugin.FindFile/Main.cs @@ -5,12 +5,13 @@ 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 + public class Main : IPlugin, ISettingProvider { private PluginInitContext context; private bool initial = false; @@ -78,27 +79,36 @@ namespace Wox.Plugin.FindFile if (!record.IsFolder) { - contextMenus.Add(new Result() + foreach (ContextMenu contextMenu in FindFileContextMenuStorage.Instance.ContextMenus) { - Title = "Open Containing Folder", - Action = _ => + contextMenus.Add(new Result() { - try + Title = contextMenu.Name, + Action = _ => { - Process.Start("explorer.exe", string.Format("/select, \"{0}\"", record.FullPath)); - } - catch - { - context.API.ShowMsg("Can't open " + record.FullPath, string.Empty, string.Empty); - return false; - } - return true; - }, - IcoPath = "Images/folder.png" - }); + 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(); + } } } diff --git a/Plugins/Wox.Plugin.FindFile/Wox.Plugin.FindFile.csproj b/Plugins/Wox.Plugin.FindFile/Wox.Plugin.FindFile.csproj index 81ecab8d62..0324d2b966 100644 --- a/Plugins/Wox.Plugin.FindFile/Wox.Plugin.FindFile.csproj +++ b/Plugins/Wox.Plugin.FindFile/Wox.Plugin.FindFile.csproj @@ -12,6 +12,8 @@ v3.5 512 + ..\..\ + true true @@ -33,15 +35,36 @@ true + + False + ..\..\packages\log4net.2.0.3\lib\net35-full\log4net.dll + + + False + ..\..\packages\Newtonsoft.Json.6.0.5\lib\net35\Newtonsoft.Json.dll + + + + + ..\..\packages\WPFToolkit.3.5.50211.1\lib\System.Windows.Controls.Input.Toolkit.dll + + + ..\..\packages\WPFToolkit.3.5.50211.1\lib\System.Windows.Controls.Layout.Toolkit.dll + + + + ..\..\packages\WPFToolkit.3.5.50211.1\lib\WPFToolkit.dll + + @@ -51,6 +74,9 @@ + + Setting.xaml + @@ -72,6 +98,9 @@ Always + + Always + Always @@ -80,11 +109,19 @@ + PreserveNewest + + + Designer + MSBuild:Compile + + + + + + + + Debug + AnyCPU + {049490F0-ECD2-4148-9B39-2135EC346EBE} + Library + Properties + Wox.Plugin.PluginManagement + Wox.Plugin.PluginManagement + v3.5 + 512 + ..\..\ + true + + + true + full + false + ..\..\Output\Debug\Plugins\Wox.Plugin.PluginManagement\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\Output\Release\Plugins\Wox.Plugin.PluginManagement\ + TRACE + prompt + 4 + + + + False + ..\..\packages\Newtonsoft.Json.6.0.5\lib\net35\Newtonsoft.Json.dll + + + + + + + + + + + + + + + + + {8451ecdd-2ea4-4966-bb0a-7bbc40138e80} + Wox.Plugin + + + + + + PreserveNewest + + + + + PreserveNewest + + + + + + + + + + + 这台计算机上缺少此项目引用的 NuGet 程序包。启用“NuGet 程序包还原”可下载这些程序包。有关详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。 + + + + \ No newline at end of file diff --git a/Wox.Infrastructure/Properties/AssemblyInfo.cs b/Wox.Infrastructure/Properties/AssemblyInfo.cs index 1bffb5142d..cc1640d88f 100644 --- a/Wox.Infrastructure/Properties/AssemblyInfo.cs +++ b/Wox.Infrastructure/Properties/AssemblyInfo.cs @@ -1,37 +1,37 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// 有关程序集的常规信息通过以下 -// 特性集控制。更改这些特性值可修改 -// 与程序集关联的信息。 -[assembly: AssemblyTitle("Wox.Infrastructure")] -[assembly: AssemblyDescription("https://github.com/qianlifeng/Wox")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Wox.Infrastructure")] -[assembly: AssemblyCopyright("The MIT License (MIT)")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// 将 ComVisible 设置为 false 使此程序集中的类型 -// 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型, -// 则将该类型上的 ComVisible 特性设置为 true。 -[assembly: ComVisible(false)] - -// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID -[assembly: Guid("aee57a31-29e5-4f03-a41f-7917910fe90f")] - -// 程序集的版本信息由下面四个值组成: -// -// 主版本 -// 次版本 -// 生成号 -// 修订号 -// -// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, -// 方法是按如下所示使用“*”: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] -[assembly: log4net.Config.XmlConfigurator(Watch = true)] +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 有关程序集的常规信息通过以下 +// 特性集控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("Wox.Infrastructure")] +[assembly: AssemblyDescription("https://github.com/qianlifeng/Wox")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Wox.Infrastructure")] +[assembly: AssemblyCopyright("The MIT License (MIT)")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 使此程序集中的类型 +// 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型, +// 则将该类型上的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("aee57a31-29e5-4f03-a41f-7917910fe90f")] + +// 程序集的版本信息由下面四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, +// 方法是按如下所示使用“*”: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: log4net.Config.XmlConfigurator(Watch = true)] diff --git a/Wox/Properties/AssemblyInfo.cs b/Wox/Properties/AssemblyInfo.cs index a96441ba2a..0d694b4f83 100644 --- a/Wox/Properties/AssemblyInfo.cs +++ b/Wox/Properties/AssemblyInfo.cs @@ -1,55 +1,55 @@ -using System.Reflection; -using System.Resources; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Windows; - -// 有关程序集的常规信息通过以下 -// 特性集控制。更改这些特性值可修改 -// 与程序集关联的信息。 -[assembly: AssemblyTitle("Wox")] -[assembly: AssemblyDescription("https://github.com/qianlifeng/Wox")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Wox")] -[assembly: AssemblyCopyright("The MIT License (MIT)")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// 将 ComVisible 设置为 false 使此程序集中的类型 -// 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型, -// 则将该类型上的 ComVisible 特性设置为 true。 -[assembly: ComVisible(false)] - -//若要开始生成可本地化的应用程序,请在 -// 中的 .csproj 文件中 -//设置 CultureYouAreCodingWith。例如,如果您在源文件中 -//使用的是美国英语,请将 设置为 en-US。然后取消 -//对以下 NeutralResourceLanguage 特性的注释。更新 -//以下行中的“en-US”以匹配项目文件中的 UICulture 设置。 - -//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] - - -[assembly: ThemeInfo( - ResourceDictionaryLocation.None, //主题特定资源词典所处位置 - //(在页面或应用程序资源词典中 - // 未找到某个资源的情况下使用) - ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置 - //(在页面、应用程序或任何主题特定资源词典中 - // 未找到某个资源的情况下使用) -)] - - -// 程序集的版本信息由下面四个值组成: -// -// 主版本 -// 次版本 -// 生成号 -// 修订号 -// -// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, -// 方法是按如下所示使用“*”: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// 有关程序集的常规信息通过以下 +// 特性集控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("Wox")] +[assembly: AssemblyDescription("https://github.com/qianlifeng/Wox")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Wox")] +[assembly: AssemblyCopyright("The MIT License (MIT)")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 使此程序集中的类型 +// 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型, +// 则将该类型上的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +//若要开始生成可本地化的应用程序,请在 +// 中的 .csproj 文件中 +//设置 CultureYouAreCodingWith。例如,如果您在源文件中 +//使用的是美国英语,请将 设置为 en-US。然后取消 +//对以下 NeutralResourceLanguage 特性的注释。更新 +//以下行中的“en-US”以匹配项目文件中的 UICulture 设置。 + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //主题特定资源词典所处位置 + //(在页面或应用程序资源词典中 + // 未找到某个资源的情况下使用) + ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置 + //(在页面、应用程序或任何主题特定资源词典中 + // 未找到某个资源的情况下使用) +)] + + +// 程序集的版本信息由下面四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, +// 方法是按如下所示使用“*”: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file From 6df3066b49ab51188f63e30643eb0346f1c495cc Mon Sep 17 00:00:00 2001 From: qianlifeng Date: Thu, 27 Nov 2014 12:38:13 +0800 Subject: [PATCH 18/19] Remove XP related description We will not provide support for Wox in XP. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index c44b0e0636..48d072fc05 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,6 @@ Download Download from [release page](https://github.com/qianlifeng/Wox/releases). -* **Windows XP users:** You have to install [.NET Framework 3.5](http://www.microsoft.com/download/details.aspx?id=22) if you have not installed yet. * **Windows 8 users:** You have to [enable the .NET Framework 3.5 in Control Panel](http://msdn.microsoft.com/library/hh506443.aspx). From e928c78749080c70758876e7a7e5147956a56ba0 Mon Sep 17 00:00:00 2001 From: qianlifeng Date: Thu, 27 Nov 2014 13:01:12 +0800 Subject: [PATCH 19/19] Change the default with of Wox. Remove Aero themes. --- Wox/Themes/Aero Dark.xaml | 52 -------------------------------------- Wox/Themes/Aero Light.xaml | 52 -------------------------------------- Wox/Themes/Default.xaml | 2 +- Wox/Wox.csproj | 10 -------- 4 files changed, 1 insertion(+), 115 deletions(-) delete mode 100644 Wox/Themes/Aero Dark.xaml delete mode 100644 Wox/Themes/Aero Light.xaml diff --git a/Wox/Themes/Aero Dark.xaml b/Wox/Themes/Aero Dark.xaml deleted file mode 100644 index 7d83892a10..0000000000 --- a/Wox/Themes/Aero Dark.xaml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - #77ffffff - - - \ No newline at end of file diff --git a/Wox/Themes/Aero Light.xaml b/Wox/Themes/Aero Light.xaml deleted file mode 100644 index d659259003..0000000000 --- a/Wox/Themes/Aero Light.xaml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - #77000000 - - - \ No newline at end of file diff --git a/Wox/Themes/Default.xaml b/Wox/Themes/Default.xaml index 8584b46d38..afaf5bb9ad 100644 --- a/Wox/Themes/Default.xaml +++ b/Wox/Themes/Default.xaml @@ -20,7 +20,7 @@