熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Delphi編程 >> 正文

利用COM技術實現外殼擴展的屬性頁

2013-11-23 17:46:51  來源: Delphi編程 

  當用戶在資源管理器中調用右鍵菜單時會顯示一個屬性菜單項點擊屬性菜單項會顯示一個屬性頁用戶可以獲得甚至修改文件信息我們可以定制屬性頁通過實現屬性頁擴展如下圖所示本文實現了一個顯示wave(波形)文件的信息如聲道數等信息的屬性頁擴展

  屬性頁擴展通常是同某類文件相關聯的來實現同之相關的操作和信息顯示另外可以同驅動器相關聯我們還可以用屬性頁擴展來替換控制面板程序的屬性頁象其他外殼擴展程序一樣屬性頁擴展也是以動態連接庫形式實現的進程內COM對象它除了IUnknown接口外還要實現IShellExtInit和IShellPropSheetExt接口

  建立同文件關聯的屬性頁擴展

  首先我們用命令File|New創建一個ActiveX Library然後新建一個COM Object實現的接口為IShellExtInit和IShellPropSheetExt

  同文件建立關聯需要注冊屬性頁要在注冊表中同相應文件對應的表項下添加Shellex/PropertySheetHandlers子鍵每增加一個頁面就需要注冊一個表項最大可以添加的頁面數是我們可以用一個擴展實現多個頁面這裡我們通過從TComObjectFactory繼承類實現的UpdateRegistry實現了注冊

  type

    TCXPropSheetFactory=class(TComObjectFactory)

   public

    procedure UpdateRegistry(Register: Boolean); override;

   end;

  procedure TCXPropSheetFactoryUpdateRegistry(Register: Boolean);var

    ClassID: string;

    StrKeyName : string;begin

    inherited UpdateRegistry(Register);

  if Register then

  begin

    ClassID:=GUIDToString(Class_CXPropSheet);

    with TRegistryCreate do

    try

    RootKey:=HKEY_CLASSES_ROOT;

    OpenKey(\wavTRUE);

    KeyName := ReadString();

   if Keyname = then

   begin

    WriteString(WaveFile);

    OpenKey(\wavTRUE);

    KeyName := ReadString();

   end;

    OpenKey(\+KeyName+\shellex\Propert eetHandlers\WavTRUE);

    WriteString(Classid);

    finally

    Free;

  end;

  if(WinPlatform=VER_PLATFORM_WIN_NT)then

  begin

    with TRegistryCreate 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實現的當外殼調用IShellExtInitInitialize時它傳遞一個數據對象包含來文件對應的目錄的PIDL標識符Initialize方法需要從數據對象中提取文件名並把文件名和PIDL標識符保存起來為了以後使用

  function TCXPropSheetSEIInitialize(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:=lpdobjGetData(FormatEtc StgMedium);

  if Failed(Result)then

  Exit;

  //如果只有一個文件被選中獲得文件名並保存

  filecount:=DragQueryFile(stgmediumhGlobal $FFFFFFFF nil );

  if filecount= then

  begin

    Result:=NOERROR;

    DragQueryFile(stgmediumhGlobal szFile SizeOf(szFile));

    FFilename:=strpas(szFile);

  end;

  ReleaseStgMedium(StgMedium);end;添加頁面的操作是通過IShellPropSheetExt接口來實現的如果屬性頁是和文件相關聯外殼會調用IShellPropSheetExtAddPages給屬性頁添加一個頁面如果屬性頁同控制面板程序相關聯外殼調用IShellPropSheetExtReplacePage來替換頁面

  IShellPropSheetExtAddPages方法有兩個參數lpfnAddPage是一個指向AddPropSheetPageProc回調函數的指針回調函數用來提供要添加的頁面信息給外殼lParam是一個用戶自定義的值這裡我們用它來返回給回調函數對象

  一般的IShellPropSheetExtAddPages方法實現步驟是

  · 給PROPSHEETPAGE結構設定正確的值特別是把擴展的對象引用記數變量付值給pcRefParent成員這可以防止頁面還在顯示時擴展對象被卸載

  · 實現PropSheetPageProc回調函數來處理頁面創建和銷毀的情況

  · 調用CreatePropertySheetPage函數來創建頁面

  · 調用lpfnAddPage指向的函數來來添加創建好的頁面

  function TCXPropSheetAddPages(lpfnAddPage: TFNADDPROPSHEETPAGE;

  lParam: LPARAM): HResult;var

  PSP: TPropSheetPage;

  HPSP: HPropSheetPage;begin

  result:=E_FAIL;

  try

  pspdwSize:=SizeOf(psp);

  pspdwFlags:=PSP_USEREFPARENT or PSP_USETITLE or PSP_USECALLBACK;

  psphInstance:=hInstance;

  //這裡我們使用了事先儲存在waveres中的對話框模板模板是用delphi自帶的

  //resource workshop編輯的使用delphi\bin\brccexe編譯的

  psppszTemplate:=MakeIntResource();

  //標題名

  psppszTitle:=波文件信息;

  //設定回調函數

  psppfnDlgProc:=@DialogProc;

  psppfnCallBack:=@PropCallback;

  //設定對象引用記數變量

  psppcRefParent:=@comserverobjectcount;

  //用lParam向回調函數傳遞對象

  psplParam:=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

  emessage:=添加頁面+emessage;

  messagebox( pchar(emessage) 錯誤 mb_ok);

  end;

  end;end;

  function TCXPropSheetReplacePage(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 PChar(ExtractFileName(PageObjFFileName)));

    OpenMedia(PageObjFFileName);

  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_COMMAND)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

    emessage:=回調處理+emessage;

    messagebox( pchar(emessage) 錯誤 mb_ok);

  end;

  end;

  end;

  建立同驅動器相關聯的屬性頁擴展

  同上面講的有兩點不同

  IShellExtInitInitialize方法傳遞過來的數據對象包含的驅動器路徑可能是CFSTR_MOUNTEDVOLUME格式而不是CF_HDROP格式的標准驅動器是CF_HDROP格式的而在NTFS文件系統中映射的遠程設備則是CFSTR_MOUNTEDVOLUME格式的

  注冊表項是HKEY_CLASSES_ROOT\Drive\Shellex\PropertySheetHandlers子鍵

  建立控制面板屬性頁擴展

  同上面講的有兩點不同

  控制面板程序調用IShellPropSheetExtReplacePage方法來替換頁面它不調用IShellPropSheetExtAddPages方法

  注冊方式子鍵可以在不同位置創建這依賴於擴展是針對用戶還是針對機器的對用戶方式子鍵是HKEY_CURRENT_USER\REGSTR_PATH_CONTROLPANEL否則子鍵是HKEY_LOCAL_MACHINE\REGSTR_PATH_CONTROLSFOLDER


From:http://tw.wingwit.com/Article/program/Delphi/201311/25066.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.