自動(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);
//獲得IE的IWebBrowser2接口
(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)用先前保存的IInputObjectSite的OnFocusChangeIS方法通知瀏覽器
//焦點(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