Windows Search Engine

Implementing Shell Search Handler using Delphi

The Shell supports several search utilities that allow users to locate namespace objects such as files or printers. You can create a custom search engine and make it available to users by implementing and registering a search handler.

Users have two ways to select a search engine. The first way is from the Start menu. With systems earlier than Microsoft Windows 2000, selecting the Find command on the Start menu displays a submenu of the available search engines. With Windows 2000 and later, the Start menu's Find command is renamed Search.

Users can also launch a search from Windows Explorer. On systems earlier than Windows 2000, they click the Find command on the Tools menu to display essentially the same menu as the one associated with the Start menu. However, Windows Explorer for Windows 2000 handles search engines in a very different way. Instead of handling search engines as a submenu of the Tools menu, there is now a Search button on the toolbar. Clicking this button opens the Explorer bar's Search pane

The following example shows how to implement Shell Search Handler using Borland Delphi. As any Shell Extension it must be implemented as in-process Component Object Model (COM) object. It must be assigned a globally unique identifier (GUID) and registered using regsvr32.exe

library SearchHandler;



uses

ComServ,

HandlerM in 'HandlerM.pas';



{$R *.RES}



exports

DllGetClassObject,

DllCanUnloadNow,

DllRegisterServer,

DllUnregisterServer;



begin

end
.





{*****************************************************************************

Name : TSearchEngine

Author : Perevoznyk Serhiy

Description : Shell Search Handler

*****************************************************************************}



unit HandlerM;



interface



uses

Windows, ActiveX, ComObj, ShlObj, Dialogs;



type

TSearchEngine = class(TComObject, IShellExtInit, IContextMenu)

protected

{ IShellExtInit }

function IShellExtInit.Initialize = SEIInitialize; // Avoid compiler warning

function SEIInitialize(pidlFolder: PItemIDList; lpdobj: IDataObject;

hKeyProgID: HKEY): HResult; stdcall;

{ IContextMenu }

function QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst, idCmdLast,

uFlags: UINT): HResult; stdcall;

function InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult; stdcall;

function GetCommandString(idCmd, uType: UINT; pwReserved: PUINT;

pszName: LPSTR; cchMax: UINT): HResult; stdcall;

end;



const

Class_SearchEngine: TGUID = '{B8091A44-1F5E-4EFE-8F26-194ACBDE4465}';



implementation



uses
ComServ, SysUtils, ShellApi, Registry;



function TSearchEngine.SEIInitialize(pidlFolder: PItemIDList; lpdobj: IDataObject;

hKeyProgID: HKEY): HResult;

begin

Result := NOERROR;

end;



function TSearchEngine.QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst,

idCmdLast, uFlags: UINT): HResult;

begin


Result := 0;

end;





function TSearchEngine.InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult;

begin

//enter your code here

ShowMessage('Executed');

Result := NOERROR;

end;



function TSearchEngine.GetCommandString(idCmd, uType: UINT; pwReserved: PUINT;

pszName: LPSTR; cchMax: UINT): HRESULT;

begin

if
(idCmd = 0) then

begin

if
(uType = GCS_HELPTEXT) then

// return help string for menu item

StrCopy(pszName, 'Find document');

Result := NOERROR;

end

else

Result := E_INVALIDARG;

end;



type

TSearchEngineFactory = class(TComObjectFactory)

public

procedure
UpdateRegistry(Register: Boolean); override;

end;





procedure CreateKey(const Key, ValueName, Value: string);

var

Handle: HKey;

Status, Disposition: Integer;

begin

Status := RegCreateKeyEx(HKEY_LOCAL_MACHINE, PChar(Key), 0, '',

REG_OPTION_NON_VOLATILE, KEY_READ or KEY_WRITE, nil, Handle,

@Disposition);

if Status = 0 then

begin

RegSetValueEx(Handle, PChar(ValueName), 0, REG_SZ,

PChar(Value), Length(Value) + 1);

RegCloseKey(Handle);

end;

end;





procedure DeleteKey(const Key: string);

begin

RegDeleteKey(HKEY_LOCAL_MACHINE, PChar(Key));

end;



procedure TSearchEngineFactory.UpdateRegistry(Register: Boolean);

var

ClassID: string;

FileName: array [0..MAX_PATH] of Char;

begin

if Register then

begin

inherited
UpdateRegistry(Register);

ClassID := GUIDToString(Class_SearchEngine);

GetModuleFileName(HInstance, FileName, SizeOf(FileName));

CreateKey('Software\Microsoft\Windows\CurrentVersion\Explorer\' +
'FindExtensions\Static\SearchHandler'
, '', ClassID);

CreateKey('Software\Microsoft\Windows\CurrentVersion\Explorer\' +
'FindExtensions\Static\SearchHandler\0'
, '', 'Using Delphi...');

CreateKey('Software\Microsoft\Windows\CurrentVersion\Explorer\' +
'FindExtensions\Static\SearchHandler\0\DefaultIcon'
, '', FileName + ',0');

end

else

begin

DeleteKey('Software\Microsoft\Windows\CurrentVersion\Explorer\' +
'
FindExtensions\Static\SearchHandler\0\DefaultIcon');

DeleteKey('Software\Microsoft\Windows\CurrentVersion\Explorer\' +
'FindExtensions\Static\SearchHandler\0'
);

DeleteKey('Software\Microsoft\Windows\CurrentVersion\Explorer\' +
'FindExtensions\Static\SearchHandler'
);

inherited UpdateRegistry(Register);

end;

end;



initialization

TSearchEngineFactory.Create(ComServer, TSearchEngine, Class_SearchEngine,

'', 'Delphi Search Engine Example', ciMultiInstance,

tmApartment);

end.

 

Share this article!

Follow us!

Find more helpful articles: