利用COM技术实现外壳扩展的属性页
点击次数:36 次 发布日期:2008-11-09 08:41:51 作者:源代码网
|
源代码网推荐 源代码网推荐 属性页扩展通常是同某类文件相关联的来实现同之相关的操作和信息显示,另外可以同驱动器相关联,我们还可以用属性页扩展来替换控制面板程序的属性页。象其他外壳扩展程序一样,属性页扩展也是以动态连接库形式实现的进程内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 ’shellexPropert eetHandlersWav’,TRUE); 源代码网推荐 源代码网推荐 WriteString(’’,Classid); 源代码网推荐 源代码网推荐 finally 源代码网推荐 源代码网推荐 Free; 源代码网推荐 源代码网推荐 end; 源代码网推荐 源代码网推荐 if(Win32Platform=VER_PLATFORM_WIN32_NT)then 源代码网推荐 源代码网推荐 begin 源代码网推荐 源代码网推荐 with TRegistry.Create do 源代码网推荐 源代码网推荐 try 源代码网推荐 源代码网推荐 RootKey:=HKEY_LOCAL_MACHINE; 源代码网推荐 源代码网推荐 OpenKey(’SOFTWAREMicrosoftWindowsCurrentVersionShell 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)); 软件开发网 www.mscto.com 源代码网推荐 源代码网推荐 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编辑的,使用delphi5inrcc32.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_ROOTDriveShellexPropertySheetHandlers子键。 源代码网推荐 源代码网推荐 建立控制面板属性页扩展 源代码网推荐 源代码网推荐 同上面讲的有两点不同: 源代码网推荐 源代码网推荐 控制面板程序调用IShellPropSheetExt.ReplacePage方法来替换页面,它不调用IShellPropSheetExt。AddPages方法。 源代码网推荐 源代码网推荐 注册方式:子键可以在不同位置创建,这依赖于扩展是针对用户还是针对机器的。对用户方式子键是HKEY_CURRENT_USERREGSTR_PATH_CONTROLPANEL,否则子键是HKEY_LOCAL_MACHINEREGSTR_PATH_CONTROLSFOLDER。 源代码网推荐 源代码网推荐 本程序在Delphi5,Win NT 4.0,K6-233系统下调试成功。例子程序可以到http://chaozhi.com/lgc去下载 源代码网推荐 源代码网供稿. |
