Implementing Shell Search Handler in Delphi

'

How to write a Shell Search by Implementing IShellExtInit, IContextMenu

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. The following illustration shows the Search button on a Windows XP system.

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.

This tutorial was kindly provided by serge perevoznyk, thank you Serge


Google
Web www.Delphi-Central.com
Delphi Central - Delphi Programming Tutorials, Hints and Tips