知识大全 利用COM技术实现外壳扩展的属性页

Posted 属性

篇首语:博学之,审问之,慎思之,明辨之,笃行之。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 利用COM技术实现外壳扩展的属性页相关的知识,希望对你有一定的参考价值。

利用COM技术实现外壳扩展的属性页  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

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

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

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

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

  同文件建立关联需要注册属性页 要在注册表中同相应文件对应的表项下添加Shellex/PropertySheetHandlers子键 每增加一个页面就需要注册一个表项 最大可以添加的页面数是 我们可以用一个扩展实现多个页面 这里我们通过从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(Win Platform=VER_PLATFORM_WIN _NT)then

  begin

    with TRegistry Create do

    try

    RootKey:=HKEY_LOCAL_MACHINE;

    OpenKey( SOFARE\\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[ MAX_PATH+ ]of Char;

    filecount: integer;begin

    Result:=E_FAIL;

  if(lpdobj=nil)then

  begin

    Result:=E_INVALIDARG;

    messagebox( 错误 mb_ok);

    Exit;

  end;

  with FormatEtc do

  begin

    cfFormat:=CF_HDROP;

    ptd:=nil;

    dwAspect:=DVASPECT_CONTENT;

    lindex:= ;

    tymed:=TYMED_HGLOBAL;

  end;

  Result:=lpdobj GetData(FormatEtc StgMedium);

  if Failed(Result)then

  Exit;

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

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

  if filecount= then

  begin

    Result:=NOERROR;

    DragQueryFile(stgmedium hGlobal 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中的对话框模板 模板是用delphi 自带的

  //resource workshop编辑的 使用delphi \\bin\\brcc exe编译的

  psp pszTemplate:=MakeIntResource( );

  //标题名

  psp pszTitle:= 波文件信息 ;

  //设定回调函数

  psp pfnDlgProc:=@DialogProc;

  psp pfnCallBack:=@PropCallback;

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

  psp pcRefParent:=@server objectcount;

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

  psp lParam:=integer(self);

  HPSP:=CreatePropertySheetPage(psp);

  if HPSP$#@ ;$#@ ;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( 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_MAND消息来处理用户交互 响应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 PChar(ExtractFileName(PageObj FFileName)));

    OpenMedia(PageObj FFileName);

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

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

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

  CloseMedia;

    SetWindowLong(hwndDlg DWL_MSGRESULT );

    Result:=TRUE;

  end

  else if(Msg=WM_MAND)then begin

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

    MessageBox( 作者:hubdog +# # + email:hubdog@ 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 );

    Result:=TRUE;

  end;

  end;

  end;

    except

    on e: exception do begin

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

    messagebox( 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方法

cha138/Article/program/Delphi/201311/25066

相关参考

知识大全 Delphi深度探索之自动完成外壳扩展

Delphi深度探索之自动完成外壳扩展  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! &

知识大全 获取源页的公共属性值

  重点总结  在ASPNET中要想从目标页获取源页的数据信息可以使用两种方法  一是通过获取源页的控件进而获取控件的属性值  二是直接通过获取源页公开的公共属性来获取源页数据  本示例代码则演示如何

知识大全 利用JS在asp.net中实现左导航页的隐藏

利用JS在asp.net中实现左导航页的隐藏  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!&nbs

知识大全 DELPHI中利用对象的常用属性制作动画

DELPHI中利用对象的常用属性制作动画  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  在DEL

知识大全 asp.net利用NamingContainer属性获取GridView行号的方法

asp.net利用NamingContainer属性获取GridView行号的方法  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内

知识大全 编写与.NET属性窗口交互的RAD组件(二)

编写与.NET属性窗口交互的RAD组件(二)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  扩展

知识大全 透彻掌握ASP分页技术

透彻掌握ASP分页技术  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  近段时间看了一些论坛上面关

知识大全 .Net技术开发中两个“属性”引起的歧异

.Net技术开发中两个“属性”引起的歧异  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  对于pr

知识大全 利用窗体的自定义属性实现窗体传值

  第步在解决方案上添加一个窗体Form;并添加textBoxtextBoxButton将Button的标题设为确定DialogResult属性设为OK  第步在窗体Form的类代

知识大全 通过继承扩展接口

  利用继承技术可方便地为一个接口添加新的方法声明也可以将几个接口合并成一个新接口在这两种情况下最终得到的都是一个新接口如下例所示    //:HorrorShowjava  //Extendinga