关于超想
本站导航
邮件列表
  首页 | 本站产品 | Delphi资料 | 免费资源 | 程序人生 | 软件工程 | 网站设计 | 推荐网站
你所在的位置 -> 主页 -> 超想软件 -> 编程资料 -> delphi -> 开发技巧 -> API相关 ->详细
相关内容  
 
 
在Delphi程序中应用IE浏览器控件
 
【新品推荐】

  详细内容
 

如何用delphi实现windows特定程序外壳扩展的开发
作者: 评价: 上站日期: 2002-05-02
内容说明:
来源:

本文介绍了如何在windows 2000 profession中,用delphi实现对特定程序文件的属性页扩展.同时也介绍了在delphi环境下,对操作系统的通用对象模型(COM)实现应用的一般方法。

人们一般都有这样的经历:当用户在资源管理器中用右键菜单时,会显示一个“属性”菜单,点击属性菜单项会显示一个属性页,系统对不同的文件会有不同的属性页扩展。如:在windows98中对文本文件系统有“常规”属性页,对于word文档系统就有:“常规”、“载要”、“统计”三个属性页。而对于DLL文件系统只有“常规”、“版本”两个属性页。

那么,作为一个程序员如何也在自己开发的程序中实现类似系统上述的功能呢?其实,属性页扩展程序主要是一个以动态链接库DLL实现的in-process服务器,他除了实现基本的COM的iunknown接口外,还实现它的IShellExtInit和IShellpropsheetext接口。其中IShellExtInit的Initialize方法用于实现初始化快捷菜单处理器,IShellpropsheetext接口用于向属性页添加页面,如果属性页和特定的文件相关则系统会调用IShellpropsheetext的addpages方法给属性页添加一个页面。

现以编写一个指定文件扩展名为".bbs"为例把方法介绍如下:

1、首先用文本编辑器编写一个资源文件ra.rc,并用delphi自带的brcc32.exe编译成ra.res。

ra.rc代码如下

#define  DIALOG_1  1        //资源文件标示符
  #define  IDC_PUSHBUTTON1  101    //按扭标示符
 
  DIALOG_1  DIALOG  6,  15,  161,  127
  STYLE  WS_POPUP  |  WS_VISIBLE  |  WS_CAPTION  |  WS_SYSMENU  |  WS_THICKFRAME  |  WS_MINIMIZEBOX  |  WS_MAXIMIZEBOX
  CAPTION  "DIALOG_1"
  FONT  8,  "MS  Sans  Serif"
  {
    LTEXT  "作者",  -1,  9,  15,  47,  18
    LTEXT  "时间",  -1,  8,  38,  44,  17
    LTEXT  "孙航东",  -1,  79,  17,  64,  20
    LTEXT  "2002.04.26",  -1,  80,  41,  60,  18
    PUSHBUTTON  "Button",  IDC_PUSHBUTTON1,  79,  88,  53,  17
  }


2、然后在Delphi中选择菜单File中的New命令,在ActiveX页中选择active Library 以实现一个标准的in-process COM server。然后选择菜单File中的New命令,在ActiveX选择COM object对象。

如图1,以实现IShellExtInit和IShellpropsheetext接口。并把单元文件文件保存unit1.pas,把项目文件保存为project1.dpr。



3、向prject1.dpr文件添加自己编译的资源文件,把{$R *.RES}修改成{$R as.RES}。

3、编辑unit1.pas代码如下(我在要加入的代码旁都加以注释):

unit  unit  Unit1;
 
  interface
 
  uses
      Windows,  Sysutils,  Messages,  Registry,  Shellapi,  ActiveX,  Classes,  ComObj,  Shlobj,  ComServ,  MMSystem,Dialogs,  Commctrl;
 
  type
      TPropSheetExt  =  class(TComObject,  IShellExtInit,  IShellPropSheetExt)
      private
          TempFile:string;//定义一个文件名传递变量。
      protected
          {Declare  IShellExtInit  methods  here}
          function  IShellExtInit.Initialize=MyInitialize;
        //进行初始化代码的转移,使系统执行初始化操作时调用自己的代码//
          function  MyInitialize(pidlFolder:  PItemIDList;  lpdobj:  IDataObject;
                    hKeyProgID:  HKEY):  HResult;  stdcall;
        //Initialize的方法定义在shlobj.pas文件中//
          {Declare  IShellPropSheetExt  methods  here}
          function  AddPages(lpfnAddPage:  TFNAddPropSheetPage;  lParam:  LPARAM):  HResult;  stdcall;
          function  ReplacePage(uPageID:  UINT;  lpfnReplaceWith:  TFNAddPropSheetPage;
              lParam:  LPARAM):  HResult;  stdcall;
          //IShellPropSheetExt的方法定义在shlobj.pas文件中//
      end;
  type//每一个COM对象必须有一个类工厂,用于在服务器端实现COM对象//
        TPropSheetExtFactory=class(TComObjectFactory)
        public
              procedure  UpdateRegistry(Register:  Boolean);  override;
        end;
  const
      Class_PropSheetExt:  TGUID  =  '{2356E2F2-419F-11D4-9376-5254AB159E5E}';
    //GUID值系统唯一产生// 
var
    Error,  dwFlags:  Longint;
      DeviceID  :  Word;
 
  implementation
  //---------------------------------------------------------------------------------//
  function  PropCallback(hWndDlg:  HWnd;  Msg:  Integer;
        var  PPSP:  TPropSheetPage):  Integer;  stdcall;
  begin
        case  Msg  of
              PSPCB_RELEASE:  if  ppsp.lparam<>  0  then    TPropSheetExt(ppsp.lparam)._release;
        end;//使用完接口后通过调用_release来减少对接口的引用。//
      result:=1;
  end;
  //-------------------------------------------------------------------------------//
  function  DialogProc(hwndDlg:  HWnd;  Msg:  UINT;  wParam:  wParam;
        lParam:  LPARAM):  Bool;  stdcall;//该回调函数用于处理属性页的消息//
  var
        MyPropsheetExt:  TPropSheetExt;
        filename:  string;
      //  displayName  :  string;
      //  buffer:  array[0..255]of  char;
        //SheetHWnd:  HWnd;
  begin
        result:=false;
        try
              if  Msg=WM_INITDIALOG  then//该消息用于初始化页面显示信息// 
                                            begin
                  MyPropSheetExt:=TPropSheetExt(PPropSheetPage(lParam)^.lParam);
                  SetWindowLong(hwndDlg,  DWL_USER,  integer(MyPropSheetExt));
                    SetDlgItemText(hwndDlg,  100,  PChar(ExtractFileName(MyPropSheetExt.TempFile)));
                    SetWindowLong(hwndDlg,  DWL_MSGRESULT,  0);
                    Result:=TRUE;
                                                  end;
                if(Msg=WM_COMMAND)then//该消息用于响应用户在属性页上的按扭事件// 
                            begin
                  if  Lo(wParam)=101  then//101为资源文件上IDC_PUSHBUTTON1的标示符// 
                      showmessage('谢谢你使用');
                            end  ;
        except//在处理属性页面失效时显示出错信息//
              on  e:  exception  do
                begin
                    e.message:='PropExtDlgProc  '+e.message;
                    messagebox(0,  pchar(e.message),  'error',  mb_ok);
              end;
        end;
  end;
  //------------------------------------------------------------------------------------//
 
 
  procedure  TPropSheetExtFactory.UpdateRegistry(Register:  Boolean);
  var//注册属性页以便同指定的文件关联//
      MyClassID:  string;
  begin
        inherited  UpdateRegistry(Register);
        if  Register  then
        begin
            MyClassID:=GUIDToString(Class_PropSheetExt);
            with  TRegistry.Create  do
            try
                RootKey:=HKEY_CLASSES_ROOT;
                createregkey('.bbs','','sunhangdong');
                createregkey('sunhangdong\shellex\PropertySheetHandlers\'+classname,'',MyClassID);
            finally
              Free;
            end;
        end
        else
        begin
        deleteregkey('sunhangdong\shellex\PropertySheetHandlers\'+classname);
        end;
  end;
 
  //----------------------------------------------------------------------------------------//
  {  TPropSheetExt  }
 
  function  TPropSheetExt.AddPages(lpfnAddPage:  TFNADDPROPSHEETPAGE;
      lParam:  LPARAM):  HResult;
  var//初始化快捷菜单//
        TProp:  TPropSheetPage;
        HProP:  HPropSheetPage;
  begin
        result:=E_FAIL;
        try
              TProp.dwSize:=SizeOf(TProp);
              TProp.dwFlags:=PSP_USEREFPARENT  or  PSP_USETITLE  or  PSP_USECALLBACK;
              TProp.hInstance:=hInstance;
              TProp.pszTemplate:=MakeIntResource(1);//属性页的标示符//
              TProp.pszTitle:='特别消息';//属性页标题
              Tprop.pfnDlgProc:=@DialogProc;
              TProp.pfnCallBack:=@PropCallback;
            //设立回调函数//
              TProp.pcRefParent:=@comserver.objectcount;
  //把扩展对象引用计数赋予pcRefParent对象,以防止属性页在显示时就被删除//
              TProp.lParam:=integer(self);//传递对象指针//
              HProP:=CreatePropertySheetPage(TProp);
              if  HPSP<>nil  then  begin
                    if  not  lpfnAddPage(HProP,  lParam)then  begin
                          DestroyPropertySheetPage(HProP);
                    end  else  begin
                          _addref;//增加引用计数,以防止方法不在作用范围时,被系统释放//
                          result:=S_OK;
                    end
              end
        except
              on  e:  exception  do  begin
                    e.message:='AddPages  '+e.message;
                    messagebox(0,  pchar(e.message),  'error',  mb_ok);
              end;
        end;
  end;
  //------------------------------------------------------------------------------------------//
  function  TPropSheetExt.ReplacePage(uPageID:  UINT;
      lpfnReplaceWith:  TFNADDPROPSHEETPAGE;  lParam:  LPARAM):  HResult;
  begin//当属性页和控制面版相关时,系统会调用该方法来替换属性页,在本程序中无用,但必须定义//
      Result:=E_NOTIMPL;
  end;
  //-----------------------------------------------------------------------------------------//
  function  TPropSheetExt.MyInitialize(pidlFolder:  PItemIDList;
      lpdobj:  IDataObject;  hKeyProgID:  HKEY):  HResult;
  var//实现初始化快捷菜单处理器//
        MyStgMedium:  TStgMedium;
        MyFormatEtc:  TFormatEtc;
        Filelength:  array[0..MAX_PATH+1]of  Char;
        count:  integer;
  begin
        Result:=E_FAIL;
        if(lpdobj=nil)then  begin
              Result:=E_INVALIDARG;//如果COM服务器没有对象提供//
              messagebox(0,  '1',  'error',  mb_ok);
              Exit;
        end;
 
        with  MyFormatEtc  do  begin//在用户进行数据接口的呈现时必须用此接口//
              cfFormat:=CF_HDROP;
              ptd:=nil;
              dwAspect:=DVASPECT_CONTENT;
              lindex:=-1;
              tymed:=TYMED_HGLOBAL;
        end;
        Result:=lpdobj.GetData(MyFormatEtc,  MyStgMedium);
        if  Failed(Result)then
              Exit;//如果从数据接口无法得到数据//
        count:=DragQueryFile(Mystgmedium.hGlobal,  $FFFFFFFF,  nil,  0);//count返回的是用户选择的文件数//
        if  count=1  then//用于确保用户只选择了一个文件// 
            begin
            Result:=NOERROR;
            DragQueryFile(Mystgmedium.hGlobal,  0,  FileLength,  MAX_PATH);
              TempFile:=strpas(FileLength);
              end;
        ReleaseStgMedium(MyStgMedium);
  end;
  //--------------------------------------------------------------------------------------------//
  initialization
      TPropSheetExtFactory.Create(ComServer,  TPropSheetExt,  Class_PropSheetExt,
          'PropSheetExt',  '',  ciMultiInstance,  tmApartment);
  end.


结果见图2和图3。





以上代码在Delphi 5.0+Windows 2000 Profession 中运行通过。

 
你所在的位置 -> 主页 -> 超想软件 -> 编程资料 -> delphi -> 开发技巧 -> API相关 ->详细
  首页 | 本站产品 | Delphi资料 | 免费资源 | 程序人生 | 软件工程 | 网站设计 | 推荐网站
声明:本站内容除注明原创以外均从网上摘抄,如有侵权请指明。
  如果您对我们的网站有什么意见或者建议,请与我们联系
powered by 建站易上手- V2.0