Delphi知识中心
www.delphi.ee
提供Delphi技术知识
与Delphi程序员共同进步


在线服务QQ:99923144 随时恭候您的光临
首页 基础知识 WIN系统 组件使用 组件开发 数据库 ACTIVEX 多媒体技术 网络技术 关于
文章类别:ACTIVEX    你尚未登陆,会员功能无法使用,请从 网站首页 登陆。
  文件飞跃提示扩展  
 
文件飞跃提示扩展

我相信几乎每一台电脑上都会安装Winzip的,在最新的Winzip 8.0里它增加了一项特殊功能,就是当你的鼠标在资源管理器中的Zip文件停留几秒钟后,会显示一个飞跃提示的信息告诉你zip文件里有多少个压缩文件,如图2.3所示。其实Winzip使用的就是文件飞跃提示扩展技术(不过前提条件是你安装了IE4或以上版本的浏览器)。

  实现这个扩展必须编写一个实现IPersistFile和IQueryInfo接口(除了标准的Iunknown接口外)进程内的COM Server。IPersistFile接口使当前文件名可以被传递到COM对象,而IQueryInfo则把对应文件的信息反馈回外壳,然后外壳负责显示信息。这实际上是一个非常简单的过程,但奇怪的是甚至在最新的Windows SDK里也没有记载。

  下面是建立一个基本的Infotip扩展的详细步骤。这个扩展可以获取mp3歌曲文件的ID3-Tag中的信息,并显示出来。首先,创建一个新的 ActiveX library (File |New |ActiveX|Active Library)并添加IPersistFile和IQueryInfo接口,得到下列文件:

  Define a new type as below:

   TInfoTip = class(TComObject, IQueryInfo, IPersistFile)

   private

    fName : string;

   protected

    { IQueryInfo }

    function GetInfoTip(dwFlags: DWORD; var ppwszTip: PWideChar): HResult; stdcall;

    function GetInfoFlags(out pdwFlags: DWORD): HResult; stdcall;

    { IPersistFile }

    function IsDirty: HResult; stdcall;

    function Load(pszFileName: POleStr; dwMode: Longint): HResult; stdcall;

    function Save(pszFileName: POleStr; fRemember: BOOL): HResult; stdcall;

    function SaveCompleted(pszFileName: POleStr): HResult; stdcall;

    function GetCurFile(out pszFileName: POleStr): HResult; stdcall;

    function GetClassID(out classID: TCLSID): HResult; stdcall;

   end;

   implementation

   uses ComServ;

  对于这个扩展,IPersistFile唯一重要的方法是Load,至于IpersistFile其他的方法只要返回E_NOTIMPL就可以了,所以IpersistFile的其他方法都实现为类似下面的方法:

  function TInfoTip.Save(pszFileName: POleStr; fRemember: BOOL): HResult;

  begin

   Result := E_NOTIMPL;

  end;

  当外壳调用IPersistFile.Load,它会传递文件名作为pszFileName的参数给COM对象,这时要把文件名保存起来,因为后面要用到它(注意的是pszFileName的类型是PoleStr,实际上等同于类型 PWideChar)。下面是对文件名进行保存:

  function TInfoTip.Load(pszFileName: POleStr; dwMode: Integer): HResult;

  begin

   WideCharToStrVar(pszFileName, fName);

   Result := S_OK;

  end;

  同样IQueryInfo接口的.GetInfoFlags方法不被外壳调用,所以也只需要返回E_NOTIMPL就可以了。整个扩展的核心部分是 IQueryInfo.GetInfoTip方法。 DwFlags参数没有被外壳调用,所以可以忽略它,而ppwszTip参数就是用来返回想要显示的信息 (是一个 UNICODE 字符串)。要注意的是,必须为它分配内存,然而释放内存则是由外壳来负责。Delphi里有一个非常有用的函数StringTooleStr,这个函数接受一个Pascal类型的字符串参数,分配必须的内存,然后把它转化成PWideChar。

  过程的核心部分是获得mp3文件中的Id3-tag信息。一个MP3文件包含有一个ID3-Tag头,它用来提供艺术家、标题、专辑、出版年和歌曲流派等信息。这个头总是128字节长并位于MP3文件末尾。ID3-Tag 结构是这样的:

  type

  TID3Tag = packed record // 128 字节

   TAGID: array[0..2] of char; // 3 字节: 必须是TAG

   Title: array[0..29] of char; // 30 字节: 歌曲标题

   Artist: array[0..29] of char; // 30 字节: 演唱歌曲的艺术家

   Album: array[0..29] of char; // 30 字节: 歌曲专辑

   Year: array[0..3] of char; // 4 字节: 出版年

   Comment: array[0..29] of char; // 30 字节: 评论

   Genre: byte; // 1 字节: 种类标识

  end;

  我们要做的就是读取fName文件,跳到倒数第128个字节,读取ID3-Tag信息,并将其格式化成字符串。下面就是实现的IQueryInfo.GetInfoTip方法,注意这里我们要返回S_Ok的结果。

  function TInfoTip.GetInfoTip(dwFlags: DWORD; var ppwszTip: PWideChar): HResult;

  var

   id3tag: Tid3tag;

   mp3file: Tfilestream;

   s:string;

  begin

   mp3file:=Tfilestream.create(fName,fmOpenRead);

   try

    mp3file.position:=mp3file.size-128; // 跳到id3-tag

    mp3file.Read(id3tag,SizeOf(id3tag));

    s:=' 标题:'+id3tag.title+#10#13+ ‘艺术家:

     '+id3tag.artist+#10#13+

     ' Album: '+id3tag.album+#10#13+ 年份:

     '+id3tag.year+#10#13+ 注释:

     '+id3tag.comment+#10#13+ 风格-ID:

     '+inttostr(id3tag.genre);

   finally

    mp3file.free;

   end;

   ppwszTip := StringToOleStr(s);

   Result := S_OK;

  end;

  最后就是注册COM Server使之同文件相关联,我们要重载COM类工厂对象的UpdateReigistry 方法来添加额外的注册表项。

  下面是我们要在注册表中添加的表项:

   HKEY_CLASSES_ROOT

    \.txt

     \ShellEx

      \{00021500-0000-0000-C000-000000000046}

  {00021500-0000-0000-C000-000000000046}是IqueryInfo接口的GUID,我们不能改变它,最后点菜单 (Run | Register ActiveX Server.)来注册它。

  很重要的是一旦提示信息被显示出来,动态连接库就被装入内存,这时就无法重新编译或UnRegister库了。要想重新编译,必须用任务管理器关闭explore.exe。

  注意:要想在Windows NT和Windows 2000下正常工作,外壳扩展必须注册为管理员同意权限。很多开发者会疏忽这一点,因为大多数情况下他们是以管理员的权限登录的系统。对于Win 9X则不需要设定这一项。

  下面就是要添加的注册表项

  HKEY_LOCAL_MACHINE

   \SOFTWARE

    \Microsoft

     \Windows

      \CurrentVersion

       \Shell Extensions

        \Approved

  在这个键下添加扩展的类标示符(CLSID)及描述信息。

  下面是最后实现的注册代码:

  procedure TCXFileInfoFactory.UpdateRegistry(Register: Boolean);

  var

   ClassID: string;

  begin

   if Register then begin

    inherited UpdateRegistry(Register);

    ClassID := GUIDToString(Class_CXFileInfo);

    CreateRegKey('.mp3\ShellEx\{00021500-0000-0000-C000-000000000046}', '', Classid);

    with TRegistry.Create do

    begin

     try

      RootKey:=HKEY_LOCAL_MACHINE;

      OpenKey('\SOFTWARE\Classes\.mp3\ShellEx\

{00021500-0000-0000-C000-000000000046}',True);

      WriteString('',ClassID);

     finally

      CloseKey;

      Free;

     end;

    end;

   end

   else begin

    //winnt approve registry not installed

    DeleteRegKey('.mp3\ShellEx\{00021500-0000-0000-C000-000000000046}');

    with TRegistry.Create do

    begin

     try

      RootKey:=HKEY_LOCAL_MACHINE;

图2.4

      DeleteKey('\SOFTWARE\Classes\.mp3\ShellEx\{00021500-0000-0000-C000-000000000046}');

     finally

      CloseKey;

      Free;

     end;

    end;

    inherited UpdateRegistry(Register);

   end;

  end;

  好了,现在让我们来试验一下它的效果吧。扩展运行后的示意如图2.4所示。

 

在线服务QQ:99923144 Delphi程序员QQ群(139442)
Delphi知识中心 www.delphi.ee 最专业的Delphi技术资料网站