隨筆 - 312, 文章 - 14, 評(píng)論 - 1393, 引用 - 0
          數(shù)據(jù)加載中……

          自動(dòng)填表的IE面板插件

          簡介

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

           

          此外我們還可以通過實(shí)現(xiàn)COM組件來添加我們自己的瀏覽器面板到IE中。當(dāng)我們的面板COM組件注冊(cè)后,它會(huì)被添加到瀏覽器的查看菜單的瀏覽器欄的子菜單下。當(dāng)用戶選中該菜單項(xiàng)后,該面板就會(huì)顯示在瀏覽器中。

          實(shí)現(xiàn)面板COM組件

              接下來我們將實(shí)現(xiàn)類似于IE內(nèi)置的收藏夾的一個(gè)面板,不過它不是用來收藏網(wǎng)址的,而是用來運(yùn)行程序的。下面是它的示意圖:

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

          首先選擇菜單File | New | ActiveX | Com Object命令,創(chuàng)建一個(gè)TDelphiBand的COM組件框架

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

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

          begin

            classID := CLSID_DelphiBand;

            Result := S_OK;

          end;

          IObjectWithSite接口,顧 名思義這個(gè)接口就是一個(gè)嵌入在COM容器中的組件需要實(shí)現(xiàn)的接口,當(dāng)用戶選中一個(gè)瀏覽器面板的時(shí)候,IE這個(gè)COM容器會(huì)調(diào)用面板組件的 IObjectWithSite的SetSite方法,這個(gè)方法傳遞過來的punkSite參數(shù)就是COM容器的IUnknown接口,通過這個(gè)接口我們 可以獲得IE提供的各個(gè)COM接口,進(jìn)而可以調(diào)用IE提供的所有功能。這個(gè)方法的一般實(shí)現(xiàn)是:

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

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

          下面是SetSite方法的實(shí)現(xiàn)代碼:

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

          begin

            if Assigned(pUnkSite) then begin

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

          //面板焦點(diǎn)的變化情況

              Site := pUnkSite as IInputObjectSite;

          //通過調(diào)用GetWindow來獲得父窗體的句柄,并保存

          (pUnkSite as IOleWindow).GetWindow(ParentWnd);

          //獲得IEIWebBrowser2接口

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

            end;

            Result := S_OK;

          end;

           

          IObjectWithSite還有一個(gè)GetSite方法也需要實(shí)現(xiàn),方法的定義如下:

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

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

          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接口就是我們面板組件所要實(shí)現(xiàn)的核心接口了。它包括下面這些方法。

              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 方法系統(tǒng)也從來不會(huì)調(diào)用,因此我們也返回E_NOTIMPL。

           

          獲得面板的顯示信息

           

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

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

          begin

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

          begin

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

          BandForm := TBandForm.CreateParented(ParentWnd);

          //將IE賦值給面板界面的相應(yīng)變量

          BandForm.IE:=IE;

            End;

            //返回子窗體的句柄

            Wnd := Bandform.Handle;

            SavedWndProc := Bandform.WindowProc;

            //替換默認(rèn)的窗體消息過程

            Bandform.WindowProc := BandWndProc;

            Result := S_OK;

          end;

           

          此外,因?yàn)槊姘鍖?duì)象是以子窗體的形式顯示,它還必須實(shí)現(xiàn)窗口消息過程。這里我們使用BandWndProc過程替換了窗體默認(rèn)的消息處理過程,BandWndProc的實(shí)現(xiàn)如下:

           

          procedure TDelphiBand.BandWndProc(var Message: TMessage);

          begin

            //當(dāng)我們的窗體的子控件,如編輯框獲得焦點(diǎn)后,系統(tǒng)會(huì)發(fā)WM_ParentNotify消息給

            //我們的窗體,這時(shí)要通知瀏覽器我們面板獲得了焦點(diǎn),這樣IE才會(huì)將快捷鍵發(fā)送給

            //我們的窗體

            if (Message.Msg = WM_PARENTNOTIFY)  then

            begin

              Hasfocus:=True;

              FocusChange(True);

            end;

            //然后調(diào)用保存的原有窗體消息過程來處理

            SavedWndProc(Message);

          end;

           

          FocuseChanged方法用來通知瀏覽器焦點(diǎn)的變化情況,實(shí)現(xiàn)如下:

          procedure TDelphiBand.FocusChange(bHasFocus: Boolean);

          begin

          //調(diào)用先前保存的IInputObjectSiteOnFocusChangeIS方法通知瀏覽器

          //焦點(diǎn)變化。

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

          end;

           

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

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

          其中dwBandID參數(shù)是面板的標(biāo)識(shí)符,這個(gè)標(biāo)識(shí)符是COM容器賦予的,我們需要保存這個(gè)ID。dwViewMode表示面板的顯示模式:

           

          DBIF_VIEWMODE_FLOATING

          浮動(dòng)面板

          DBIF_VIEWMODE_NORMAL

          水平面板

          DBIF_VIEWMODE_TRANSPARENT

          面板是透明的

          DBIF_VIEWMODE_VERTICAL

          面板是垂直面板

           

          pdbi參數(shù)則是一個(gè)TDESKBANDINFO 結(jié)構(gòu),結(jié)構(gòu)定義如下:

            DESKBANDINFO = packed record

              dwMask: DWORD;

              ptMinSize: TPointL;

              ptMaxSize: TPointL;

              ptIntegral: TPointL;

              ptActual: TPointL;

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

              dwModeFlags: DWORD;

              crBkgnd: COLORREF;

            end;

          下表是關(guān)于結(jié)構(gòu)中各個(gè)成員的詳細(xì)說明:

           

          dwMask

          指定被請(qǐng)求的面板信息的掩碼,是下面參數(shù)的組合。

          DBIM_MINSIZE

          請(qǐng)求面板最小尺寸信息

          DBIM_MAXSIZE

          請(qǐng)求面板最大尺寸信息

          DBIM_INTEGRAL

          請(qǐng)求面板尺寸改變的幅度信息

          DBIM_ACTUAL

          請(qǐng)求面板默認(rèn)尺寸信息

          DBIM_TITLE

          請(qǐng)求面板標(biāo)題信息

          DBIM_MODEFLAGS

          請(qǐng)求dwModeFlags參數(shù)代表的額外的面板顯示信息

          DBIM_BKCOLOR

          請(qǐng)求面板背景色信息

          ptMinSize

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

          ptMaxSize

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

          ptIntegral

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

          ptActual

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

          wszTitle

          返回面板的標(biāo)題

          dwModeFlags

          返回下面顯示方式的組合

          DBIMF_NORMAL

          缺省的顯示模式

          DBIMF_VARIABLEHEIGHT

          面板的高度可以被改變。

          DBIMF_DEBOSSED

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

          DBIMF_BKCOLOR

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

          crBkgnd

          背景色

          當(dāng)系統(tǒng)調(diào)用GetBandInfo方法后,我們只要根據(jù)系統(tǒng)請(qǐng)求返回相應(yīng)的面板信息就可以了,代碼實(shí)現(xiàn)如下:

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

          begin

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

            BandId := dwBandID;

            //如果請(qǐng)求最小尺寸,則窗體的最小寬度是窗體設(shè)計(jì)時(shí)的寬度

            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;

            //默認(rèn)尺寸為窗體設(shè)計(jì)尺寸,注意我們這里的面板是垂直面板,因此x對(duì)應(yīng)的高度

            //y對(duì)應(yīng)的是寬度

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

          begin

              pdbi.ptActual.x := Bandform.Height;

              pdbi.ptActual.y := bandform.Width;

            end; 

          //面板的寬度可調(diào)

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

            begin

              pdbi.dwModeFlags := DBIMF_VARIABLEHEIGHT;

            end;

            //忽略背景色的設(shè)置,因?yàn)?/em>Delphi的窗體背景色是VCL自己畫的,不使用

            //Windows默認(rèn)顏色

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

            begin

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

            end;

            //返回面板的標(biāo)題,注意返回的字符串必須是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;

           

          當(dāng)面板需要顯示或隱藏的時(shí)候系統(tǒng)會(huì)調(diào)用IDeskBand接口的ShowDW方法通知面板改變窗體的顯示狀態(tài),方法的fShow布爾參數(shù)表示需要顯示還是隱藏窗體,代碼實(shí)現(xiàn)如下:

           

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

          begin

            Hasfocus:=fShow;

            FocusChange(fShow);

            Result := S_OK;

          end;

           

          注意當(dāng)顯示或隱藏的時(shí)候,我們還需要調(diào)用FocusChange方法通知瀏覽器焦點(diǎn)發(fā)生了變化。

          當(dāng)IE需要關(guān)閉面板時(shí),會(huì)調(diào)用IDeskBand的CloseDW方法,這時(shí)我們需要銷毀面板窗體,代碼實(shí)現(xiàn)如下:

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

          begin

            if BandForm <> nil then BandForm.Destroy;//為什么不是調(diào)用Free?

            Result := S_OK;

          end;

           

          用戶輸入支持

           

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

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

              function HasFocusIO: HResult; stdcall;

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

           

          Internet瀏覽器會(huì)在面板被激活和失活時(shí)調(diào)用UIActivateIO方法通知面板對(duì)象,這時(shí)面板應(yīng)該調(diào)用SetFocus獲得焦點(diǎn)。方法的fActivate表示是激活還是失活的狀態(tài),代碼實(shí)現(xiàn)如下:

           

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

          begin

            Hasfocus:=fActivate;

            if HasFocus then Bandform.SetFocus;

            Result := S_OK;

          end;

           

          當(dāng)瀏覽器想要知道目前是哪個(gè)子窗體獲得了焦點(diǎn)的時(shí)候,它會(huì)調(diào)用HasFocusIO方法,如果我們的面板獲得了焦點(diǎn),那么就應(yīng)該返回S_OK,否則返回S_False。代碼實(shí)現(xiàn)如下:

          function TDelphiBand.HasFocusIO: HResult;

          begin

          Result:=Integer(not HasFocus);//S_OK對(duì)應(yīng)的常數(shù)為0,所以要not 一下

          end;

           

          最后一個(gè)TranslateAcceleratorIO方法允許面板處理鍵盤快捷鍵消息,代碼實(shí)現(xiàn)如下:

          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;

           

          右鍵菜單支持

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

           

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

          begin

          //添加關(guān)于菜單

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

          //返回添加的菜單數(shù)目

            Result := 1;

          end;

           

          當(dāng)菜單處于高亮狀態(tài)時(shí),IE會(huì)調(diào)用菜單接口的GetCommandString方法獲得上下文相關(guān)幫助,并顯示在瀏覽器的狀態(tài)條上,這里我們簡單返回NOERROR,表示沒有相關(guān)幫助就可以了。

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

          begin

            Result := NOERROR;

          end;

          最后,當(dāng)用戶點(diǎn)擊了菜單后,IE會(huì)調(diào)用菜單接口的InvokeCommand來實(shí)現(xiàn)菜單命令,我們只要簡單地顯示一個(gè)關(guān)于對(duì)話框就可以了。

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

          begin

            //如果是被程序調(diào)用,則退出

            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組件基本完成之后,就該設(shè)計(jì)我們的界面的功能了。現(xiàn)在瀏覽很多網(wǎng)站時(shí)都要填寫登錄界面或者其它一些注冊(cè) 信息,非常煩瑣,所以下面我就要寫一個(gè)自動(dòng)填表的工具。界面非常簡單,先放一個(gè)TCoolbar,然后放上一個(gè)列表框和一個(gè)保存按鈕和一個(gè)填表按鈕,自動(dòng) 填表的過程如下:

          1.       當(dāng)用戶填寫完表單信息后,點(diǎn)擊保存按鈕,COM組件會(huì)從頁面上獲取填寫的表單信息,并將其保存到一個(gè)配置文件中。

          2.       等用戶下回再訪問該頁面時(shí),選中被保存的表單,然后點(diǎn)擊加載,COM組件就會(huì)自動(dòng)填寫上次保存的信息。

          3.       考慮到很多網(wǎng)站的都要求輸入密碼,為了讓用戶在提交時(shí),能看清填寫的被*號(hào)遮蔽的密碼,向?qū)г诩虞d表單時(shí),會(huì)截獲提交按鈕的事件,在用戶點(diǎn)擊提交按鈕時(shí),會(huì)顯示一個(gè)消息框,顯示填寫的密碼內(nèi)容。

          下面是保存表單的代碼:

          //保存頁面表單內(nèi)的值

          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;
            //目前只能處理頁面的第一個(gè)表單
            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('輸入表單名稱', '請(qǐng)輸入表單名稱', ''));
                if FormName = '' then
                begin
                  ShowMessage('表單名稱不能為空,請(qǐng)重新輸入');
                  continue;
                end;
                if FIniFile.SectionExists(FormName) then
                begin
                  ShowMessage('表單名稱重復(fù),請(qǐng)重新輸入');
                  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;
            //更新界面列表框的內(nèi)容
            FiniFile.ReadSections(lbForms.Items);
          end;

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

          下面則是加載表單的內(nèi)容的代碼:

          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;
            //加載表單內(nèi)容
            Section := lbForms.Items[lbForms.ItemIndex];
            HtmlDocument := IE.Document as IHTMLDocument2;
            //只能設(shè)定第一個(gè)表單的內(nèi)容
            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;

          加載表單的過程類似,從配置信息中讀取表單內(nèi)容,并通過IHtmlInputElement接口的Set_Value方法設(shè)定相應(yīng)的值,不同的地方在于判斷輸入元素的類型,如果是submit提交類型的按鈕,則截獲按鈕的OnClick事件,以便顯示自動(dòng)填表功能所填寫的密碼值。為了截獲的頁面元素的OnClick事件,必須提供一個(gè)IDispatch接口用來處理點(diǎn)擊事件。IDispatch定義了四個(gè)方法,其中只有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組件的注冊(cè)

          實(shí)現(xiàn)完COM組件的功能后,剩下的就是注冊(cè)到系統(tǒng)中以便IE加載了,面板COM組件首先要把自己的GUID寫到注冊(cè)表中HKEY_CLASS_ROOT下,下面是具體的注冊(cè)表項(xiàng):

          HKEY_CLASSES_ROOT

          CLSID

          {面板組件的CLSID GUID}

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

          InProcServer32

          (Default) = DLL路徑

          ThreadingModel= Apartment

           

          同時(shí)面板還要在IE的注冊(cè)表項(xiàng)下填寫下面信息:

          HKEY_LOCAL_MACHINE

          Software

          Microsoft

          Internet Explorer

          Toolbar

          {面板組件的CLSID GUID}

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

          HKEY_CLASSES_ROOT\CLSID\<面板GUID>\

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

          要注意的是從IE5開始,注冊(cè)一個(gè)新的面板,需要?jiǎng)h除下面的注冊(cè)表項(xiàng),迫使IE重建緩存來識(shí)別新的面板。

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

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

          下面是DeskBand類工廠的實(shí)現(xiàn)代碼:

          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

          //刪除注冊(cè)表項(xiàng),迫使IE重建緩存,發(fā)現(xiàn)新面板

          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.

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

           

          最后

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

           

          參考文獻(xiàn):

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

          2、  MSDN。


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





          Android開發(fā)完全講義(第2版)(本書版權(quán)已輸出到臺(tái)灣)

          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 銀河使者 閱讀(2172) 評(píng)論(0)  編輯  收藏 所屬分類: delphi

          主站蜘蛛池模板: 吕梁市| 波密县| 抚顺县| 水富县| 双流县| 上思县| 澄江县| 闽侯县| 余干县| 通江县| 衢州市| 托克逊县| 嵊泗县| 鹤壁市| 洪泽县| 巴青县| 绩溪县| 锡林郭勒盟| 云和县| 榆林市| 诏安县| 昆明市| 新竹县| 连云港市| 岳池县| 米易县| 梁山县| 贞丰县| 梅州市| 抚州市| 繁昌县| 稻城县| 瓦房店市| 杭锦后旗| 绥中县| 云龙县| 张北县| 洞口县| 卢龙县| 三河市| 贵阳市|