隨筆 - 312, 文章 - 14, 評論 - 1393, 引用 - 0
          數據加載中……

          自動填表的IE面板插件

          簡介

          IE的面板實際就是嵌入到IE瀏覽器中的子窗體。面板有兩種顯示模式,一種是垂直顯示在瀏覽器的左側,一種是水平顯示在瀏覽器的下方。IE瀏覽器內置提供了很多的標準面板,如收藏夾和搜索面板這些是垂直的面板,而每日提示和討論面板則是水平的面板。

           

          此外我們還可以通過實現COM組件來添加我們自己的瀏覽器面板到IE中。當我們的面板COM組件注冊后,它會被添加到瀏覽器的查看菜單的瀏覽器欄的子菜單下。當用戶選中該菜單項后,該面板就會顯示在瀏覽器中。

          實現面板COM組件

              接下來我們將實現類似于IE內置的收藏夾的一個面板,不過它不是用來收藏網址的,而是用來運行程序的。下面是它的示意圖:

          同所有的COM組件一樣,面板組件首先要實現IUnknown 和IClassFactory接口,不過Borland提供了TComObject類,這個類已經實現了前面兩個接口,我們因此就不需要再重造輪子了,只要從TComObject類繼承就可以了。

          首先選擇菜單File | New | ActiveX | Com Object命令,創建一個TDelphiBand的COM組件框架

          然 后我們就需要實現IDeskBand,IObjectWithSite和IPersistStreamInit或者IPersistStream接口了。 其中IPersistStreamInit和IPersistStream接口可以用來保存面板的各種狀態和信息,IPersistStreamInit 和IPersistStream接口相比就是多了一個InitNew的方法,這個方法可以用來初始化面板組件的狀態。在本文中,由于不涉及信息的保存,因 此這個接口的方法的實現大部分都是直接返回E_NOTIMPL表示該方法沒有被實現。除了GetClassID方法,當系統調用這個方法的時候,我們需要 返回COM組件的GUID標識符。

          function TDelphiBand.GetClassID(out classID: TCLSID): HResult;

          begin

            classID := CLSID_DelphiBand;

            Result := S_OK;

          end;

          IObjectWithSite接口,顧 名思義這個接口就是一個嵌入在COM容器中的組件需要實現的接口,當用戶選中一個瀏覽器面板的時候,IE這個COM容器會調用面板組件的 IObjectWithSite的SetSite方法,這個方法傳遞過來的punkSite參數就是COM容器的IUnknown接口,通過這個接口我們 可以獲得IE提供的各個COM接口,進而可以調用IE提供的所有功能。這個方法的一般實現是:

          1、  如果方法傳過來的punkSite參數為nil,表示面板組件正在被隱藏釋放。這時方法的返回結果必須為S_OK。

          2、  如果punkSite參數不為nil,則通過punkSite獲得我們所需要的COM接口(如IE的IWebBrowser接口),并將其保存起來。

          下面是SetSite方法的實現代碼:

          function TDelphiBand.SetSite(const pUnkSite: IUnknown): HResult;

          begin

            if Assigned(pUnkSite) then begin

          //獲得IInputObjectSite接口,并保存起來,后面會用它通知瀏覽器

          //面板焦點的變化情況

              Site := pUnkSite as IInputObjectSite;

          //通過調用GetWindow來獲得父窗體的句柄,并保存

          (pUnkSite as IOleWindow).GetWindow(ParentWnd);

          //獲得IEIWebBrowser2接口

          (Site as IServiceProvider).QueryService(IWebbrowserApp, IWebbrowser2, IE);

            end;

            Result := S_OK;

          end;

           

          IObjectWithSite還有一個GetSite方法也需要實現,方法的定義如下:

          function GetSite(const riid: TIID; out site: IUnknown): HResult; stdcall;

          其中我們需要返回在 SetSite方法中保存的Site接口,然后從site接口獲得riid參數所需要的接口,如果Site接口為nil,方法的返回的HResult需要 設定為E_Fail,表示調用失敗。如果Site接口支持riid指定的接口的話,我們就返回S_OK表示成功,如果Site接口不為nil,但是也不支 持riid的接口的話,我們就返回E_NOINTERFACE,表示無法獲得riid對應的接口。代碼實現如下:

          function TDelphiBand.GetSite(const riid: TIID; out site: IUnknown): HResult;

          begin

            if Assigned(Site) then Result := Site.QueryInterface(riid, site)

            else Result := E_FAIL;

          end;

           

          接下來的IDeskBand接口就是我們面板組件所要實現的核心接口了。它包括下面這些方法。

              function GetBandInfo(dwBandID, dwViewMode: DWORD; var pdbi: TDeskBandInfo):

                HResult; stdcall;

              function ShowDW(fShow: BOOL): HResult; stdcall;

              function CloseDW(dwReserved: DWORD): HResult; stdcall;

              function ResizeBorderDW(var prcBorder: TRect; punkToolbarSite: IUnknown;

                fReserved: BOOL): HResult; stdcall;

              function GetWindow(out wnd: HWnd): HResult; stdcall;

          function ContextSensitiveHelp(fEnterMode: BOOL): HResult; stdcall;

          其中ContextSensitiveHelp方法是用來提供上下文幫助支持的,未來簡單起見,這里我們不提供上下文支持,所以簡單返回E_NOTIMPL就可以了。而ResizeBorderDW 方法系統也從來不會調用,因此我們也返回E_NOTIMPL。

           

          獲得面板的顯示信息

           

          對于GetWindow方法來說,我們需要返回要嵌入到IE中的子窗體的句柄,以便容器用來顯示。下面是GetWindow方法的實現:

          function TDelphiBand.GetWindow(out wnd: HWnd): HResult;

          begin

          //如果還沒有創建面板窗體,則創建
            if not Assigned(BandForm) then

          begin

              //父窗體是先前在SetSite方法中獲得的父窗體

          BandForm := TBandForm.CreateParented(ParentWnd);

          //將IE賦值給面板界面的相應變量

          BandForm.IE:=IE;

            End;

            //返回子窗體的句柄

            Wnd := Bandform.Handle;

            SavedWndProc := Bandform.WindowProc;

            //替換默認的窗體消息過程

            Bandform.WindowProc := BandWndProc;

            Result := S_OK;

          end;

           

          此外,因為面板對象是以子窗體的形式顯示,它還必須實現窗口消息過程。這里我們使用BandWndProc過程替換了窗體默認的消息處理過程,BandWndProc的實現如下:

           

          procedure TDelphiBand.BandWndProc(var Message: TMessage);

          begin

            //當我們的窗體的子控件,如編輯框獲得焦點后,系統會發WM_ParentNotify消息給

            //我們的窗體,這時要通知瀏覽器我們面板獲得了焦點,這樣IE才會將快捷鍵發送給

            //我們的窗體

            if (Message.Msg = WM_PARENTNOTIFY)  then

            begin

              Hasfocus:=True;

              FocusChange(True);

            end;

            //然后調用保存的原有窗體消息過程來處理

            SavedWndProc(Message);

          end;

           

          FocuseChanged方法用來通知瀏覽器焦點的變化情況,實現如下:

          procedure TDelphiBand.FocusChange(bHasFocus: Boolean);

          begin

          //調用先前保存的IInputObjectSiteOnFocusChangeIS方法通知瀏覽器

          //焦點變化。

            if (Site <> nil) then Site.OnFocusChangeIS(Self, bHasFocus);

          end;

           

          系統獲得子窗體的同時,因 為IE本身對子窗體的顯示區域是有一定限制的,所以它還需要知道面板窗體的某些屬性,如最大顯示尺寸、最小顯示尺寸、改變大小時的尺寸變化幅度等信息,這 些信息它是通過調用面板組件的IDeskBand接口的GetBandInfo方法來獲得的。下面是GetBandInfo方法的聲明:

          function GetBandInfo(dwBandID, dwViewMode: DWORD; var pdbi: TDeskBandInfo):HResult;

          其中dwBandID參數是面板的標識符,這個標識符是COM容器賦予的,我們需要保存這個ID。dwViewMode表示面板的顯示模式:

           

          DBIF_VIEWMODE_FLOATING

          浮動面板

          DBIF_VIEWMODE_NORMAL

          水平面板

          DBIF_VIEWMODE_TRANSPARENT

          面板是透明的

          DBIF_VIEWMODE_VERTICAL

          面板是垂直面板

           

          pdbi參數則是一個TDESKBANDINFO 結構,結構定義如下:

            DESKBANDINFO = packed record

              dwMask: DWORD;

              ptMinSize: TPointL;

              ptMaxSize: TPointL;

              ptIntegral: TPointL;

              ptActual: TPointL;

              wszTitle: array[0..255] of WideChar;

              dwModeFlags: DWORD;

              crBkgnd: COLORREF;

            end;

          下表是關于結構中各個成員的詳細說明:

           

          dwMask

          指定被請求的面板信息的掩碼,是下面參數的組合。

          DBIM_MINSIZE

          請求面板最小尺寸信息

          DBIM_MAXSIZE

          請求面板最大尺寸信息

          DBIM_INTEGRAL

          請求面板尺寸改變的幅度信息

          DBIM_ACTUAL

          請求面板默認尺寸信息

          DBIM_TITLE

          請求面板標題信息

          DBIM_MODEFLAGS

          請求dwModeFlags參數代表的額外的面板顯示信息

          DBIM_BKCOLOR

          請求面板背景色信息

          ptMinSize

          返回面板最小尺寸,最小寬度保存在x成員,最小高度保存在y成員

          ptMaxSize

          返回面板最大尺寸,最大高度放在y成員中,x成員不被使用。如果最大高度沒有限制,應該將y賦值為-1

          ptIntegral

          返回面板尺寸改變幅度,垂直改變幅度放在y中,x不使用。如果dwModeFlags不包含DBIMF_VARIABLEHEIGHT,這個信息被忽略。

          ptActual

          返回面板的默認尺寸。x保存寬度,y保存高度,容器會盡量使用這個尺寸來顯示面板,但不保證一定使用這個尺寸。

          wszTitle

          返回面板的標題

          dwModeFlags

          返回下面顯示方式的組合

          DBIMF_NORMAL

          缺省的顯示模式

          DBIMF_VARIABLEHEIGHT

          面板的高度可以被改變。

          DBIMF_DEBOSSED

          面板采用下陷的樣式來顯示

          DBIMF_BKCOLOR

          面板將以crbkgnd指定的顏色作為自己的背景色

          crBkgnd

          背景色

          當系統調用GetBandInfo方法后,我們只要根據系統請求返回相應的面板信息就可以了,代碼實現如下:

          function TDelphiBand.GetBandInfo(dwBandID, dwViewMode: DWORD; var pdbi: TDeskBandInfo):  HResult;

          begin

            //保存面板ID,以便后面使用

            BandId := dwBandID;

            //如果請求最小尺寸,則窗體的最小寬度是窗體設計時的寬度

            if (pdbi.dwMask or DBIM_MINSIZE) <> 0 then

          begin

              pdbi.ptMinSize.y := Bandform.width;

              pdbi.ptMinSize.x := -1;

            end;

            //最大尺寸無限制

            if (pdbi.dwMask or DBIM_MAXSIZE) <> 0  then

          begin

              pdbi.ptMaxSize.x := -1;

              pdbi.ptMaxSize.y := -1;

            end;

            //大小改變幅度都為1

            if (pdbi.dwMask or DBIM_INTEGRAL) <> 0 then

          begin

              pdbi.ptIntegral.x := 1;

              pdbi.ptIntegral.y := 1;

            end;

            //默認尺寸為窗體設計尺寸,注意我們這里的面板是垂直面板,因此x對應的高度

            //y對應的是寬度

            if (pdbi.dwMask or DBIM_ACTUAL) <> 0 then

          begin

              pdbi.ptActual.x := Bandform.Height;

              pdbi.ptActual.y := bandform.Width;

            end; 

          //面板的寬度可調

            if (pdbi.dwMask or DBIM_MODEFLAGS) <> 0 then

            begin

              pdbi.dwModeFlags := DBIMF_VARIABLEHEIGHT;

            end;

            //忽略背景色的設置,因為Delphi的窗體背景色是VCL自己畫的,不使用

            //Windows默認顏色

            if (pdbi.dwMask or DBIM_BKCOLOR) <> 0 then

            begin

              pdbi.dwMask := pdbi.dwMask and (not DBIM_BKCOLOR);

            end;

            //返回面板的標題,注意返回的字符串必須是Unicode

            if (Pdbi.dwMask and DBIM_TITLE) = DBIM_TITLE then

          begin

              FillChar(pdbi.wszTitle, SizeOf(Caption) + 1, ' ');

              StringToWideChar(Caption, @pdbi.wszTitle, Length(Caption) + 1);

            end;

            Result := NOERROR;

          end;

           

          當面板需要顯示或隱藏的時候系統會調用IDeskBand接口的ShowDW方法通知面板改變窗體的顯示狀態,方法的fShow布爾參數表示需要顯示還是隱藏窗體,代碼實現如下:

           

          function TDelphiBand.ShowDW(fShow: BOOL): HResult;

          begin

            Hasfocus:=fShow;

            FocusChange(fShow);

            Result := S_OK;

          end;

           

          注意當顯示或隱藏的時候,我們還需要調用FocusChange方法通知瀏覽器焦點發生了變化。

          當IE需要關閉面板時,會調用IDeskBand的CloseDW方法,這時我們需要銷毀面板窗體,代碼實現如下:

          function TDelphiBand.CloseDW(dwReserved: DWORD): HResult;

          begin

            if BandForm <> nil then BandForm.Destroy;//為什么不是調用Free?

            Result := S_OK;

          end;

           

          用戶輸入支持

           

          實現了上面三個接口方法的的面板還是僅僅能夠用來顯示信息,如果我們需要在面板中提供一些編輯框,允許用戶輸入Email信息的話,那么還必須實現IInputObject接口。IInputObject接口有下面三個方法:

              function UIActivateIO(fActivate: BOOL; var lpMsg: TMsg): HResult; stdcall;

              function HasFocusIO: HResult; stdcall;

          function TranslateAcceleratorIO(var lpMsg: TMsg): HResult; stdcall;

           

          Internet瀏覽器會在面板被激活和失活時調用UIActivateIO方法通知面板對象,這時面板應該調用SetFocus獲得焦點。方法的fActivate表示是激活還是失活的狀態,代碼實現如下:

           

          function TDelphiBand.UIActivateIO(fActivate: BOOL; var lpMsg: TMsg): HResult;

          begin

            Hasfocus:=fActivate;

            if HasFocus then Bandform.SetFocus;

            Result := S_OK;

          end;

           

          當瀏覽器想要知道目前是哪個子窗體獲得了焦點的時候,它會調用HasFocusIO方法,如果我們的面板獲得了焦點,那么就應該返回S_OK,否則返回S_False。代碼實現如下:

          function TDelphiBand.HasFocusIO: HResult;

          begin

          Result:=Integer(not HasFocus);//S_OK對應的常數為0,所以要not 一下

          end;

           

          最后一個TranslateAcceleratorIO方法允許面板處理鍵盤快捷鍵消息,代碼實現如下:

          function TDelphiBand.TranslateAcceleratorIO(var lpMsg: TMsg): HResult;

          begin

            if (lpMsg.WParam <> VK_TAB) then begin

              TranslateMessage(lpMSg);

              DispatchMessage(lpMsg);

              Result := S_OK;

            end

            else Result := S_FALSE;

          end;

           

          右鍵菜單支持

          另 外如果我們還想在面板中顯示一個右鍵菜單以便用戶能夠快速的調用一些命令的話,如顯示一個關于窗口等。我們還需要實現IContextMenu接口。當 IE需要返回右鍵菜單項的時候,它會調用面板的IContextMenu接口的QueryContextMenu方法,這里我們向菜單添加了一個關于菜 單,下面是實現代碼:

           

          function TDelphiBand.QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst, idCmdLast, uFlags: UINT): HResult;

          begin

          //添加關于菜單

            InsertMenu(Menu, indexMenu, MF_STRING or MF_BYPOSITION, idCmdFirst , 'About...');

          //返回添加的菜單數目

            Result := 1;

          end;

           

          當菜單處于高亮狀態時,IE會調用菜單接口的GetCommandString方法獲得上下文相關幫助,并顯示在瀏覽器的狀態條上,這里我們簡單返回NOERROR,表示沒有相關幫助就可以了。

          function TDelphiBand.GetCommandString(idCmd, uType: UINT; pwReserved: PUINT; pszName: LPSTR; cchMax: UINT): HResult;

          begin

            Result := NOERROR;

          end;

          最后,當用戶點擊了菜單后,IE會調用菜單接口的InvokeCommand來實現菜單命令,我們只要簡單地顯示一個關于對話框就可以了。

          function TDelphiBand.InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult;

          begin

            //如果是被程序調用,則退出

            if (HiWord(Integer(lpici.lpVerb)) <> 0) or (LoWord(lpici.lpVerb) > 0) then

            begin

              Result := E_FAIL;

              Exit;

            end;

            case LoWord(lpici.lpVerb) of

             0: Showmessage('IE瀏覽器面板組件演示程序1.0');

            end;

            Result := NO_ERROR;

          end;

          程序界面

          COM組件基本完成之后,就該設計我們的界面的功能了。現在瀏覽很多網站時都要填寫登錄界面或者其它一些注冊 信息,非常煩瑣,所以下面我就要寫一個自動填表的工具。界面非常簡單,先放一個TCoolbar,然后放上一個列表框和一個保存按鈕和一個填表按鈕,自動 填表的過程如下:

          1.       當用戶填寫完表單信息后,點擊保存按鈕,COM組件會從頁面上獲取填寫的表單信息,并將其保存到一個配置文件中。

          2.       等用戶下回再訪問該頁面時,選中被保存的表單,然后點擊加載,COM組件就會自動填寫上次保存的信息。

          3.       考慮到很多網站的都要求輸入密碼,為了讓用戶在提交時,能看清填寫的被*號遮蔽的密碼,向導在加載表單時,會截獲提交按鈕的事件,在用戶點擊提交按鈕時,會顯示一個消息框,顯示填寫的密碼內容。

          下面是保存表單的代碼:

          //保存頁面表單內的值

          procedure TBandForm.ActionSaveExecute(Sender: TObject);
          var
            HtmlDocument: IHTMLDocument2;
            HtmlForms: IHTMLElementCollection;
            HtmlForm: IHTMLFormElement;
            FormName: WideString;
            ItemIndex, ItemName: OleVariant;
            InputElement: IHTMLInputElement;
            I: Integer;
            InputName, InputValue: string;
          begin
            HtmlDocument := IE.Document as IHTMLDocument2;
            //目前只能處理頁面的第一個表單
            HtmlForms := HtmlDocument.forms;
            if HtmlForms.Length = 0 then
              Exit;
            HtmlForm := HtmlForms.item(0, 0) as IHTMLFormElement;
            // 獲得表單的名稱
            FormName := trim(HtmlForm.Get_name);
            if (FormName = '') or FIniFile.SectionExists(FormName) then
              while True do
              begin
                FormName := Trim(InputBox('輸入表單名稱', '請輸入表單名稱', ''));
                if FormName = '' then
                begin
                  ShowMessage('表單名稱不能為空,請重新輸入');
                  continue;
                end;
                if FIniFile.SectionExists(FormName) then
                begin
                  ShowMessage('表單名稱重復,請重新輸入');
                  continue;
                end;
                break;
              end;
            for I := 0 to HtmlForm.Length - 1 do
            begin
              ItemIndex := 0;
              ItemName := I;
              if Supports(HtmlForm.item(ItemName, ItemIndex), IHTMLInputElement,
                InputElement) then
                if (InputElement.type_ = 'text') or (InputElement.type_ = 'password') then
                begin
                  InputName := InputElement.Name;
                  InputValue := InputElement.Value;
                  FIniFile.WriteString(FormName, InputName, InputValue);
                end;
            end;
            //更新ini文件
            FIniFile.UpdateFile;
            //更新界面列表框的內容
            FiniFile.ReadSections(lbForms.Items);
          end;

          保存表單內容時,首先通過IE獲得頁面的DOM接口IHtmlDocument,然后通過HtmlDocument.forms方法獲得表單域的集合,為了簡單起見,這里我們只處理頁面中的第一個表單的IHtmlFormElement接口。通過表單接口,獲得表單名稱,接著遍歷表單內的Input元素,獲得輸入元素的名稱及值并將其寫入配置文件。注意這里我們只處理了簡單的文本輸入框和密碼輸入框(通過判斷頁面元素的type_屬性),至于下拉框等頁面元素則不考慮。

          下面則是加載表單的內容的代碼:

          procedure TBandForm.ActionLoadExecute(Sender: TObject);
          var
            Section: string;
            HtmlDocument: IHTMLDocument2;
            HtmlForms: IHTMLElementCollection;
            HtmlForm: IHTMLFormElement;
            FormName: WideString;
            Name, Index: OleVariant;
            ItemIndex, ItemName: OleVariant;
            InputElement: IHTMLInputElement;
            I, J: Integer;
            InputName, InputValue: string;
          begin
            if lbForms.ItemIndex<0 then Exit;
            //加載表單內容
            Section := lbForms.Items[lbForms.ItemIndex];
            HtmlDocument := IE.Document as IHTMLDocument2;
            //只能設定第一個表單的內容
            HtmlForms := HtmlDocument.forms;
            if HtmlForms.Length = 0 then
              Exit;
            HtmlForm := HtmlForms.item(0, 0) as IHTMLFormElement;
            for I := 0 to HtmlForm.Length - 1 do
            begin
              ItemIndex := 0;
              ItemName := I;
              if Supports(HtmlForm.item(ItemName, ItemIndex), IHTMLInputElement,
                InputElement) then
                if (InputElement.type_ = 'text') or (InputElement.type_ = 'password') then
                begin
                  InputName := InputElement.Name;
                  InputValue := InputElement.Value;
                  InputElement.Set_Value(FIniFile.ReadString(Section, InputName, InputValue));
                end
                else if (InputElement.type_='submit') then
                  (InputElement as IHtmlElement).OnClick:=OleVariant(Self as IDispatch);
            end;
          end;

          加載表單的過程類似,從配置信息中讀取表單內容,并通過IHtmlInputElement接口的Set_Value方法設定相應的值,不同的地方在于判斷輸入元素的類型,如果是submit提交類型的按鈕,則截獲按鈕的OnClick事件,以便顯示自動填表功能所填寫的密碼值。為了截獲的頁面元素的OnClick事件,必須提供一個IDispatch接口用來處理點擊事件。IDispatch定義了四個方法,其中只有Invoke方法是必須的,其它方法直接返回E_NotImpl就可以了,下面就是窗體的Invoke方法:

          function TBandForm.Invoke(DispID: Integer; const IID: TGUID;
            LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo,
            ArgErr: Pointer): HResult;
          var
            Strings:TStringList;
          begin
            Strings:=TStringList.Create;
            try
              FiniFile.ReadSectionValues(lbForms.Items[lbForms.ItemIndex], Strings);
              ShowMessage(Strings.Text);
              Result:=S_OK;
            finally
              Strings.Free;
            end;
          end;

          COM組件的注冊

          實現完COM組件的功能后,剩下的就是注冊到系統中以便IE加載了,面板COM組件首先要把自己的GUID寫到注冊表中HKEY_CLASS_ROOT下,下面是具體的注冊表項:

          HKEY_CLASSES_ROOT

          CLSID

          {面板組件的CLSID GUID}

          (Default) = 顯示在查看|瀏覽器欄的菜單文本

          InProcServer32

          (Default) = DLL路徑

          ThreadingModel= Apartment

           

          同時面板還要在IE的注冊表項下填寫下面信息:

          HKEY_LOCAL_MACHINE

          Software

          Microsoft

          Internet Explorer

          Toolbar

          {面板組件的CLSID GUID}

          最后,對于IE垂直面板來說,我們還要注冊COM組件的類別:

          HKEY_CLASSES_ROOT\CLSID\<面板GUID>\

          Implemented Categories\{00021493-0000-0000-C000-000000000046}

          要注意的是從IE5開始,注冊一個新的面板,需要刪除下面的注冊表項,迫使IE重建緩存來識別新的面板。

          HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Discardable\PostSetup\

          Component Categories\{00021493-0000-0000-C000-000000000046}\Enum

          下面是DeskBand類工廠的實現代碼:

          TDelphiBandFactory = class(TComObjectFactory)

          private

              procedure AddKeys;

            procedure RemoveKeys;

          public

              procedure UpdateRegistry(Register: Boolean); override;

          end;

          procedure TDelphiBandFactory.UpdateRegistry(Register: Boolean);

          begin

            inherited UpdateRegistry(Register);

            if Register then AddKeys else RemoveKeys;

          end;

          procedure TDelphiBandFactory.AddKeys;

          var S: string;

          begin

            S := GUIDToString(CLSID_DelphiBand);

            with TRegistry.Create do

            try

          //刪除注冊表項,迫使IE重建緩存,發現新面板

          DeleteKey('Software\Microsoft\Windows\CurrentVersion\Explorer\Discardable\

          PostSetup\Component Categories\' + VerticalBand + '\Enum');

              RootKey := HKEY_CLASSES_ROOT;

              if OpenKey('CLSID\' + S, True) then

              begin

                WriteString('', '&Delphi Band');

                CloseKey;

              end;

              if OpenKey('CLSID\' + S + '\InProcServer32', True) then

              begin

                WriteString('ThreadingModel', 'Apartment');

                CloseKey;

              end;

              if OpenKey('CLSID\' + S + '\Implemented Categories\' + VerticalBand, True)

                then CloseKey;

            finally

              Free;

            end;

          end;

          procedure TDelphiBandFactory.RemoveKeys;

          var S: string;

          begin

            S := GUIDToString(CLSID_DelphiBand);

            with TRegistry.Create do

            try

              RootKey := HKEY_CLASSES_ROOT;

              DeleteKey('CLSID\' + S + '\Implemented Categories\' + VerticalBand);

              DeleteKey('CLSID\' + S + '\InProcServer32');

              DeleteKey('CLSID\' + S);

              Closekey;

            finally

              Free;

            end;

          end;

          initialization

            TDelphiBandFactory.Create(ComServer, TDelphiBand, CLSID_DelphiBand, '', Caption, ciMultiInstance);

          end.

          注冊組件之后,啟動IE,打開隨書光盤中的LoginForm.html,然后啟動面板程序,執行加載和保存功能,界面示意圖:

           

          最后

          實際上面板對象不僅僅可以應用在IE中,外殼的任務條的快捷方式工具條實際上也是面板組件,也可以采用本文提到的類似的技術來實現,除了要填寫的注冊表項內容不同外,其它大同小異,因此這里就不贅述了,有興趣的朋友直接察看MSDN就可以了。

           

          參考文獻:

          1、  Peter Larsen寫的IE面板組件例子的代碼。

          2、  MSDN。


          原文:http://www.codesky.net/article/doc/200801/2008011681208862.htm





          Android開發完全講義(第2版)(本書版權已輸出到臺灣)

          http://product.dangdang.com/product.aspx?product_id=22741502



          Android高薪之路:Android程序員面試寶典 http://book.360buy.com/10970314.html


          新浪微博:http://t.sina.com.cn/androidguy   昵稱:李寧_Lining

          posted on 2010-10-02 21:25 銀河使者 閱讀(2165) 評論(0)  編輯  收藏 所屬分類: delphi

          主站蜘蛛池模板: 济南市| 合山市| 邓州市| 青冈县| 张家界市| 莱阳市| 南皮县| 景泰县| 新丰县| 尚义县| 佳木斯市| 山阴县| 丹阳市| 陆川县| 岐山县| 仲巴县| 宕昌县| 恩平市| 宿松县| 大田县| 郸城县| 诏安县| 大石桥市| 阜宁县| 合作市| 沙洋县| 五大连池市| 元朗区| 囊谦县| 厦门市| 鄂温| 孝感市| 嘉义市| 依兰县| 桃园市| 青川县| 深州市| 镇赉县| 垦利县| 定陶县| 林芝县|