Você está na página 1de 16

https://stackoverflow.

com/questions/26726177/get-a-list-of-all-indexed-files-in-windows-with-
delphi

Get a list of all indexed files in Windows with Delphi

I would like to list all the files that windows has indexed using its Windows Indexing Service.
Specified file extensions are acceptable.

For instance: I am working an a software which presents user media such as photos and
videos. I am currently using the following custom procedure to find the files myself:

function FindAllFiles_Safe(aDirectory, aFilter: string; aIncludeSubDirs: boolean): string;


{$IFDEF DCC}
var TD: TDirectory;
SO: TSearchOption;
DF: TStringDynArray;
i: integer;
sl: TStringList;

MaskArray: TStringDynArray;
Predicate: TDirectory.TFilterPredicate;
{$ENDIF}
begin
{$IFDEF FPC}
result:=FindAllFiles(aDirectory,aFilter,aIncludeSubDirs).text;
{$ENDIF}

{$IFDEF DCC}
MaskArray := SplitString(aFilter, ';');

if aIncludeSubDirs=true then SO:=TSearchOption.soAllDirectories;

Predicate :=
function(const Path: string; const SearchRec: TSearchRec): Boolean
var Mask: string;
begin
for Mask in MaskArray do
if MatchesMask(SearchRec.Name, Mask) then
exit(True);
exit(False);
end;

//DF:=TD.GetFiles(aDirectory, Predicate, SO);


DF:=TD.GetFiles(aDirectory, SO, Predicate);

if length(DF)=0 then exit;

sl:=TStringList.Create;
for i := 0 to length(DF)-1 do sl.Add(DF[i]);

result:=sl.Text;
sl.Free;

{$ENDIF}
end;
Is there a way to access files that Windows has already indexed?
I'd like to take advantage of Windows Indexing Service to quickly retrieve files, rather then
wasting resources if Windows already has done it before.

2 Answers

One of the ways to query the index of the Windows Search is use ADO and the Query Syntax
(AQS) and SQL.
Try this sample code (off course you can improve the SQL sentence to filter and speed up
the results)

{$APPTYPE CONSOLE}

{$R *.res}

uses
ADOInt,
SysUtils,
ActiveX,
ComObj,
Variants;

procedure QuerySystemIndex;
var
Connection : _Connection;
RecordSet: _RecordSet;
v: Variant;
begin;
OleCheck(CoCreateInstance(CLASS_Connection, nil, CLSCTX_ALL, IID__Connection, Connection));
OleCheck(CoCreateInstance(CLASS_RecordSet, nil, CLSCTX_ALL, IID__RecordSet, RecordSet));
Connection.CursorLocation := adUseClient;
Connection.Open('Provider=Search.CollatorDSO;Extended Properties=''Application=Windows'';', '', '',
adConnectUnspecified);
Recordset.Open('SELECT Top 5 System.ItemPathDisplay FROM SYSTEMINDEX', Connection,
adOpenForwardOnly, adLockReadOnly, adCmdText);
Recordset.MoveFirst;
v:='System.ItemPathDisplay';
while not Recordset.EOF do
begin
Writeln(Recordset.Fields.Item[v].Value);
Recordset.MoveNext();
end;
end;

begin
try
CoInitialize(nil);
try
QuerySystemIndex;
finally
CoUninitialize;
end;
except
on E:EOleException do
Writeln(Format('EOleException %s %x', [E.Message,E.ErrorCode]));
on E:Exception do
Writeln(E.Classname, ':', E.Message);
end;
Writeln('Press Enter to exit');
Readln;
end.
You can found alternatives ways to access the Search Index on the MSDN documentation.

There is an API for Windows Search (previously known as Windows Desktop Search).
However, whilst the Windows Search API is undoubtedly enormously powerful, I think for
simply locating files based on file extension (or even other constituent elements in the file
name) the Windows Search API is likely to prove prohibitively complex and provide
negligible benefit, unless you are dealing with a truly extraordinary number of files.

https://stackoverflow.com/questions/3153428/windows-search-4-query-delphi-example

The following web page describes querying Windows Search programmatically:

http://msdn.microsoft.com/en-us/library/aa965362.aspx
Does anyone have examples using Delphi/Pascal?

Examples I have in mind are fairly simple:

1. Search for certain file types.


2. Search for specific text within files.
3. Limit these above searches to a certain path.

1 Answer

Here's one I did a while ago - be aware that it may be out of date:

const

GENERAL_COLUMNS = '"System.Itemname", "System.Size", "System.DateCreated",


"System.ItemDate",' +

'"System.ItemFolderPathDisplay", "System.Search.AutoSummary",
"System.ItemType"';

IMAGE_COLUMNS = '"System.Image.HorizontalSize", "System.Image.VerticalSize", '+

'"System.Image.BitDepth", "System.Image.Compression", '+

'"System.Photo.CameraModel", "System.Photo.DateTaken",
"System.Photo.Flash"';

MUSIC_COLUMNS = '"System.Music.Artist", "System.Music.Genre",


"System.Music.TrackNumber", '+
'"System.Audio.Compression", "System.Audio.SampleRate", '+

'"System.DRM.IsProtected", "System.Music.AlbumTitle",
"System.Rating", '+

'"System.Audio.EncodingBitrate"';

procedure TWDSDataSource.RetrieveDataFromDB;

var

manager : ISearchManager;

catalogManager : ISearchCatalogManager;

queryHelper : ISearchQueryHelper;

wQuery : string;

temp : PWideChar;

sTemp : string;

begin

manager := CoCSearchManager.Create;

if Succeeded(manager.GetCatalog('SystemIndex',catalogManager)) then

begin

if Succeeded(catalogManager.GetQueryHelper(queryHelper)) then

begin

if fMaxResults 0 then

queryHelper.Set_QueryMaxResults(fMaxResults);

queryHelper.Set_QuerySelectColumns(GENERAL_COLUMNS + ',' + MUSIC_COLUMNS + ','


+ IMAGE_COLUMNS);

queryHelper.GenerateSQLFromUserQuery(PWideChar(fQuery),temp);

wQuery := temp;

queryHelper.Get_ConnectionString(temp);

sTemp := temp;

dataset := CreateComObject(CLASS_Recordset) as _Recordset;

dataset.CursorLocation := adUseClient;

dataset.Open(wQuery, stemp, adOpenForwardOnly, adLockReadOnly, adCmdText);


dataset.Set_ActiveConnection(nil);

bDatabaseFailed := false;

end else

bDatabaseFailed := true;

end else

bDatabaseFailed := true;

end;

I think it's all pretty self explanatory, fQuery is the query you want to execute.

Regards Keith

 Thanks for the sample code. What is in your USES clause for this unit? – Greg Bishop Jul 1 '10 at 17:53

https://stackoverflow.com/questions/26726177/get-a-list-of-all-indexed-files-in-windows-with-
delphi

Get a list of all indexed files in Windows with Delphi

I would like to list all the files that windows has indexed using its Windows Indexing Service.
Specified file extensions are acceptable.

For instance: I am working an a software which presents user media such as photos and
videos. I am currently using the following custom procedure to find the files myself:

function FindAllFiles_Safe(aDirectory, aFilter: string; aIncludeSubDirs: boolean): string;


{$IFDEF DCC}
var TD: TDirectory;
SO: TSearchOption;
DF: TStringDynArray;
i: integer;
sl: TStringList;

MaskArray: TStringDynArray;
Predicate: TDirectory.TFilterPredicate;
{$ENDIF}
begin
{$IFDEF FPC}
result:=FindAllFiles(aDirectory,aFilter,aIncludeSubDirs).text;
{$ENDIF}

{$IFDEF DCC}
MaskArray := SplitString(aFilter, ';');
if aIncludeSubDirs=true then SO:=TSearchOption.soAllDirectories;

Predicate :=
function(const Path: string; const SearchRec: TSearchRec): Boolean
var Mask: string;
begin
for Mask in MaskArray do
if MatchesMask(SearchRec.Name, Mask) then
exit(True);
exit(False);
end;

//DF:=TD.GetFiles(aDirectory, Predicate, SO);


DF:=TD.GetFiles(aDirectory, SO, Predicate);

if length(DF)=0 then exit;

sl:=TStringList.Create;
for i := 0 to length(DF)-1 do sl.Add(DF[i]);

result:=sl.Text;
sl.Free;

{$ENDIF}
end;
Is there a way to access files that Windows has already indexed?
I'd like to take advantage of Windows Indexing Service to quickly retrieve files, rather then
wasting resources if Windows already has done it before.

2 Answers

One of the ways to query the index of the Windows Search is use ADO and the Query Syntax
(AQS) and SQL.
Try this sample code (off course you can improve the SQL sentence to filter and speed up
the results)

{$APPTYPE CONSOLE}

{$R *.res}

uses
ADOInt,
SysUtils,
ActiveX,
ComObj,
Variants;

procedure QuerySystemIndex;
var
Connection : _Connection;
RecordSet: _RecordSet;
v: Variant;
begin;
OleCheck(CoCreateInstance(CLASS_Connection, nil, CLSCTX_ALL, IID__Connection, Connection));
OleCheck(CoCreateInstance(CLASS_RecordSet, nil, CLSCTX_ALL, IID__RecordSet, RecordSet));
Connection.CursorLocation := adUseClient;
Connection.Open('Provider=Search.CollatorDSO;Extended Properties=''Application=Windows'';', '', '',
adConnectUnspecified);
Recordset.Open('SELECT Top 5 System.ItemPathDisplay FROM SYSTEMINDEX', Connection,
adOpenForwardOnly, adLockReadOnly, adCmdText);
Recordset.MoveFirst;
v:='System.ItemPathDisplay';
while not Recordset.EOF do
begin
Writeln(Recordset.Fields.Item[v].Value);
Recordset.MoveNext();
end;
end;

begin
try
CoInitialize(nil);
try
QuerySystemIndex;
finally
CoUninitialize;
end;
except
on E:EOleException do
Writeln(Format('EOleException %s %x', [E.Message,E.ErrorCode]));
on E:Exception do
Writeln(E.Classname, ':', E.Message);
end;
Writeln('Press Enter to exit');
Readln;
end.
You can found alternatives ways to access the Search Index on the MSDN documentation.

1down vote
There is an API for Windows Search (previously known as Windows Desktop Search).
However, whilst the Windows Search API is undoubtedly enormously powerful, I think for simply
locating files based on file extension (or even other constituent elements in the file name) the
Windows Search API is likely to prove prohibitively complex and provide negligible benefit, unless
you are dealing with a truly extraordinary number of files.

http://zarko-gajic.iz.hr/full-text-search-functionality-in-delphi-applications-implementation-
idea/

https://stackoverflow.com/questions/25921237/how-to-access-windows-7-start-search-with-
python
How to access Windows 7 start search with Python?

0down vote favorite

I would like some of my scripts to have an access to Windows 7 search with Python.

Possibility to get results I get when i go into Search for programs and files in windows is what I am
interested in.
Few clues are available for me right now. Should I use win32 api?

1 Answer

I believe you can use the following resource to figure out what you want to query:

 http://msdn.microsoft.com/en-us/library/windows/desktop/bb266517%28v=vs.85%29.aspx
If I understand that page correctly, you may be able to use an OLE-DB connection to query the
search index using SQL. I believe you can use pyAdo for this task.
On the other hand, the following link shows a method of calling explorer.exe itself to do the query:
 http://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/1c7349d7-7ea9-4e2b-8061-
1a4d36e4619c/calling-windows-search-programatically-in-windows-
7?forum=windowsdesktopsearchdevelopment
It's example goes like this:

explorer.exe "search-ms://query=ref123"
If you went that route, you could use Python's subprocess module.

How to use Windows Search Service in c#

I'm working on an application, an user can search for files or folders either on the local
computer or on the network. I am using DirectoryInfo.GetDirecotories().

(a) But I also want to add the functionality that windows 7 uses for searching, I believe that
uses indexing. I also saw "Windows Searching Service" on msdn, but I'm not sure which
way is best, querying the indexed catalog or using the search service, any suggestions ? (b)
I was wondering if any one can give me a small example in C# that searches the indexed
catalog.

Thanks in advance.

1 Answer
See the below example:

static void Main(string[] args)


{
var connection = new OleDbConnection(@"Provider=Search.CollatorDSO;Extended
Properties=""Application=Windows""");

// File name search (case insensitive), also searches sub directories


var query1 = @"SELECT System.ItemName FROM SystemIndex " +
@"WHERE scope ='file:C:/' AND System.ItemName LIKE '%Test%'";

// File name search (case insensitive), does not search sub directories
var query2 = @"SELECT System.ItemName FROM SystemIndex " +
@"WHERE directory = 'file:C:/' AND System.ItemName LIKE '%Test%' ";

// Folder name search (case insensitive)


var query3 = @"SELECT System.ItemName FROM SystemIndex " +
@"WHERE scope = 'file:C:/' AND System.ItemType = 'Directory' AND System.Itemname LIKE
'%Test%' ";

// Folder name search (case insensitive), does not search sub directories
var query4 = @"SELECT System.ItemName FROM SystemIndex " +
@"WHERE directory = 'file:C:/' AND System.ItemType = 'Directory' AND System.Itemname LIKE
'%Test%' ";

connection.Open();

var command = new OleDbCommand(query4, connection);

using (var r = command.ExecuteReader())


{
while (r.Read())
{
Console.WriteLine(r[0]);
}
}

connection.Close();

Console.ReadKey();
}
It's using OLE DB api to connect to the indexer service and use a SQL-like syntax to
search System objects in its SystemIndex table. You have 4 example queries which do
different things. All example queries will search in the c:\ folder for items that
contain Test in their names.
You can search for files, folders mails and possibly other media (depending on OS) on local
or other machines. From what I have researched network drives are not supported since
they can't be indexed but you can connect to other machines for which I assume RPC is
used in the background which means you have to supply network credentials using a
different api (e.g. System.Net).

Note that for any of this to work your indexing must be fully operational on the target
machine (which it is by default). The api is corresponding to whatever you specify in your
Indexing Options. This is the screen in question:
The full list of properties for the System object can be found here: Property System Reference.
This object contains things such as URL, Path, Name, Date etc.
More interesting examples using different predicates (e.g. scope and directory) can be
found here: Windows Vista Search Syntax. There is also a crude MSDN
documentation: SCOPE and DIRECTORY Predicates
I recommend you check out the documentation because you can do a lot of stuff with this
api.

Get a list of all indexed files in Windows with Delphi

I would like to list all the files that windows has indexed using its Windows Indexing Service.
Specified file extensions are acceptable.

For instance: I am working an a software which presents user media such as photos and
videos. I am currently using the following custom procedure to find the files myself:

function FindAllFiles_Safe(aDirectory, aFilter: string; aIncludeSubDirs: boolean): string;


{$IFDEF DCC}
var TD: TDirectory;
SO: TSearchOption;
DF: TStringDynArray;
i: integer;
sl: TStringList;

MaskArray: TStringDynArray;
Predicate: TDirectory.TFilterPredicate;
{$ENDIF}
begin
{$IFDEF FPC}
result:=FindAllFiles(aDirectory,aFilter,aIncludeSubDirs).text;
{$ENDIF}

{$IFDEF DCC}
MaskArray := SplitString(aFilter, ';');

if aIncludeSubDirs=true then SO:=TSearchOption.soAllDirectories;

Predicate :=
function(const Path: string; const SearchRec: TSearchRec): Boolean
var Mask: string;
begin
for Mask in MaskArray do
if MatchesMask(SearchRec.Name, Mask) then
exit(True);
exit(False);
end;

//DF:=TD.GetFiles(aDirectory, Predicate, SO);


DF:=TD.GetFiles(aDirectory, SO, Predicate);

if length(DF)=0 then exit;

sl:=TStringList.Create;
for i := 0 to length(DF)-1 do sl.Add(DF[i]);

result:=sl.Text;
sl.Free;

{$ENDIF}
end;
Is there a way to access files that Windows has already indexed?
I'd like to take advantage of Windows Indexing Service to quickly retrieve files, rather then
wasting resources if Windows already has done it before.

2 Answers

One of the ways to query the index of the Windows Search is use ADO and the Query Syntax
(AQS) and SQL.
Try this sample code (off course you can improve the SQL sentence to filter and speed up
the results)

{$APPTYPE CONSOLE}

{$R *.res}
uses
ADOInt,
SysUtils,
ActiveX,
ComObj,
Variants;

procedure QuerySystemIndex;
var
Connection : _Connection;
RecordSet: _RecordSet;
v: Variant;
begin;
OleCheck(CoCreateInstance(CLASS_Connection, nil, CLSCTX_ALL, IID__Connection, Connection));
OleCheck(CoCreateInstance(CLASS_RecordSet, nil, CLSCTX_ALL, IID__RecordSet, RecordSet));
Connection.CursorLocation := adUseClient;
Connection.Open('Provider=Search.CollatorDSO;Extended Properties=''Application=Windows'';', '', '',
adConnectUnspecified);
Recordset.Open('SELECT Top 5 System.ItemPathDisplay FROM SYSTEMINDEX', Connection,
adOpenForwardOnly, adLockReadOnly, adCmdText);
Recordset.MoveFirst;
v:='System.ItemPathDisplay';
while not Recordset.EOF do
begin
Writeln(Recordset.Fields.Item[v].Value);
Recordset.MoveNext();
end;
end;

begin
try
CoInitialize(nil);
try
QuerySystemIndex;
finally
CoUninitialize;
end;
except
on E:EOleException do
Writeln(Format('EOleException %s %x', [E.Message,E.ErrorCode]));
on E:Exception do
Writeln(E.Classname, ':', E.Message);
end;
Writeln('Press Enter to exit');
Readln;
end.
You can found alternatives ways to access the Search Index on the MSDN documentation.

There is an API for Windows Search (previously known as Windows Desktop Search).
However, whilst the Windows Search API is undoubtedly enormously powerful, I think for
simply locating files based on file extension (or even other constituent elements in the file
name) the Windows Search API is likely to prove prohibitively complex and provide
negligible benefit, unless you are dealing with a truly extraordinary number of files.
https://msdn.microsoft.com/en-us/library/aa965362(VS.85).aspx

Querying the Index


Programmatically
https://msdn.microsoft.com/en-us/library/windows/desktop/bb266517%28v=vs.85%29.aspx

Using SQL and AQS


Approaches to Query the Index
https://msdn.microsoft.com/en-us/library/ff684395%28v=vs.85%29.aspx

Shell Interfaces
https://msdn.microsoft.com/en-us/library/bb774328(v=vs.85).aspx

PRIVATE-STORM
http://private-storm.de/2009/07/04/windows-search-project/

DisableBackoff
There is no need to just live with it. Here is how you can make search indexing run at full speed:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Search\Gathering
Manager
DisableBackoff = 1
I found the answer here:
http://www.neowin.net/forum/topic/613825-can-i-force-search-indexing-to-high-priority/

Can I force full speed to the indexing service of Windows?

There is a setting in the group policy for the computer, so you don't have to manually edit
the registry.

 Open run dialog: Win + R


 Type "gpedit.msc" and select OK
 Browse to Computer Configuration\Administrative Templates\Windows Components\Search
 Select "Disable indexer backoff", and set it to Enabled.
This setting will not take effect until the service is restarted. The easiest way is to just reboot
your computer, but you can do it live

 Open run dialog: Win + R


 Type "services.msc" and select OK
 Scroll to "Windows Search"
 Right click and select "Restart"

https://superuser.com/questions/234211/can-i-force-full-speed-to-the-indexing-service-of-
windows

https://www.youtube.com/watch?v=PrS7YIyOogE

https://office-watch.com/2016/force-windows-indexing-to-run-faster/

Você também pode gostar