mirror of
https://github.com/doublecmd/doublecmd.git
synced 2026-06-21 09:58:13 +00:00
307 lines
8.9 KiB
ObjectPascal
307 lines
8.9 KiB
ObjectPascal
{
|
|
Everything search engine interface via IPC
|
|
|
|
Copyright (C) 2017 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
|
|
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_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
|
|
TFoundCallback = procedure(FileName: PWideChar);
|
|
|
|
var
|
|
ChangeWindowMessageFilterEx: function(hWnd: HWND; message: UINT; action: DWORD; filter: PChangeFilterStruct): BOOL; stdcall;
|
|
|
|
procedure Start(FileMask: String; Flags: Integer; pr: TFoundCallback);
|
|
|
|
implementation
|
|
|
|
function SendQuery(hwnd: HWND; num: DWORD; search_string: PWideChar; search_flags: integer): Boolean;
|
|
var
|
|
query: ^TEVERYTHING_IPC_QUERYW;
|
|
len: Int32;
|
|
size: Int32;
|
|
everything_hwnd: HWND;
|
|
cds: COPYDATASTRUCT;
|
|
begin
|
|
everything_hwnd:= FindWindow(EVERYTHING_IPC_WNDCLASS, nil);
|
|
if (everything_hwnd <> 0) then
|
|
begin
|
|
len := StrLen(search_string);
|
|
|
|
size := SizeOf(TEVERYTHING_IPC_QUERYW) - SizeOf(WideChar) + len * SizeOf(WideChar) + SizeOf(WideChar);
|
|
|
|
query := GetMem(size);
|
|
if Assigned(query) then
|
|
begin
|
|
query^.offset := 0;
|
|
query^.max_results := num;
|
|
query^.reply_copydata_message := COPYDATA_IPCTEST_QUERYCOMPLETEW;
|
|
query^.search_flags := search_flags;
|
|
query^.reply_hwnd := hwnd;
|
|
StrLCopy(@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
|
|
//HeapFree(GetProcessHeap(),0,query);
|
|
|
|
//return 1;
|
|
REsult:= True;
|
|
end
|
|
else
|
|
begin
|
|
//write(L"Everything IPC service not running.\n");
|
|
end;
|
|
|
|
FreeMem(query);
|
|
end;
|
|
end;
|
|
|
|
Result:= False;
|
|
end;
|
|
|
|
function EVERYTHING_IPC_ITEMPATHW(list: PEVERYTHING_IPC_LISTW; item: PEVERYTHING_IPC_ITEMW): PWideChar;
|
|
begin
|
|
Result:= PWideChar(PByte(list) + item^.path_offset);
|
|
end;
|
|
|
|
function EVERYTHING_IPC_ITEMFILENAMEW(list: PEVERYTHING_IPC_LISTW; item: PEVERYTHING_IPC_ITEMW): PWideChar;
|
|
begin
|
|
Result:= PWideChar(PByte(list) + item^.filename_offset);
|
|
end;
|
|
|
|
procedure listresultsW(hwnd2: HWND; list: PEVERYTHING_IPC_LISTW);
|
|
var
|
|
I: Integer;
|
|
Item: PEVERYTHING_IPC_ITEMW;
|
|
CallB: TFoundCallback;
|
|
Result: PWideChar;
|
|
Res: UnicodeString;
|
|
begin
|
|
CallB:= TFoundCallback(GetWindowLongPtr(hwnd2, GWL_USERDATA));
|
|
|
|
for i:=0 to list^.numitems - 1 do
|
|
begin
|
|
Item:= PEVERYTHING_IPC_ITEMW(@list^.items) + i;
|
|
if (Item^.flags and EVERYTHING_IPC_DRIVE) <> 0 then
|
|
begin
|
|
//WriteLn(WideString(EVERYTHING_IPC_ITEMFILENAMEW(list, Item)));
|
|
Result:= EVERYTHING_IPC_ITEMFILENAMEW(list, Item);
|
|
end
|
|
else
|
|
begin
|
|
//WriteLn(WideString(EVERYTHING_IPC_ITEMPATHW(list, Item)));
|
|
|
|
//WriteLn(WideString(EVERYTHING_IPC_ITEMFILENAMEW(list, Item)));
|
|
Res:= UnicodeString(EVERYTHING_IPC_ITEMPATHW(list, Item)) + PathDelim + UnicodeString(EVERYTHING_IPC_ITEMFILENAMEW(list, Item));
|
|
Result:= PWideChar(Res);//EVERYTHING_IPC_ITEMFILENAMEW(list, Item);
|
|
end;
|
|
CallB(REsult);
|
|
end;
|
|
CallB(nil);
|
|
PostQuitMessage(0);
|
|
end;
|
|
|
|
function window_proc(hwnd: HWND; msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
|
|
var
|
|
cds: PCOPYDATASTRUCT;
|
|
begin
|
|
case msg of
|
|
WM_COPYDATA:
|
|
begin
|
|
cds := PCOPYDATASTRUCT(lParam);
|
|
if cds^.dwData = COPYDATA_IPCTEST_QUERYCOMPLETEW then
|
|
begin
|
|
listresultsW(hwnd, PEVERYTHING_IPC_LISTW(cds^.lpData));
|
|
Exit(1);
|
|
end;
|
|
end;
|
|
end;
|
|
Result:= DefWindowProc(hwnd, msg, wParam, lParam);
|
|
end;
|
|
|
|
procedure Start(FileMask: String; Flags: Integer; pr: TFoundCallback);
|
|
var
|
|
wcex: WNDCLASSEX;
|
|
hwnd2: HWND;
|
|
HH: HMODULE;
|
|
lpMsg: TMsg;
|
|
begin
|
|
ZeroMemory(@wcex, SizeOf(wcex));
|
|
wcex.cbSize := sizeof(wcex);
|
|
wcex.hInstance := System.HINSTANCE;;
|
|
wcex.lpfnWndProc := @window_proc;
|
|
wcex.lpszClassName := 'IPCTEST';
|
|
|
|
if (RegisterClassEx(@wcex) = 0) then
|
|
begin
|
|
WriteLn('failed to register IPCTEST window class');
|
|
|
|
|
|
end;
|
|
|
|
hwnd2 := CreateWindow(
|
|
'IPCTEST',
|
|
'',
|
|
0,
|
|
0,0,0,0,
|
|
0,0,HINSTANCE,nil);
|
|
|
|
HH:= LoadLibrary('user32.dll');
|
|
Pointer(ChangeWindowMessageFilterEx) := GetProcAddress(HH, 'ChangeWindowMessageFilterEx');
|
|
ChangeWindowMessageFilterEx(hwnd2, WM_COPYDATA, MSGFLT_ALLOW, nil);
|
|
|
|
SetWindowLongPtr(hwnd2, GWL_USERDATA, LONG_PTR(pr));
|
|
|
|
sendquery(hwnd2,EVERYTHING_IPC_ALLRESULTS,PWideChar(WideString(FileMask)), Flags);
|
|
while (True) do
|
|
begin
|
|
if (PeekMessage(lpmsg, 0,0,0,0)) then
|
|
begin
|
|
if not GetMessage(lpmsg,0,0,0) then Exit;
|
|
|
|
// let windows handle it.
|
|
TranslateMessage(lpmsg);
|
|
DispatchMessage(lpmsg);
|
|
end
|
|
else
|
|
begin
|
|
WaitMessage();
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
end.
|
|
|