mirror of
https://github.com/doublecmd/doublecmd.git
synced 2026-06-21 09:58:13 +00:00
308 lines
9.1 KiB
ObjectPascal
308 lines
9.1 KiB
ObjectPascal
{
|
|
Everything search engine interface via IPC
|
|
|
|
Copyright (C) 2017-2023 Alexander Koblov (alexx2000@mail.ru)
|
|
|
|
Based on Everything command line interface source
|
|
|
|
Copyright (C) 2016 David Carpenter
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
a copy of this software and associated documentation files (the
|
|
"Software"), to deal in the Software without restriction, including
|
|
without limitation the rights to use, copy, modify, merge, publish,
|
|
distribute, sublicense, and/or sell copies of the Software, and to
|
|
permit persons to whom the Software is furnished to do so, subject to
|
|
the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included
|
|
in all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
}
|
|
|
|
unit everything;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, Windows;
|
|
|
|
const
|
|
EVERYTHING_DSX_WNDCLASS = 'EVERYTHING_DSX';
|
|
|
|
const
|
|
COPYDATA_IPCTEST_QUERYCOMPLETEW = 0;
|
|
MSGFLT_RESET = 0;
|
|
MSGFLT_ALLOW = 1;
|
|
MSGFLT_DISALLOW = 2;
|
|
|
|
EVERYTHING_IPC_COPYDATAQUERYW = 2;
|
|
|
|
EVERYTHING_IPC_SEARCH_WNDCLASS = 'EVERYTHING';
|
|
EVERYTHING_IPC_WNDCLASS = 'EVERYTHING_TASKBAR_NOTIFICATION';
|
|
|
|
EVERYTHING_IPC_ALLRESULTS = $FFFFFFFF; // all results
|
|
|
|
EVERYTHING_IPC_FOLDER = $00000001; // The item is a folder. (its a file if not set)
|
|
EVERYTHING_IPC_DRIVE = $00000002; // The folder is a drive. Path will be an empty string.
|
|
|
|
// search flags for querys
|
|
EVERYTHING_IPC_MATCHCASE = $00000001; // match case
|
|
EVERYTHING_IPC_MATCHPATH = $00000004; // include paths in search
|
|
EVERYTHING_IPC_REGEX = $00000008; // enable regex
|
|
|
|
type
|
|
PChangeFilterStruct = ^TChangeFilterStruct;
|
|
TChangeFilterStruct = record
|
|
cbSize: DWORD;
|
|
ExtStatus: DWORD;
|
|
end;
|
|
|
|
{$push}{$packrecords 1}
|
|
|
|
TEVERYTHING_IPC_QUERYW = record
|
|
// the window that will receive the new results.
|
|
reply_hwnd: HWND;
|
|
|
|
// the value to set the dwData member in the COPYDATASTRUCT struct
|
|
// sent by Everything when the query is complete.
|
|
reply_copydata_message: ULONG_PTR;
|
|
|
|
// search flags (see EVERYTHING_MATCHCASE | EVERYTHING_MATCHWHOLEWORD | EVERYTHING_MATCHPATH)
|
|
search_flags: DWORD;
|
|
|
|
// only return results after 'offset' results (0 to return the first result)
|
|
// useful for scrollable lists
|
|
offset: DWORD;
|
|
|
|
// the number of results to return
|
|
// zero to return no results
|
|
// EVERYTHING_IPC_ALLRESULTS to return ALL results
|
|
max_results: DWORD;
|
|
|
|
// null terminated string. arbitrary sized search_string buffer.
|
|
search_string: WCHAR;
|
|
end;
|
|
|
|
PEVERYTHING_IPC_ITEMW = ^TEVERYTHING_IPC_ITEMW;
|
|
TEVERYTHING_IPC_ITEMW = record
|
|
// item flags
|
|
flags: DWORD;
|
|
|
|
// The offset of the filename from the beginning of the list structure.
|
|
// (wchar_t *)((char *)everything_list + everythinglist->name_offset)
|
|
filename_offset: DWORD;
|
|
|
|
// The offset of the filename from the beginning of the list structure.
|
|
// (wchar_t *)((char *)everything_list + everythinglist->path_offset)
|
|
path_offset: DWORD;
|
|
end;
|
|
|
|
PEVERYTHING_IPC_LISTW = ^TEVERYTHING_IPC_LISTW;
|
|
TEVERYTHING_IPC_LISTW = record
|
|
// the total number of folders found.
|
|
totfolders: DWORD;
|
|
|
|
// the total number of files found.
|
|
totfiles: DWORD;
|
|
|
|
// totfolders + totfiles
|
|
totitems: DWORD;
|
|
|
|
// the number of folders available.
|
|
numfolders: DWORD;
|
|
|
|
// the number of files available.
|
|
numfiles: DWORD;
|
|
|
|
// the number of items available.
|
|
numitems: DWORD;
|
|
|
|
// index offset of the first result in the item list.
|
|
offset: DWORD;
|
|
|
|
// arbitrary sized item list.
|
|
// use numitems to determine the actual number of items available.
|
|
items: TEVERYTHING_IPC_ITEMW;
|
|
end;
|
|
|
|
{$pop}
|
|
|
|
type
|
|
TFindData = class
|
|
Cancel: Boolean;
|
|
PluginNumber: Integer;
|
|
FoundCallback: procedure(FileName: PWideChar; UserData: Pointer);
|
|
end;
|
|
|
|
procedure Start(FileMask: String; Flags: Integer; FindData: TFindData);
|
|
|
|
implementation
|
|
|
|
var
|
|
ChangeWindowMessageFilterEx: function(hWnd: HWND; message: UINT; action: DWORD; filter: PChangeFilterStruct): BOOL; stdcall;
|
|
|
|
function SendQuery(hwnd: HWND; num: DWORD; const search_string: UnicodeString; search_flags: integer): Boolean;
|
|
var
|
|
len: Int32;
|
|
size: Int32;
|
|
cds: COPYDATASTRUCT;
|
|
everything_hwnd: HWND;
|
|
query: ^TEVERYTHING_IPC_QUERYW;
|
|
begin
|
|
everything_hwnd:= FindWindow(EVERYTHING_IPC_WNDCLASS, nil);
|
|
if (everything_hwnd = 0) then
|
|
MessageBoxW(0, 'Everything not found!', nil, MB_OK or MB_ICONERROR)
|
|
else begin
|
|
len:= Length(search_string);
|
|
size := SizeOf(TEVERYTHING_IPC_QUERYW) + len * SizeOf(WideChar);
|
|
|
|
query:= GetMem(size);
|
|
if (query = nil) then
|
|
begin
|
|
MessageBoxW(0, PWideChar(UnicodeString(SysErrorMessage(E_OUTOFMEMORY))), nil, MB_OK or MB_ICONERROR);
|
|
Exit(False);
|
|
end;
|
|
try
|
|
query^.offset := 0;
|
|
query^.max_results := num;
|
|
query^.reply_copydata_message := COPYDATA_IPCTEST_QUERYCOMPLETEW;
|
|
query^.search_flags := search_flags;
|
|
query^.reply_hwnd := hwnd;
|
|
StrPLCopy(@query^.search_string, search_string, len);
|
|
|
|
cds.cbData := size;
|
|
cds.dwData := EVERYTHING_IPC_COPYDATAQUERYW;
|
|
cds.lpData := query;
|
|
|
|
if (SendMessage(everything_hwnd, WM_COPYDATA, WPARAM(hwnd), LPARAM(@cds)) <> 0) then
|
|
begin
|
|
Exit(True);
|
|
end;
|
|
finally
|
|
FreeMem(query);
|
|
end;
|
|
end;
|
|
Result:= False;
|
|
end;
|
|
|
|
function EVERYTHING_IPC_ITEMPATHW(AList: PEVERYTHING_IPC_LISTW; Item: PEVERYTHING_IPC_ITEMW): PWideChar; inline;
|
|
begin
|
|
Result:= PWideChar(PByte(AList) + Item^.path_offset);
|
|
end;
|
|
|
|
function EVERYTHING_IPC_ITEMFILENAMEW(AList: PEVERYTHING_IPC_LISTW; Item: PEVERYTHING_IPC_ITEMW): PWideChar; inline;
|
|
begin
|
|
Result:= PWideChar(PByte(AList) + Item^.filename_offset);
|
|
end;
|
|
|
|
procedure ListResults(hWnd: HWND; AList: PEVERYTHING_IPC_LISTW);
|
|
var
|
|
I: DWORD = 0;
|
|
Temp: UnicodeString;
|
|
FileName: PWideChar;
|
|
FindData: TFindData;
|
|
Item: PEVERYTHING_IPC_ITEMW;
|
|
dwOldLong: LONG_PTR absolute FindData;
|
|
begin
|
|
dwOldLong:= GetWindowLongPtr(hWnd, GWL_USERDATA);
|
|
|
|
while I < AList^.numitems do
|
|
begin
|
|
Item:= PEVERYTHING_IPC_ITEMW(@AList^.items) + I;
|
|
|
|
if (Item^.flags and EVERYTHING_IPC_DRIVE) <> 0 then
|
|
begin
|
|
FileName:= EVERYTHING_IPC_ITEMFILENAMEW(AList, Item);
|
|
end
|
|
else
|
|
begin
|
|
Temp:= UnicodeString(EVERYTHING_IPC_ITEMPATHW(AList, Item)) + PathDelim + UnicodeString(EVERYTHING_IPC_ITEMFILENAMEW(AList, Item));
|
|
FileName:= PWideChar(Temp);
|
|
end;
|
|
|
|
if (FindData.Cancel) then Break;
|
|
|
|
FindData.FoundCallback(FileName, FindData);
|
|
Inc(I);
|
|
end;
|
|
FindData.FoundCallback(nil, FindData);
|
|
PostMessage(hWnd, WM_CLOSE, 0, 0);
|
|
end;
|
|
|
|
function WindowProc(hwnd: HWND; msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
|
|
var
|
|
cds: PCopyDataStruct absolute lParam;
|
|
begin
|
|
Result:= 0;
|
|
case msg of
|
|
WM_COPYDATA:
|
|
begin
|
|
if cds^.dwData = COPYDATA_IPCTEST_QUERYCOMPLETEW then
|
|
begin
|
|
ListResults(hwnd, PEVERYTHING_IPC_LISTW(cds^.lpData));
|
|
Exit(1);
|
|
end;
|
|
end;
|
|
WM_CLOSE:
|
|
DestroyWindow(hwnd);
|
|
else
|
|
Result:= DefWindowProc(hwnd, msg, wParam, lParam);
|
|
end;
|
|
end;
|
|
|
|
procedure Start(FileMask: String; Flags: Integer; FindData: TFindData);
|
|
var
|
|
hWnd: Windows.HWND;
|
|
dwNewLong: LONG_PTR absolute FindData;
|
|
begin
|
|
hWnd := CreateWindow(EVERYTHING_DSX_WNDCLASS,
|
|
'', 0, 0, 0, 0, 0, 0, 0, HINSTANCE,nil);
|
|
|
|
if Assigned(ChangeWindowMessageFilterEx) then
|
|
begin
|
|
ChangeWindowMessageFilterEx(hWnd, WM_COPYDATA, MSGFLT_ALLOW, nil);
|
|
end;
|
|
|
|
SetWindowLongPtr(hWnd, GWL_USERDATA, dwNewLong);
|
|
|
|
if not SendQuery(hWnd, EVERYTHING_IPC_ALLRESULTS, UnicodeString(FileMask), Flags) then
|
|
begin
|
|
FindData.FoundCallback(nil, FindData);
|
|
PostMessage(hWnd, WM_CLOSE, 0, 0);
|
|
end;
|
|
end;
|
|
|
|
procedure Initialize;
|
|
var
|
|
hUser32: HMODULE;
|
|
wcex: TWndClassEx;
|
|
begin
|
|
wcex:= Default(TWndClassEx);
|
|
wcex.cbSize:= SizeOf(TWndClassEx);
|
|
wcex.hInstance:= System.HINSTANCE;
|
|
wcex.lpfnWndProc:= @WindowProc;
|
|
wcex.lpszClassName:= EVERYTHING_DSX_WNDCLASS;
|
|
|
|
if (RegisterClassEx(@wcex) = 0) then
|
|
begin
|
|
// WriteLn('failed to register IPCTEST window class');
|
|
end;
|
|
hUser32:= GetModuleHandle(User32);
|
|
Pointer(ChangeWindowMessageFilterEx):= GetProcAddress(hUser32, 'ChangeWindowMessageFilterEx');
|
|
end;
|
|
|
|
initialization
|
|
Initialize;
|
|
|
|
end.
|
|
|