转至繁体中文版     | 网站首页 | 图文教程 | 资源下载 | 站长博客 | 图片素材 | 武汉seo | 武汉网站优化 | 
最新公告:     敏韬网|教学资源学习资料永久免费分享站!  [mintao  2008年9月2日]        
您现在的位置: 学习笔记 >> 图文教程 >> 软件开发 >> Delphi程序 >> 正文
利用COM技术实现外壳扩展的属性页         ★★★★

利用COM技术实现外壳扩展的属性页

作者:闵涛 文章来源:闵涛的学习笔记 点击数:678 更新时间:2009/4/23 18:24:33

  当用户在资源管理器中调用右键菜单时,会显示一个"属性"菜单项,点击属性菜单项会显示一个属性页,用户可以获得甚至修改文件信息。我们可以定制属性页通过实现属性页扩展。如下图所示,本文实现了一个显示wave(波形)文件的信息如声道数等信息的属性页扩展。

  属性页扩展通常是同某类文件相关联的来实现同之相关的操作和信息显示,另外可以同驱动器相关联,我们还可以用属性页扩展来替换控制面板程序的属性页。象其他外壳扩展程序一样,属性页扩展也是以动态连接库形式实现的进程内COM对象。它除了IUnknown接口外还要实现IShellExtInit和IShellPropSheetExt接口。

  建立同文件关联的属性页扩展

  首先,我们用命令File|New...,创建一个ActiveX Library,然后新建一个COM Object,实现的接口为IShellExtInit和IShellPropSheetExt。

  同文件建立关联需要注册属性页,要在注册表中同相应文件对应的表项下添加Shellex/PropertySheetHandlers子键,每增加一个页面就需要注册一个表项,最大可以添加的页面数是24,我们可以用一个扩展实现多个页面。这里我们通过从TComObjectFactory继承类实现的UpdateRegistry实现了注册。

  

  type

    TCXPropSheetFactory=class(TComObjectFactory)

   public

    procedure UpdateRegistry(Register: Boolean); override;

   end;

  procedure TCXPropSheetFactory.UpdateRegistry(Register: Boolean);var

    ClassID: string;

    Str,KeyName : string;begin

    inherited UpdateRegistry(Register);

  if Register then

  begin

    ClassID:=GUIDToString(Class_CXPropSheet);

    with TRegistry.Create do

    try

    RootKey:=HKEY_CLASSES_ROOT;

    OpenKey(’\.wav’,TRUE);

    KeyName := ReadString(’’);

   if Keyname = ’’ then

   begin

    WriteString(’’,’WaveFile’);

    OpenKey(’\.wav’,TRUE);

    KeyName := ReadString(’’);

   end;

    OpenKey(’\’+KeyName+’\shellex\Propert eetHandlers\Wav’,TRUE);

    WriteString(’’,Classid);

    finally

    Free;

  end;

  if(Win32Platform=VER_PLATFORM_WIN32_NT)then

  begin

    with TRegistry.Create do

    try

    RootKey:=HKEY_LOCAL_MACHINE;

    OpenKey(’SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions’, True);

    OpenKey(’Approved’, True);

    WriteString(ClassID, ’Wave File Property Sheet’);

    finally

    Free;

    end;

   end;

  end

  else

  删除注册表项....................... end;初始化扩展是通过IShellExtInit实现的,当外壳调用IShellExtInit.Initialize时,它传递一个数据对象包含来文件对应的目录的PIDL标识符。Initialize方法需要从数据对象中提取文件名,并把文件名和PIDL标识符保存起来为了以后使用。

  

  function TCXPropSheet.SEIInitialize(pidlFolder: PItemIDList;

    lpdobj: IDataObject; hKeyProgID: HKEY): HResult;

  var

    StgMedium: TStgMedium;

    FormatEtc: TFormatEtc;

    szFile: array[0..MAX_PATH+1]of Char;

    filecount: integer;begin

    Result:=E_FAIL;

  if(lpdobj=nil)then

  begin

    Result:=E_INVALIDARG;

    messagebox(0, ’1’, ’错误’, mb_ok);

    Exit;

  end;

  with FormatEtc do

  begin

    cfFormat:=CF_HDROP;

    ptd:=nil;

    dwAspect:=DVASPECT_CONTENT;

    lindex:=-1;

    tymed:=TYMED_HGLOBAL;

  end;

  Result:=lpdobj.GetData(FormatEtc, StgMedium);

  if Failed(Result)then

  Exit;

  //如果只有一个文件被选中,获得文件名并保存。

  filecount:=DragQueryFile(stgmedium.hGlobal, $FFFFFFFF, nil, 0);

  if filecount=1 then

  begin

    Result:=NOERROR;

    DragQueryFile(stgmedium.hGlobal, 0, szFile, SizeOf(szFile));

    FFilename:=strpas(szFile);

  end;

  ReleaseStgMedium(StgMedium);end;添加页面的操作是通过IShellPropSheetExt接口来实现的。如果属性页是和文件相关联,外壳会调用IShellPropSheetExt.AddPages给属性页添加一个页面。如果属性页同控制面板程序相关联,外壳调用IShellPropSheetExt.ReplacePage来替换页面。

  IShellPropSheetExt.AddPages方法有两个参数,lpfnAddPage是一个指向AddPropSheetPageProc回调函数的指针,回调函数用来提供要添加的页面信息给外壳。lParam是一个用户自定义的值,这里我们用它来返回给回调函数对象。

  一般的IShellPropSheetExt.AddPages方法实现步骤是:

  给PROPSHEETPAGE结构设定正确的值,特别是:

  把扩展的对象引用记数变量付值给pcRefParent成员,这可以防止页面还在显示时,扩展对象被卸载。

  实现PropSheetPageProc回调函数来处理页面创建和销毁的情况。

  调用CreatePropertySheetPage函数来创建页面。

  调用lpfnAddPage指向的函数来来添加创建好的页面。

  function TCXPropSheet.AddPages(lpfnAddPage: TFNADDPROPSHEETPAGE;

  lParam: LPARAM): HResult;var

  PSP: TPropSheetPage;

  HPSP: HPropSheetPage;begin

  result:=E_FAIL;

  try

  psp.dwSize:=SizeOf(psp);

  psp.dwFlags:=PSP_USEREFPARENT or PSP_USETITLE or PSP_USECALLBACK;

  psp.hInstance:=hInstance;

  //这里我们使用了事先储存在wave.res中的对话框模板,模板是用delphi5自带的

  //resource workshop编辑的,使用delphi5\bin\brcc32.exe编译的。

  psp.pszTemplate:=MakeIntResource(100);

  //标题名

  psp.pszTitle:=’波文件信息’;

  //设定回调函数

  psp.pfnDlgProc:=@DialogProc;

  psp.pfnCallBack:=@PropCallback;

  //设定对象引用记数变量

  psp.pcRefParent:=@comserver.objectcount;

  //用lParam向回调函数传递对象

  psp.lParam:=integer(self);

  HPSP:=CreatePropertySheetPage(psp);

  if HPSP$#@60;$#@62;nil then begin

  if not lpfnAddPage(HPSP, lParam)then begin

  DestroyPropertySheetPage(HPSP);

  end else begin

  _addref;//增加引用记数,否则一脱离这个方法的作用域,delphi自动释放对象。

  result:=S_OK;

  end

  end

  except

  on e: exception do begin

  e.message:=’添加页面’+e.message;

  messagebox(0, pchar(e.message), ’错误’, mb_ok);

  end;

  end;end;

  function TCXPropSheet.ReplacePage(uPageID: UINT;

  lpfnReplaceWith: TFNADDPROPSHEETPAGE; lParam: LPARAM): HResult;begin

  Result:=E_NOTIMPL;//同文件关联时,外壳不调用ReplacePage,所以不用实现end;回调函数处理属性页的消息,主要要响应WM_INITDIALOG消息来初始化页面显示信息,响应WM_COMMAND消息来处理用户交互,响应WM_NOTIFY消息来处理页面切换或关闭后处理操作结果。

  

  function DialogProc(hwndDlg: HWnd; Msg: UINT; wParam: wParam;

  lParam: LPARAM): Bool; stdcall;

  var

    PageObj: TCXPropSheet;

    filename: string;

    displayName : string;

    SheetHWnd: HWnd;

  begin

    result:=false;

    try

    if Msg=WM_INITDIALOG then begin//初始化界面

  //获得lparam传递过来的对象

    pageObj:=TCXPropSheet(PPropSheetPage(lParam)^.lParam);

  //保存对象信息

    SetWindowLong(hwndDlg, DWL_USER, integer(pageObj));

  //设置界面显示波文件信息

    SetDlgItemText(hwndDlg, 100, PChar(ExtractFileName(PageObj.FFileName)));

    OpenMedia(PageObj.FFileName);

  SetDlgItemText(hwndDlg, 101, PChar(IntToStr(GetWavStatus(MCI_WAVE_STATUS_AVGBYTESPERSEC))));

  SetDlgItemText(hwndDlg, 102, PChar(IntToStr(GetWavStatus(MCI_WAVE_STATUS_BITSPERSAMPLE))));

  SetDlgItemText(hwndDlg, 103, PChar(IntToStr(GetWavStatus(MCI_WAVE_STATUS_CHANNELS))));

  CloseMedia;

    SetWindowLong(hwndDlg, DWL_MSGRESULT, 0);

    Result:=TRUE;

  end

  else if(Msg=WM_COMMAND)then begin

  if Lo(wParam)=110 then//用户点击了关于按钮(id=110)

    MessageBox(0,’作者:hubdog’+#13#10+’email:hubdog@263.net’,’关于...’,MB_OK);

  end else if(msg=WM_NOTIFY)then begin

    sheetHwnd:=getparent(hwndDlg);//获得属性页的窗口句柄

    case PNMHdr(lparam)^.code of

  //页面失去焦点

    PSN_KILLACTIVE:

  begin

    SetWindowLong(hwndDlg, DWL_MSGRESULT, 0);

    Result:=TRUE;

  end;

  end;

  end;

    except

    on e: exception do begin

    e.message:=’回调处理’+e.message;

    messagebox(0, pchar(e.message), ’错误’, mb_ok);

  end;

  end;

  end;

  

  建立同驱动器相关联的属性页扩展用

  同上面讲的有两点不同:

  IShellExtInit.Initialize方法传递过来的数据对象包含的驱动器路径可能是CFSTR_MOUNTEDVOLUME格式而不是CF_HDROP格式的。标准驱动器是CF_HDROP格式的,而在NTFS文件系统中映射的远程设备则是CFSTR_MOUNTEDVOLUME格式的。

  注册表项是HKEY_CLASSES_ROOT\Drive\Shellex\PropertySheetHandlers子键。

  建立控制面板属性页扩展

  同上面讲的有两点不同:

  控制面板程序调用IShellPropSheetExt.ReplacePage方法来替换页面,它不调用IShellPropSheetExt。AddPages方法。

  注册方式:子键可以在不同位置创建,这依赖于扩展是针对用户还是针对机器的。对用户方式子键是HKEY_CURRENT_USER\REGSTR_PATH_CONTROLPANEL,否则子键是HKEY_LOCAL_MACHINE\REGSTR_PATH_CONTROLSFOLDER。

  本程序在Delphi5,Win NT 4.0,K6-233系统下调试成功。例子程序可以到http://chaozhi.com/lgc去下载。


没有相关教程
教程录入:mintao    责任编辑:mintao 
  • 上一篇教程:

  • 下一篇教程:
  • 【字体: 】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
      注:本站部分文章源于互联网,版权归原作者所有!如有侵权,请原作者与本站联系,本站将立即删除! 本站文章除特别注明外均可转载,但需注明出处! [MinTao学以致用网]
      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)

    同类栏目
    · C语言系列  · VB.NET程序
    · JAVA开发  · Delphi程序
    · 脚本语言
    更多内容
    热门推荐 更多内容
  • 没有教程
  • 赞助链接
    更多内容
    闵涛博文 更多关于武汉SEO的内容
    500 - 内部服务器错误。

    500 - 内部服务器错误。

    您查找的资源存在问题,因而无法显示。

    | 设为首页 |加入收藏 | 联系站长 | 友情链接 | 版权申明 | 广告服务
    MinTao学以致用网

    Copyright @ 2007-2012 敏韬网(敏而好学,文韬武略--MinTao.Net)(学习笔记) Inc All Rights Reserved.
    闵涛 投放广告、内容合作请Q我! E_mail:admin@mintao.net(欢迎提供学习资源)

    站长:MinTao ICP备案号:鄂ICP备11006601号-18

    闵涛站盟:医药大全-武穴网A打造BCD……
    咸宁网络警察报警平台