介绍

用过3721的人都知道,当我们在地址栏中直接输入一个非网址的中文名字后,3721搜索引擎可以获得我们输入的中文名字进行查找,并提供一个同中文名字匹配的搜索结果列表。3721的这项功能其实并不神秘,我们可以通过IE的地址搜索扩展来实现。所谓搜索扩展就是当用户在IE地址栏中或通过链接连接到一个没有指定协议的字符串(如hubdog.csdn.net,这里没有指定http协议),IE首先会试图确定字符串的真实协议,如果无法确定的话,它就会创建搜索扩展对象,并调用扩展对象的Translate方法来解析地址。我们可以通过自定义的扩展来对网址进行解析处理,返回一些的有特殊意义的结果。

比如我平时查东西都喜欢用Google,但是每次查询都需要连接到Google网站上进行输入。下面就来看如何实现一个搜索扩展,可以当在地址框中输入一个非网址的字符串后,自动调用Google来进行检索。

 

创建COM组件

 

首先创建ActiveX Library,保存为IESearch.dpr,然后再新建一个名为TIEGoogleSearch的COM Object,保存向导生成的文件为CIESearch.pas。对于IE的搜索扩展来说,我们必须实现IURLSearchHook接口,该接口非常简单只有一个Translate方法:

  IURLSearchHook = interface(IUnknown)
    [SID_IURLSearchHook]
    function Translate(lpwszSearchURL: PWideChar; cchBufferSize: DWORD): HResult; stdcall;
  end;

其中lpwszSearchURL参数就是无协议的网址字符串,如果搜索扩展可以解析出该字符串的协议来,则需要在lpwszSearchURL参数中返回解析后的带有完整协议(如http, ftp等)的网址,同时函数返回S_OK标识,之后浏览器将浏览修正后的网址,而不再调用其它的搜索扩展来进行解析。

如果,搜索扩展只能解析出网址字符串的部分内容,则也应该修改lpwszSearchURL参数为部分修正的网址,并返回S_FALSE,则浏览器会继续调用其它的搜索扩展来执行剩余部分的解析。

最后,如果搜索扩展不能解析该字符串,则返回E_FAIL值,这样浏览器会继续调用其它搜索来尝试解析。对于Google搜索扩展来说,只要将lpwszSearchURL修正为Goole搜索网址字符串的网址连接,并返回S_OK就可以了。

下面就是Google搜索组件的实现代码:

type
  TIEGoogleSearch = class(TComObject, IURLSearchHook)
  protected
    function Translate(lpwszSearchURL: PWideChar; cchBufferSize: DWORD): HResult; stdcall;
  end;
function TIEGoogleSearch.Translate(lpwszSearchURL: PWideChar;
  cchBufferSize: DWORD): HResult;
var
  TranslateUrl:string;
begin
  TranslateUrl:=lpwszSearchURL;
TranslateUrl:='http://www.google.com/search?hl=zh-CN&ie=UTF-8&oe=UTF-8&q='+TranslateUrl+'&btnG=Google%E6%90%9C%E7%B4%A2&lr=';
  //返回翻译后的Url
  StringToWideChar(TranslateUrl, lpwszSearchUrl, (Length(TranslateUrl) + 1)
    * 2);
  Result := S_OK;
end;

 

注意,Translate方法中Google搜索网址的构造非常简单,只是为了示意搜索扩展的使用,因此构造的该搜索串只能搜索单个英文(如Delphi, hubdog等),要想能够对中文进行查询,需要对中文字符串进行编码,同时构造的网址也不保证在未来继续有效,至于更加复杂的Google查询网址的构造不是本文的主旨,也就不深入探讨了。构造完网址后,别忘了使用StringToWideChar将网址字符串转换成PWideChar。

 

注册组件

 

前菜单和工具条按钮的注册相比,搜索扩展的注册要简单的多。我们只要在注册表的HKEY_CURRENT_USER\SOFTWARE\Microsoft\Internet Explorer\UrlSearchHooks新加一个扩展的Guid关键字就可以了。下面是实现代码,其中DeleteRegKeyValue和CreateRegKeyValue是删除和创建注册表项的通用方法:

 

procedure DeleteRegKeyValue(Root: DWORD; Key: string; ValueName: string = '');
var
  KeyHandle: HKEY;
begin
  if ValueName = '' then
    RegDeleteKey(Root, PChar(Key));
  if RegOpenKey(Root, PChar(Key), KeyHandle) = ERROR_SUCCESS then
  try
    RegDeleteValue(KeyHandle, PChar(ValueName));
  finally
    RegCloseKey(KeyHandle);
  end;
end;
 
procedure CreateRegKeyValue(Root: DWORD; const Key, ValueName, Value: string);
var
  Handle: HKey;
  Status, Disposition: Integer;
begin
  Status := RegCreateKeyEx(ROOT, PChar(Key), 0, '',
    REG_OPTION_NON_VOLATILE, KEY_READ or KEY_WRITE, nil, Handle,
    @Disposition);
  if Status = 0 then
  begin
    Status := RegSetValueEx(Handle, PChar(ValueName), 0, REG_SZ,
      PChar(Value), Length(Value) + 1);
    RegCloseKey(Handle);
  end;
  if Status <> 0 then
    raise EOleRegistrationError.CreateRes(@SCreateRegKeyError);
 
end;
 
type
  TIEGoogleSearchFactory = class(TComObjectFactory)
  public
    procedure UpdateRegistry(Register: Boolean); override;
  end;
 
{ TIEGoogleSearchFactory }
 
procedure TIEGoogleSearchFactory.UpdateRegistry(Register: Boolean);
begin
  inherited;
  if Register then
    CreateRegKeyValue(HKEY_CURRENT_USER, 'SOFTWARE\Microsoft\Internet Explorer\UrlSearchHooks', GuidToString(ClassID), '')
  else
    DeleteRegKeyValue(HKEY_CURRENT_USER, 'SOFTWARE\Microsoft\Internet Explorer\UrlSearchHooks', GuidToString(ClassID));
end;
 
initialization
  TIEGoogleSearchFactory.Create(ComServer, TIEGoogleSearch, Class_IEGoogleSearch,
    'IEGoogleSearch', '', ciMultiInstance, tmApartment);
end.

 

注册后,在网址中输入hubdog字符串,然后回车后,你会看到下面的搜索结果:

 

注意,在测试本文例子时,一定要先禁止3721,因为3721不管三七二十一总是都会将浏览器引导到它的网站而不把网址传给后面的搜索扩展。

 

总结

 

使用搜索扩展,我们可以对网络搜索过程加以处理和控制,利用这项技术,说不定哪天我们这些程序员中也能有人成立一个3721这样的公司,拿到大把大把的风险投资呢,到时千万别忘了分我一份J。

 

posted on 2009-08-28 22:44  on_road  阅读(308)  评论(0编辑  收藏  举报