vba调用Everything 二次开发与 vb.net 类似
Everything是一款基于名称快速定位文件和文件夹的搜索工具, 比Windows自带的搜索要快很多,有关它的详细介绍及使用教程,可以访问这里:
城东书院:高效搜索神器Everything最全使用技巧(一篇看全)及详细功能帮助教程
但EveryThing更强大的地方是提供二次开发的接口(SDK),让使用者进行无限的扩展。
1、将搜索的结果进行二次加工
2、对结果处理输出到网页
3、将数据保存到数据库,共享给其它用户(这样不用每个用户重复搜索)
4、自动化实现某些功能
Everything SDK 通过IPC 提供 DLL 和 Lib 接口
它还提供了将 WM_COPYDATA 用于IPC的方法。
需要EveryThing运行在后台
import ctypes
import datetime
import struct
#defines
EVERYTHING_REQUEST_FILE_NAME = 0x00000001
EVERYTHING_REQUEST_PATH = 0x00000002
EVERYTHING_REQUEST_FULL_PATH_AND_FILE_NAME = 0x00000004
EVERYTHING_REQUEST_EXTENSION = 0x00000008
EVERYTHING_REQUEST_SIZE = 0x00000010
EVERYTHING_REQUEST_DATE_CREATED = 0x00000020
EVERYTHING_REQUEST_DATE_MODIFIED = 0x00000040
EVERYTHING_REQUEST_DATE_ACCESSED = 0x00000080
EVERYTHING_REQUEST_ATTRIBUTES = 0x00000100
EVERYTHING_REQUEST_FILE_LIST_FILE_NAME = 0x00000200
EVERYTHING_REQUEST_RUN_COUNT = 0x00000400
EVERYTHING_REQUEST_DATE_RUN = 0x00000800
EVERYTHING_REQUEST_DATE_RECENTLY_CHANGED = 0x00001000
EVERYTHING_REQUEST_HIGHLIGHTED_FILE_NAME = 0x00002000
EVERYTHING_REQUEST_HIGHLIGHTED_PATH = 0x00004000
EVERYTHING_REQUEST_HIGHLIGHTED_FULL_PATH_AND_FILE_NAME = 0x00008000
#dll imports
everything_dll = ctypes.WinDLL ("C:\\EverythingSDK\\DLL\\Everything32.dll")
everything_dll.Everything_GetResultDateModified.argtypes = [ctypes.c_int,ctypes.POINTER(ctypes.c_ulonglong)]
everything_dll.Everything_GetResultSize.argtypes = [ctypes.c_int,ctypes.POINTER(ctypes.c_ulonglong)]
everything_dll.Everything_GetResultFileNameW.argtypes = [ctypes.c_int]
everything_dll.Everything_GetResultFileNameW.restype = ctypes.c_wchar_p
#setup search
everything_dll.Everything_SetSearchW("test.py")
everything_dll.Everything_SetRequestFlags(EVERYTHING_REQUEST_FILE_NAME | EVERYTHING_REQUEST_PATH | EVERYTHING_REQUEST_SIZE | EVERYTHING_REQUEST_DATE_MODIFIED)
#execute the query
everything_dll.Everything_QueryW(1)
#get the number of results
num_results = everything_dll.Everything_GetNumResults()
#show the number of results
print("Result Count: {}".format(num_results))
#convert a windows FILETIME to a python datetime
#https://stackoverflow.com/questions/39481221/convert-datetime-back-to-windows-64-bit-filetime
WINDOWS_TICKS = int(1/10**-7) # 10,000,000 (100 nanoseconds or .1 microseconds)
WINDOWS_EPOCH = datetime.datetime.strptime('1601-01-01 00:00:00',
'%Y-%m-%d %H:%M:%S')
POSIX_EPOCH = datetime.datetime.strptime('1970-01-01 00:00:00',
'%Y-%m-%d %H:%M:%S')
EPOCH_DIFF = (POSIX_EPOCH - WINDOWS_EPOCH).total_seconds() # 11644473600.0
WINDOWS_TICKS_TO_POSIX_EPOCH = EPOCH_DIFF * WINDOWS_TICKS # 116444736000000000.0
def get_time(filetime):
"""Convert windows filetime winticks to python datetime.datetime."""
winticks = struct.unpack('<Q', filetime)[0]
microsecs = (winticks - WINDOWS_TICKS_TO_POSIX_EPOCH) / WINDOWS_TICKS
return datetime.datetime.fromtimestamp(microsecs)
#create buffers
filename = ctypes.create_unicode_buffer(260)
date_modified_filetime = ctypes.c_ulonglong(1)
file_size = ctypes.c_ulonglong(1)
#show results
for i in range(num_results):
everything_dll.Everything_GetResultFullPathNameW(i,filename,260)
everything_dll.Everything_GetResultDateModified(i,date_modified_filetime)
everything_dll.Everything_GetResultSize(i,file_size)
print("Filename: {}\nDate Modified: {}\nSize: {} bytes\n".format(ctypes.wstring_at(filename),get_time(date_modified_filetime),file_size.value))
form1.Designer.cs
namespace WindowsApplication1
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.listBox1 = new System.Windows.Forms.ListBox();
this.textBox1 = new System.Windows.Forms.TextBox();
this.vScrollBar1 = new System.Windows.Forms.VScrollBar();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(250, 12);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(84, 20);
this.button1.TabIndex = 0;
this.button1.Text = "Search";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// listBox1
//
this.listBox1.FormattingEnabled = true;
this.listBox1.Location = new System.Drawing.Point(12, 38);
this.listBox1.Name = "listBox1";
this.listBox1.Size = new System.Drawing.Size(302, 199);
this.listBox1.TabIndex = 2;
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(12, 12);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(232, 20);
this.textBox1.TabIndex = 3;
//
// vScrollBar1
//
this.vScrollBar1.Location = new System.Drawing.Point(317, 38);
this.vScrollBar1.Name = "vScrollBar1";
this.vScrollBar1.Size = new System.Drawing.Size(17, 199);
this.vScrollBar1.TabIndex = 4;
this.vScrollBar1.Scroll += new System.Windows.Forms.ScrollEventHandler(this.vScrollBar1_Scroll);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(344, 245);
this.Controls.Add(this.vScrollBar1);
this.Controls.Add(this.textBox1);
this.Controls.Add(this.listBox1);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button button1;
private System.Windows.Forms.ListBox listBox1;
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.VScrollBar vScrollBar1;
}
}
form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WindowsApplication1
{
public partial class Form1 : Form
{
const int EVERYTHING_OK = 0;
const int EVERYTHING_ERROR_MEMORY = 1;
const int EVERYTHING_ERROR_IPC = 2;
const int EVERYTHING_ERROR_REGISTERCLASSEX = 3;
const int EVERYTHING_ERROR_CREATEWINDOW = 4;
const int EVERYTHING_ERROR_CREATETHREAD = 5;
const int EVERYTHING_ERROR_INVALIDINDEX = 6;
const int EVERYTHING_ERROR_INVALIDCALL = 7;
const int EVERYTHING_REQUEST_FILE_NAME = 0x00000001;
const int EVERYTHING_REQUEST_PATH = 0x00000002;
const int EVERYTHING_REQUEST_FULL_PATH_AND_FILE_NAME = 0x00000004;
const int EVERYTHING_REQUEST_EXTENSION = 0x00000008;
const int EVERYTHING_REQUEST_SIZE = 0x00000010;
const int EVERYTHING_REQUEST_DATE_CREATED = 0x00000020;
const int EVERYTHING_REQUEST_DATE_MODIFIED = 0x00000040;
const int EVERYTHING_REQUEST_DATE_ACCESSED = 0x00000080;
const int EVERYTHING_REQUEST_ATTRIBUTES = 0x00000100;
const int EVERYTHING_REQUEST_FILE_LIST_FILE_NAME = 0x00000200;
const int EVERYTHING_REQUEST_RUN_COUNT = 0x00000400;
const int EVERYTHING_REQUEST_DATE_RUN = 0x00000800;
const int EVERYTHING_REQUEST_DATE_RECENTLY_CHANGED = 0x00001000;
const int EVERYTHING_REQUEST_HIGHLIGHTED_FILE_NAME = 0x00002000;
const int EVERYTHING_REQUEST_HIGHLIGHTED_PATH = 0x00004000;
const int EVERYTHING_REQUEST_HIGHLIGHTED_FULL_PATH_AND_FILE_NAME = 0x00008000;
const int EVERYTHING_SORT_NAME_ASCENDING = 1;
const int EVERYTHING_SORT_NAME_DESCENDING = 2;
const int EVERYTHING_SORT_PATH_ASCENDING = 3;
const int EVERYTHING_SORT_PATH_DESCENDING = 4;
const int EVERYTHING_SORT_SIZE_ASCENDING = 5;
const int EVERYTHING_SORT_SIZE_DESCENDING = 6;
const int EVERYTHING_SORT_EXTENSION_ASCENDING = 7;
const int EVERYTHING_SORT_EXTENSION_DESCENDING = 8;
const int EVERYTHING_SORT_TYPE_NAME_ASCENDING = 9;
const int EVERYTHING_SORT_TYPE_NAME_DESCENDING = 10;
const int EVERYTHING_SORT_DATE_CREATED_ASCENDING = 11;
const int EVERYTHING_SORT_DATE_CREATED_DESCENDING = 12;
const int EVERYTHING_SORT_DATE_MODIFIED_ASCENDING = 13;
const int EVERYTHING_SORT_DATE_MODIFIED_DESCENDING = 14;
const int EVERYTHING_SORT_ATTRIBUTES_ASCENDING = 15;
const int EVERYTHING_SORT_ATTRIBUTES_DESCENDING = 16;
const int EVERYTHING_SORT_FILE_LIST_FILENAME_ASCENDING = 17;
const int EVERYTHING_SORT_FILE_LIST_FILENAME_DESCENDING = 18;
const int EVERYTHING_SORT_RUN_COUNT_ASCENDING = 19;
const int EVERYTHING_SORT_RUN_COUNT_DESCENDING = 20;
const int EVERYTHING_SORT_DATE_RECENTLY_CHANGED_ASCENDING = 21;
const int EVERYTHING_SORT_DATE_RECENTLY_CHANGED_DESCENDING = 22;
const int EVERYTHING_SORT_DATE_ACCESSED_ASCENDING = 23;
const int EVERYTHING_SORT_DATE_ACCESSED_DESCENDING = 24;
const int EVERYTHING_SORT_DATE_RUN_ASCENDING = 25;
const int EVERYTHING_SORT_DATE_RUN_DESCENDING = 26;
const int EVERYTHING_TARGET_MACHINE_X86 = 1;
const int EVERYTHING_TARGET_MACHINE_X64 = 2;
const int EVERYTHING_TARGET_MACHINE_ARM = 3;
[DllImport("Everything64.dll", CharSet = CharSet.Unicode)]
public static extern UInt32 Everything_SetSearchW(string lpSearchString);
[DllImport("Everything64.dll")]
public static extern void Everything_SetMatchPath(bool bEnable);
[DllImport("Everything64.dll")]
public static extern void Everything_SetMatchCase(bool bEnable);
[DllImport("Everything64.dll")]
public static extern void Everything_SetMatchWholeWord(bool bEnable);
[DllImport("Everything64.dll")]
public static extern void Everything_SetRegex(bool bEnable);
[DllImport("Everything64.dll")]
public static extern void Everything_SetMax(UInt32 dwMax);
[DllImport("Everything64.dll")]
public static extern void Everything_SetOffset(UInt32 dwOffset);
[DllImport("Everything64.dll")]
public static extern bool Everything_GetMatchPath();
[DllImport("Everything64.dll")]
public static extern bool Everything_GetMatchCase();
[DllImport("Everything64.dll")]
public static extern bool Everything_GetMatchWholeWord();
[DllImport("Everything64.dll")]
public static extern bool Everything_GetRegex();
[DllImport("Everything64.dll")]
public static extern UInt32 Everything_GetMax();
[DllImport("Everything64.dll")]
public static extern UInt32 Everything_GetOffset();
[DllImport("Everything64.dll")]
public static extern IntPtr Everything_GetSearchW();
[DllImport("Everything64.dll")]
public static extern UInt32 Everything_GetLastError();
[DllImport("Everything64.dll")]
public static extern bool Everything_QueryW(bool bWait);
[DllImport("Everything64.dll")]
public static extern void Everything_SortResultsByPath();
[DllImport("Everything64.dll")]
public static extern UInt32 Everything_GetNumFileResults();
[DllImport("Everything64.dll")]
public static extern UInt32 Everything_GetNumFolderResults();
[DllImport("Everything64.dll")]
public static extern UInt32 Everything_GetNumResults();
[DllImport("Everything64.dll")]
public static extern UInt32 Everything_GetTotFileResults();
[DllImport("Everything64.dll")]
public static extern UInt32 Everything_GetTotFolderResults();
[DllImport("Everything64.dll")]
public static extern UInt32 Everything_GetTotResults();
[DllImport("Everything64.dll")]
public static extern bool Everything_IsVolumeResult(UInt32 nIndex);
[DllImport("Everything64.dll")]
public static extern bool Everything_IsFolderResult(UInt32 nIndex);
[DllImport("Everything64.dll")]
public static extern bool Everything_IsFileResult(UInt32 nIndex);
[DllImport("Everything64.dll", CharSet = CharSet.Unicode)]
public static extern void Everything_GetResultFullPathName(UInt32 nIndex, StringBuilder lpString, UInt32 nMaxCount);
[DllImport("Everything64.dll")]
public static extern void Everything_Reset();
[DllImport("Everything64.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr Everything_GetResultFileName(UInt32 nIndex);
// Everything 1.4
[DllImport("Everything64.dll")]
public static extern void Everything_SetSort(UInt32 dwSortType);
[DllImport("Everything64.dll")]
public static extern UInt32 Everything_GetSort();
[DllImport("Everything64.dll")]
public static extern UInt32 Everything_GetResultListSort();
[DllImport("Everything64.dll")]
public static extern void Everything_SetRequestFlags(UInt32 dwRequestFlags);
[DllImport("Everything64.dll")]
public static extern UInt32 Everything_GetRequestFlags();
[DllImport("Everything64.dll")]
public static extern UInt32 Everything_GetResultListRequestFlags();
[DllImport("Everything64.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr Everything_GetResultExtension(UInt32 nIndex);
[DllImport("Everything64.dll")]
public static extern bool Everything_GetResultSize(UInt32 nIndex, out long lpFileSize);
[DllImport("Everything64.dll")]
public static extern bool Everything_GetResultDateCreated(UInt32 nIndex, out long lpFileTime);
[DllImport("Everything64.dll")]
public static extern bool Everything_GetResultDateModified(UInt32 nIndex, out long lpFileTime);
[DllImport("Everything64.dll")]
public static extern bool Everything_GetResultDateAccessed(UInt32 nIndex, out long lpFileTime);
[DllImport("Everything64.dll")]
public static extern UInt32 Everything_GetResultAttributes(UInt32 nIndex);
[DllImport("Everything64.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr Everything_GetResultFileListFileName(UInt32 nIndex);
[DllImport("Everything64.dll")]
public static extern UInt32 Everything_GetResultRunCount(UInt32 nIndex);
[DllImport("Everything64.dll")]
public static extern bool Everything_GetResultDateRun(UInt32 nIndex, out long lpFileTime);
[DllImport("Everything64.dll")]
public static extern bool Everything_GetResultDateRecentlyChanged(UInt32 nIndex, out long lpFileTime);
[DllImport("Everything64.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr Everything_GetResultHighlightedFileName(UInt32 nIndex);
[DllImport("Everything64.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr Everything_GetResultHighlightedPath(UInt32 nIndex);
[DllImport("Everything64.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr Everything_GetResultHighlightedFullPathAndFileName(UInt32 nIndex);
[DllImport("Everything64.dll")]
public static extern UInt32 Everything_GetRunCountFromFileName(string lpFileName);
[DllImport("Everything64.dll")]
public static extern bool Everything_SetRunCountFromFileName(string lpFileName, UInt32 dwRunCount);
[DllImport("Everything64.dll")]
public static extern UInt32 Everything_IncRunCountFromFileName(string lpFileName);
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
UInt32 i;
// set the search
Everything_SetSearchW(textBox1.Text);
// use our own custom scrollbar...
// Everything_SetMax(listBox1.ClientRectangle.Height / listBox1.ItemHeight);
// Everything_SetOffset(VerticalScrollBarPosition...);
// request name and size
Everything_SetRequestFlags(EVERYTHING_REQUEST_FILE_NAME | EVERYTHING_REQUEST_PATH | EVERYTHING_REQUEST_DATE_MODIFIED | EVERYTHING_REQUEST_SIZE);
Everything_SetSort(13);
// execute the query
Everything_QueryW(true);
// sort by path
// Everything_SortResultsByPath();
// clear the old list of results
listBox1.Items.Clear();
// set the window title
Text = textBox1.Text + " - " + Everything_GetNumResults() + " Results";
// loop through the results, adding each result to the listbox.
for (i = 0; i < Everything_GetNumResults(); i++)
{
long date_modified;
long size;
Everything_GetResultDateModified(i, out date_modified);
Everything_GetResultSize(i, out size);
// add it to the list box
listBox1.Items.Insert((int)i, "Size: " + size.ToString() + " Date Modified: " + DateTime.FromFileTime(date_modified).Year + "/" + DateTime.FromFileTime(date_modified).Month + "/" + DateTime.FromFileTime(date_modified).Day + " " + DateTime.FromFileTime(date_modified).Hour + ":" + DateTime.FromFileTime(date_modified).Minute.ToString("D2") + " Filename: " + Marshal.PtrToStringUni(Everything_GetResultFileName(i)));
}
}
}
}
form1.vb
Public Class Form1
Public Declare Unicode Function Everything_SetSearchW Lib "d:\dev\everything\sdk\dll\Everything32.dll" (ByVal search As String) As UInt32
Public Declare Unicode Function Everything_SetRequestFlags Lib "d:\dev\everything\sdk\dll\Everything32.dll" (ByVal dwRequestFlags As UInt32) As UInt32
Public Declare Unicode Function Everything_QueryW Lib "d:\dev\everything\sdk\dll\Everything32.dll" (ByVal bWait As Integer) As Integer
Public Declare Unicode Function Everything_GetNumResults Lib "d:\dev\everything\sdk\dll\Everything32.dll" () As UInt32
Public Declare Unicode Function Everything_GetResultFileNameW Lib "d:\dev\everything\sdk\dll\Everything32.dll" (ByVal index As UInt32) As IntPtr
Public Declare Unicode Function Everything_GetLastError Lib "d:\dev\everything\sdk\dll\Everything32.dll" () As UInt32
Public Declare Unicode Function Everything_GetResultFullPathNameW Lib "d:\dev\everything\sdk\dll\Everything32.dll" (ByVal index As UInt32, ByVal buf As System.Text.StringBuilder, ByVal size As UInt32) As UInt32
Public Declare Unicode Function Everything_GetResultSize Lib "d:\dev\everything\sdk\dll\Everything32.dll" (ByVal index As UInt32, ByRef size As UInt64) As Integer
Public Declare Unicode Function Everything_GetResultDateModified Lib "d:\dev\everything\sdk\dll\Everything32.dll" (ByVal index As UInt32, ByRef ft As UInt64) As Integer
Public Const EVERYTHING_REQUEST_FILE_NAME = &H1
Public Const EVERYTHING_REQUEST_PATH = &H00000002
Public Const EVERYTHING_REQUEST_FULL_PATH_AND_FILE_NAME = &H00000004
Public Const EVERYTHING_REQUEST_EXTENSION = &H00000008
Public Const EVERYTHING_REQUEST_SIZE = &H00000010
Public Const EVERYTHING_REQUEST_DATE_CREATED = &H00000020
Public Const EVERYTHING_REQUEST_DATE_MODIFIED = &H00000040
Public Const EVERYTHING_REQUEST_DATE_ACCESSED = &H00000080
Public Const EVERYTHING_REQUEST_ATTRIBUTES = &H00000100
Public Const EVERYTHING_REQUEST_FILE_LIST_FILE_NAME = &H00000200
Public Const EVERYTHING_REQUEST_RUN_COUNT = &H00000400
Public Const EVERYTHING_REQUEST_DATE_RUN = &H00000800
Public Const EVERYTHING_REQUEST_DATE_RECENTLY_CHANGED = &H00001000
Public Const EVERYTHING_REQUEST_HIGHLIGHTED_FILE_NAME = &H00002000
Public Const EVERYTHING_REQUEST_HIGHLIGHTED_PATH = &H00004000
Public Const EVERYTHING_REQUEST_HIGHLIGHTED_FULL_PATH_AND_FILE_NAME = &H00008000
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Everything_SetSearchW(TextBox1.Text)
Everything_SetRequestFlags(EVERYTHING_REQUEST_FILE_NAME Or EVERYTHING_REQUEST_PATH Or EVERYTHING_REQUEST_SIZE Or EVERYTHING_REQUEST_DATE_MODIFIED)
Everything_QueryW(1)
Dim NumResults As UInt32
Dim i As UInt32
Dim filename As New System.Text.StringBuilder(260)
Dim size As UInt64
Dim ftdm As UInt64
Dim DateModified As System.DateTime
NumResults = Everything_GetNumResults()
ListBox1.Items.Clear()
If NumResults > 0 Then
For i = 0 To NumResults - 1
Everything_GetResultFullPathNameW(i, filename, filename.Capacity)
Everything_GetResultSize(i, size)
Everything_GetResultDateModified(i, ftdm)
DateModified = System.DateTime.FromFileTime(ftdm)
' ListBox1.Items.Insert(i, filename.ToString() & " size:" & size & " date:" & DateModified.ToString())
ListBox1.Items.Insert(i, System.Runtime.InteropServices.Marshal.PtrToStringUni(Everything_GetResultFileNameW(i)) & " Size:" & size & " Date Modified:" & DateModified.ToString())
Next
End If
End Sub
End Class
以下是用Access开发的
以下内容摘自:文章 Everything实现原理
everything搜索快 主要原因是利用了NTFS的USNJournal特性,直接从系统的主文件表里读取文件信息。
USNJournal(Update SequenceNumber Journal)也被称作Change Journal。微软在NTFS 5.0(Windows 2000)中引入了USN Journal特性。USN Journal实际上是NTFS分区的一个日志文件,包含了所有对分区操作(文件操作)的记录。操作系统为每一个扇区单独维护一个USN Journal。当扇区的文件有变化时,操作系统会往USN Journal文件中追加一条记录,该记录包含文件名、变化发生的时间、变化的原因等信息,而不包含变化的内容。每一条记录用一个64位数字标识,称作USN(UpdateSequence Number)。微软用每一条记录在日志文件中的偏移作为该记录的USN,这样可以快速地通过USN获取到对应的记录。显而易见,USN是递增的,但是不连续。同时,由于文件名有长有短,每条记录的长度也不固定。在日志文件中,以文件块的形式存储记录。每个文件块大小为4K(USN_PAGE_SIZE),按每条记录100字节计,可以存储30~40条记录。单条记录不允许跨块存储。
USNJournal也有一个64位的ID(Journal ID)。当文件/目录发生变化时,系统除了往USN Journal追加一条日志外,也会更新Journal ID。如果Journal ID没有更新,意味着文件系统没有任何变化。
对NTFS分区,文件信息存储于主文件表(Master File Table,MFT)。MFT是NTFS的核心。主文件表里的每条记录包含文件和目录的所有信息,例如文件名/目录名、路径、大小、属性等。此外,还会存储该文件/目录最后一次变化对应的USN,系统在更新USN Journal时,也会更新这个字段。
小提示:可以用FSUtil.exe获取NTFS信息。FSUtil.exe FSInfoNTFSInfo C:
二、相关API
Windows提供了一系列API供应用程序访问USN Journal及MFT。相关的函数及数据结构罗列如下:
l DeviceIoControl
l FSCTL_QUERY_USN_JOURNAL
l struct USN_JOURNAL_DATA
l FSCTL_ENUM_USN_DATA
l FSCTL_READ_USN_JOURNAL
l struct USN_RECORD
DeviceIoControl如何使用请查阅MSDN。FSCTL_QUERY_USN_JOURNAL和FSCTL_READ_USN_JOURNAL是DeviceIoControl的两个控制码,分别用于读取USN Journal统计信息和USN Journal记录。
USN_JOURNAL_DATA是USN Journal统计信息结构体,定义如下:
typedefstruct {
DWORDLONG UsnJournalID;
USN FirstUsn;
USN NextUsn;
USN LowestValidUsn;
USN MaxUsn;
DWORDLONG MaximumSize;
DWORDLONG AllocationDelta;
}USN_JOURNAL_DATA, *PUSN_JOURNAL_DATA;
Members
Description
UsnJournalID
64-bit unique journal identifier.
FirstUsn
Identifies the first USN actually in the journal. All USNs below this value have been purged.
NextUsn
The USN that will be assigned to the next record appended to the journal.
LowestValidUsn
The lowest USN that is valid for this journal. On some occasions, the lowest USN number may not be zero. All changes with this USN or higher have been reported in the Change Journal.
MaxUsn
The largest USN that will ever be issued in this journal. USNs cannot make use of the entire 64-bit address space-they are limited by the maximum logical size of a sparse file on an NTFS volume. Administrators are responsible for watching this number and deleting the journal if the NextUsn member approaches this value.
MaximumSize
The maximum size in bytes that the journal should use on the volume.
AllocationDelta
Size to grow the journal when needed, and size to purge from the start of the journal if it grows past MaximumSize.
USN Journal文件中,每一项记录的结构如下:
// Version 2.0 USN_RECORD structure
typedef struct {
DWORD RecordLength;
WORD MajorVersion;
WORD MinorVersion;
DWORDLONG FileReferenceNumber;
DWORDLONG ParentFileReferenceNumber;
USN Usn;
LARGE_INTEGER TimeStamp;
DWORD Reason;
DWORD SourceInfo;
DWORD SecurityId;
DWORD FileAttributes;
WORD FileNameLength;
WORD FileNameOffset;
WCHAR FileName[1];
} USN_RECORD, *PUSN_RECORD;
Members
Description
RecordLength
Total length of the record.
MajorVersion
USN Journal’s version.
MinorVersion
FileReferenceNumber
A File Reference Number (FRN) is 64-bit ID that uniquely identifies any file or directory on an NTFS volume.
ParentFileReferenceNumber
Parent’s FRN. It’s always a directory FRN.
Usn
Record’s update sequence number.
TimeStamp
Standard UTC time stamp of this record, in 64-bit format.
Reason
Tells you what sorts of changes have occurred to the file or directory. The Reason member may have one or more of the reason codes set.
SourceInfo
Ignore
SecurityId
FileAttributes
File information.
FileNameLength
FileNameOffset
FileName
三、实现思路
出于项目保密考虑,这里只大致介绍一下实现思路。
首先对每一个分区用FSCTL_ENUM_USN_DATA遍历文件和目录,建立索引;然后用FSCTL_READ_USN_JOURNAL监控系统中的文件变化(可只监听感兴趣的变化,如新建、删除、改名等操作),更新索引;退出程序时将索引保存到文件中,供下次启动时加载。
四、扩展思考
1. 如何由FRN获取文件/目录的路径?
Windows没有提供相应的API来完成这个功能。只有先建立索引树,然后遍历索引树得到完整的路径。
2. 关闭everything之后的文件变化,重启everything之后如何扫描到?
用FSCTL_ENUM_USN_DATA遍历至MFT的最后一项时,会返回USN Journal最后一项的USN。保存下来,下次重启Everything时,从该USN重新开始遍历即可。
3. 怎样从MFT里获取文件的访问时间?
利用控制码FSCTL_GET_NTFS_FILE_RECORD可以获取MFT里的一条记录。使用时需要提供文件的FRN(FileReferenceNumber)。实现细节可参考以下文章
http://www.codeproject.com/Articles/9293/Undelete-a-file-in-NTFS
有网友建议直接使用everything的http接口开发,也是非常不错的建议