標籤:
原文地址:http://www.vckbase.com/document/viewdoc/?id=1486
瀏覽器的定製與擴充
李漢鵬
下載源代 碼
本文分如下章節:
- 前 言
- 在 MFC中使用瀏覽器
- 怎 樣擴充或定製瀏覽器
- 定 制滑鼠右鍵彈出出菜單
- 實 現指令碼擴充(很重要的external介面)
- C++ 代碼中如何調用網頁指令碼中的函數
- 定 制訊息框的標題
- 怎 樣定製、修改瀏覽器向Web伺服器發送的HTTP要求標頭
- 怎 樣修改瀏覽器標識
- 去 掉討厭的異常警告
- 怎 樣處理瀏覽器內的拖放
- 怎 樣禁止網頁元素的選取
- 其 它
前言
由於本人在開發中經常要在程式中嵌入瀏覽器,為了符合自己的需求經常要對瀏覽器進行擴充和定製, 解決這些問題需在網上找資料和學習的過程,我想可能很多開發人員或許會遇到同樣的問題,特寫此文,以供大家參考。
在MFC中使用瀏覽器
在MFC中微軟為我們提供了CHtmlView、CDHtmlDialog類讓我們的程式很方便的嵌入瀏覽器和進行瀏覽器的二次開發,這比直 接使用WebBrowser控制項要方便很多,所以本文中討論的瀏覽器的問題都是針對CHtmlView來討論的。文中將提到一個類 CLhpHtmlView, 它是CHtmlView的衍生類別,文中提及的擴充或定製都將在CLhpHtmlView類(或衍生類別)上實現。
怎樣擴充或定製瀏覽器
瀏覽器定義了一些擴充介面(如IDocHostUIHandler可以定製瀏覽器介面有關的行為),以便開發人員進行定製和擴充。瀏覽 器會在需要的時候向他的控制網站查詢這些介面,在控制網站裡實現相應的介面就可以進行相應的擴充。在MFC7.01類 庫中,CHtmlView使用的控制網站是CHtmlControlSite的,在CHtmlControlSite類中 只實現了介面IDocHostUIHandler, 而要實現更多的擴充介面,必須用自訂的控制站類來取代CHtmlControlSite,在下文中提及的類CDocHostSite即為自訂 的控制站類。
關於介面的介紹請參考:
http://dev.csdn.net/develop/article/48/48483.shtm
如何使自訂的控制網站來替換預設的控制網站呢?在MFC7.0中只需重載CHtmlView的虛函數CreateControlSite即 可:
BOOL CLhpHtmlView::CreateControlSite(COleControlContainer * pContainer, COleControlSite ** ppSite, UINT /*nID*/, REFCLSID /*clsid*/) { *ppSite = new CDocHostSite(pContainer, this);// 建立自己的控制網站執行個體 return (*ppSite) ? TRUE : FALSE; }
VC6.0要替換控制站要複雜的多,這裡就不討論了,如需要6.0版本的請給我發郵件到[email protected]。
定製滑鼠右鍵彈出出菜單
要定製瀏覽器的滑鼠右鍵快顯功能表,必須在自訂的控制網站類中實現IDocHostUIHandler2介面,並且IE的 版本是5.5或以上。在介面IDocHostUIHandler2的ShowContextMenu方法中呼叫瀏覽器類的 OnShowContextMenu虛函數,我們 在瀏覽器類的衍生類別重載此虛函數即可實現右鍵菜單的定製,參見代碼
HRESULT CDocHostSite::XDocHostUIHandler::ShowContextMenu(DWORD dwID, POINT * ppt, IUnknown * pcmdtReserved, IDispatch * pdispReserved) { METHOD_PROLOGUE(CDocHostSite, DocHostUIHandler); return pThis->m_pView->OnShowContextMenu( dwID, ppt, pcmdtReserved,pdispReserved ); } HRESULT CLhpHtmlView::OnShowContextMenu(DWORD dwID, LPPOINT ppt, LPUNKNOWN pcmdtReserved, LPDISPATCH pdispReserved) { HRESULT result = S_FALSE; switch(m_ContextMenuMode) { case NoContextMenu:// 無菜單 result=S_OK; break; case DefaultMenu:// 預設菜單 break; case TextSelectionOnly:// 僅文本選擇菜單 if(!(dwID == CONTEXT_MENU_TEXTSELECT || dwID == CONTEXT_MENU_CONTROL)) result=S_OK; break; case CustomMenu:// 自訂菜單 if(dwID!=CONTEXT_MENU_TEXTSELECT) result=OnShowCustomContextMenu(ppt,pcmdtReserved,pdispReserved); break; } return result; }
在CLhpHtmlView中定義的枚舉類型CONTEXT_MENU_MODE舉出了定製右鍵快顯功能表的四種類型
enum CONTEXT_MENU_MODE// 操作功能表 { NoContextMenu,// 無菜單 DefaultMenu,// 預設菜單 TextSelectionOnly,// 僅文本選擇菜單 CustomMenu// 自訂菜單 };
通過CLhpHtmlView的函數SetContextMenuMode來設定右鍵菜單的類型。如果設定的右鍵快顯功能表是“自訂菜單”類型, 我們只要在CLhpHtmlView的衍生類別中重載OnShowCustomContextMenu虛函數即可,如下代碼 CDemoView是CLhpHtmlView的衍生類別
HRESULT CDemoView::OnShowCustomContextMenu(LPPOINT ppt, LPUNKNOWN pcmdtReserved,LPDISPATCH pdispReserved) { if ((ppt==NULL)||(pcmdtReserved==NULL)||(pcmdtReserved==NULL)) return S_OK; HRESULT hr=0; IOleWindow *oleWnd=NULL; hr=pcmdtReserved->QueryInterface(IID_IOleWindow, (void**)&oleWnd); if((hr != S_OK)||(oleWnd == NULL)) return S_OK; HWND hwnd=NULL; hr=oleWnd->GetWindow(&hwnd); if((hr!=S_OK)||(hwnd==NULL)) { oleWnd->Release(); return S_OK; } IHTMLElementPtrpElem=NULL; hr = pdispReserved->QueryInterface(IID_IHTMLElement, (void**)&pElem); if(hr != S_OK) { oleWnd->Release(); return S_OK; } IHTMLElementPtrpParentElem=NULL; _bstr_ttagID; BOOL go=TRUE; pElem->get_id(&tagID.GetBSTR()); while(go && tagID.length()==0) { hr=pElem->get_parentElement(&pParentElem); if(hr==S_OK && pParentElem!=NULL) { pElem->Release(); pElem=pParentElem; pElem->get_id(&tagID.GetBSTR()); } else go=FALSE; }; if(tagID.length()==0) tagID="no id"; CMenu Menu,SubMenu; Menu.CreatePopupMenu(); CString strTagID = ToStr(tagID); if(strTagID == "red") Menu.AppendMenu(MF_BYPOSITION, ID_RED, "您點擊的是紅色"); else if(strTagID == "green") Menu.AppendMenu(MF_BYPOSITION, ID_GREEN, "您點擊的是綠色"); else if(strTagID == "blue") Menu.AppendMenu(MF_BYPOSITION, ID_BLUE, "您點擊的是藍色"); else Menu.AppendMenu(MF_BYPOSITION, ID_NONE, "你點了也白點,請在指定的地方點擊"); int MenuID=Menu.TrackPopupMenu(TPM_RETURNCMD|TPM_LEFTALIGN|TPM_RIGHTBUTTON,ppt->x, ppt->y, this); switch(MenuID) { case ID_RED: MessageBox("紅色"); break; case ID_GREEN: MessageBox("紅色"); break; case ID_BLUE: MessageBox("紅色"); break; case ID_NONE: MessageBox("haha"); break; } oleWnd->Release(); pElem->Release(); return S_OK; }
實現指令碼擴充(很重要的external介面)
在你嵌入了瀏覽器的工程中,如果網頁的指令碼中能調用C++代碼,那將是一件很愜意的事情,要實現這種互動,就必須實現指令碼擴充。實現指令碼擴充就是在程 序中實現一個IDispatch介面,通過CHtmlView類的OnGetExternal虛函數返回此介面指標,這樣就可以在指令碼中通過 window.external.XXX(關鍵字window可以省略)來 引用介面暴露的方法或屬性(XXX為方法或屬性名稱)。在MFC中從CCmdTarget派生的類都可以實現自動化,而不必在MFC工程中引入繁雜的 ATL。從CCmdTarget派生的類實現自動化介面的時候不要忘了在建構函式中調用EnableAutomation函數。 要使虛函數OnGetExternal發揮作用必須在 自訂的控制網站類中實現IDocHostUIHandler,在介面IDocHostUIHandler的GetExternal方法中呼叫瀏覽器類的 OnGetExternal虛函數,我們在瀏覽器類的衍生類別重載OnGetExternal虛函數, 通過參數lppDispatch返回一個IDispatch指標,這樣指令碼中引用window.external時就是引用的返回的介面,參見代碼
HRESULT CDocHostSite::XDocHostUIHandler::GetExternal(IDispatch ** ppDispatch) { METHOD_PROLOGUE(CDocHostSite, DocHostUIHandler); return pThis->m_pView->OnGetExternal( ppDispatch ); } CLhpHtmlView::CLhpHtmlView(BOOL isview) { ...... EnableAutomation();// 允許自動化 } HRESULT CLhpHtmlView::OnGetExternal(LPDISPATCH *lppDispatch) { *lppDispatch = GetIDispatch(TRUE);// 返回自身的IDispatch介面 return S_OK; }
請注意上面代碼中,在OnGetExternal返回的是自身IDispatch介面, 這樣就不比為指令碼擴充而另外寫一個從CCmdTarget派生的新類, CLhpHtmlView本身就是從CCmdTarget派生,直接在上面實現介面就是。
下用具體樣本來說明怎樣實現指令碼擴充
樣本會在網頁上點擊一個按鈕而使整個視窗發生抖動
從CLhpHtmlView派生一個類CDemoView,在類中實現IDispatch, 並通過IDispatch暴露方法WobbleWnd
--------------------------------------------------------------------------- 檔案 DemoView.h --------------------------------------------------------------------------- ....... class CDemoView : public CLhpHtmlView { ...... DECLARE_DISPATCH_MAP() // 構建dispatch映射表以暴露方法或屬性 ...... void WobbleWnd();// 抖動視窗 }; --------------------------------------------------------------------------- 檔案 DemoView.cpp --------------------------------------------------------------------------- ...... // 把成員函數映射到Dispatch映射表中,暴露方法給指令碼 BEGIN_DISPATCH_MAP(CDemoView, CLhpHtmlView) DISP_FUNCTION(CDemoView, "WobbleWnd", WobbleWnd, VT_EMPTY, VTS_NONE) END_DISPATCH_MAP() ...... void CDemoView::WobbleWnd() { // 在這裡實現抖動視窗 ...... } --------------------------------------------------------------------------- 檔案 Demo.htm --------------------------------------------------------------------------- ...... onclick="external.WobbleWnd()" ......
這裡我要介紹一下DISP_FUNCTION宏,它的作用是將一個函數映射到Dispatch映射表中,我們看
DISP_FUNCTION(CDemoView, "WobbleWnd", WobbleWnd, VT_EMPTY, VTS_NONE)
CDemoView是宿主類名, "WobbleWnd"是暴露給外面的名字(指令碼調用時使用的名字), VT_EMPTY是傳回值得類型為空白,VTS_NONE說明此方法沒有參數,如果要映射的函數有傳回值和參數該 如何映射,通過下面舉例來說明
DISP_FUNCTION(CCalendarView,"TestFunc",TestFunc,VT_BOOL,VTS_BSTR VTS_I4 VTS_I4) BOOL TestFunc(LPCSTR param1, int param2, int param3) { ..... }
參數表VTS_BSTR VTS_I4 VTS_I4是用空格分隔,他們的類型映射請參考MSDN,這要提醒的是不要把VTS_BSTR與CString對應,而應與LPCSTR對應。
C++代碼中如何調用網頁指令碼中的函數
IHTMLDocument2::scripts屬性工作表示HTML文檔中所有指令碼對象。使用指令碼對象的IDispatch介面的 GetIDsOfNames方法可以得到指令碼函數的 DispID,得到DispID後,使用IDispatch的Invoke函數可以調用對應的指令碼函數。CLhpHtmlView提供了方便的調用 JavaScript的函數,請參考CLhpHtmlView中有關鍵字“JScript”的代碼。
定製訊息框的標題
我們在指令碼中調用alert彈出訊息框時,訊息框的標題是微軟預定義的“Microsoft Internet Explorer”,如:
在自訂的控制網站類中實現IDocHostShowUI介面,在介面的ShowMessage方法中呼叫瀏覽器的OnShowMessage,我們 重載 OnShowMessage虛函數即可定製訊息框的標題,實現代碼如下:
// 視窗標題"Microsoft Internet Explorer"的資源標識 #define IDS_MESSAGE_BOX_TITLE 2213 HRESULT CLhpHtmlView::OnShowMessage(HWND hwnd, LPOLESTR lpstrText, LPOLESTR lpstrCaption, DWORD dwType, LPOLESTR lpstrHelpFile, DWORD dwHelpContext, LRESULT * plResult) { //載入Shdoclc.dll 和IE訊息框標題字串 HINSTANCE hinstSHDOCLC = LoadLibrary(TEXT("SHDOCLC.DLL")); if (hinstSHDOCLC == NULL) return S_FALSE; CString strBuf,strCaption(lpstrCaption); strBuf.LoadString(hinstSHDOCLC, IDS_MESSAGE_BOX_TITLE); // 比較IE訊息框標題字串和lpstrCaption // 如果相同,用自訂標題替換 if(strBuf==lpstrCaption) strCaption = m_DefaultMsgBoxTitle; // 建立自己的訊息框並且顯示 *plResult = MessageBox(CString(lpstrText), strCaption, dwType); //卸載Shdoclc.dll並且返回 FreeLibrary(hinstSHDOCLC); return S_OK; }
從代碼中可以看到通過設定m_DefaultMsgBoxTitle的值來改變訊息寬的標題,修改此值是同過SetDefaultMsgBoxTitle 來實現
void CLhpHtmlView::SetDefaultMsgBoxTitle(CString strTitle) { m_DefaultMsgBoxTitle=strTitle; }
怎樣定製、修改瀏覽器向Web伺服器發送的HTTP要求標頭
在整合了WebBrowser控制項的應用中,Web伺服器有時可能希望用戶端(瀏覽器)發送的HTTP請求中附帶一些額外的資訊或自訂的 HTTP頭欄位,這樣就必須在瀏覽器中控制向Web伺服器發送的HTTP請求。 下面是捕獲的一個普通的用瀏覽器發送的HTTP要求標頭:
GET /text7.htm HTTP/1.0 Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, / application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */* Referer: http://localhost Accept-Language: en-us User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Poco 0.31; LHP Browser 1.01; / .NET CLR 1.1.4322) Host: localhost Connection: Keep-Alive CHtmlView的 void Navigate2( LPCTSTR lpszURL, DWORD dwFlags = 0, LPCTSTR lpszTargetFrameName = NULL, LPCTSTR lpszHeaders = NULL, LPVOID lpvPostData = NULL, DWORD dwPostDataLen = 0 );
函數參數lpszHeaders可以指定HTTP要求標頭,樣本如下:
Navigate2(_T("http://localhost"),NULL,NULL, "MyDefineField: TestValue");
我們捕獲的HTTP頭如下:
怎樣修改瀏覽器標識
在HTTP要求標頭中User-Agent欄位表明了瀏覽器的版本以及作業系統的版本等資訊。WEB伺服器經常需要知道使用者請求頁面時是來自IE還是來 自自己的用戶端中的WebBrowser控制項, 以便分開處理,而WebBrowser控制項向WEB伺服器發送的瀏覽器標識(User-Agent欄位)跟用IE發送的是一樣的,怎樣區分自己的瀏覽器和 IE呢? 微軟沒有提供現成的方法,要自己想法解決。 前面討論的定製HTTP要求標頭就是為這一節準備的。 思路是這樣的: 在自己的瀏覽器裡處理每一個U頁面請求,把要求標頭User-Agent改成自己想要的。 在CHtmlView的OnBeforeNavigate2虛函數裡來修改HTTP請求是再好不過了,
#define WM_NVTO(WM_USER+1000) class NvToParam { public: CString URL; DWORD Flags; CString TargetFrameName; CByteArray PostedData; CString Headers; }; void CDemoView::OnBeforeNavigate2(LPCTSTR lpszURL, DWORD nFlags, LPCTSTR lpszTargetFrameName, CByteArray& baPostedData, LPCTSTR lpszHeaders, BOOL* pbCancel) { CString strHeaders(lpszHeaders); if(strHeaders.Find("User-Agent:LHPBrowser 1.0") < 0)// 檢查頭裡有沒有自訂的User-Agent串 { *pbCancel = TRUE;// 沒有,取消這次導航 if(!strHeaders.IsEmpty()) strHeaders += "/r/n"; strHeaders += "User-Agent:LHPBrowser 1.0";// 加上自訂的User-Agent串 NvToParam* pNvTo = new NvToParam; pNvTo->URL = lpszURL; pNvTo->Flags = nFlags; pNvTo->TargetFrameName = lpszTargetFrameName; baPostedData.Copy(pNvTo->PostedData); pNvTo->Headers = strHeaders; // 發送一個自訂的導航訊息,並把參數發過去 PostMessage(WM_NVTO,(WPARAM)pNvTo); return; } CHtmlView::OnBeforeNavigate2(lpszURL, nFlags, lpszTargetFrameName, baPostedData, lpszHeaders, pbCancel); } LRESULT CDemoView::OnNvTo(WPARAM wParam, LPARAM lParam) { NvToParam* pNvTo = (NvToParam*)wParam; Navigate2((LPCTSTR)pNvTo->URL, pNvTo->Flags, pNvTo->PostedData, (LPCTSTR)pNvTo->TargetFrameName, (LPCTSTR)pNvTo->Headers); delete pNvTo; return 1; }
在OnBeforeNavigate2中如果發現沒有自訂的User-Agent串,就加上這個串,並取消本次導航,再Post一個訊息(一定要 POST,讓OnBeforeNavigate2跳出以後再進行導航 ),在訊息中再次導航,再次導航時要求標頭已經有了自己的標識,所以能正常的導航。
去掉討厭的異常警告
在程式中使用了CHtmlView以後,我們在調整視窗大小的時候經常會看到輸出視窗輸出的異常警告: ReusingBrowser.exe 中的 0x77e53887 處最可能的異常: Microsoft C++ exception: COleException @ 0x0012e348 。
Warning: constructing COleException, scode = DISP_E_MEMBERNOTFOUND($80020003).
這是由於CHtmlView在處理WM_SIZE訊息時的一點小問題引起的,採用如下代碼處理WM_SIZE訊息就不會有此警告了
void CLhpHtmlView::OnSize(UINT nType, int cx, int cy) { CFormView::OnSize(nType, cx, cy); if (::IsWindow(m_wndBrowser.m_hWnd)) { CRect rect; GetClientRect(rect); // 就這一句與CHtmlView的不同 ::AdjustWindowRectEx(rect, GetStyle(), FALSE, WS_EX_CLIENTEDGE); m_wndBrowser.SetWindowPos(NULL, rect.left, rect.top, rect.Width(), rect.Height(), SWP_NOACTIVATE | SWP_NOZORDER); } }
怎樣處理瀏覽器內的拖放
有時可能有這樣的需求,我們希望在資源管理員裡托一個檔案到瀏覽器而做出相應的處理,甚至是將檔案拖到某一個網頁元素上來做出相應的處理,而瀏覽器默 認的處理拖放檔案操作是將檔案開啟,但WebBrowser控制項給了我們一個自己處理拖放的機會。 那就是在自訂的控制網站類中實現IDocHostUIHandler,在介面IDocHostUIHandler的GetDropTarget方法中調 用 瀏覽器類的OnGetDropTarget虛函數。要處理網頁內的拖放,必需在OnGetDropTarget函數中返回一個自己定義的 IDropTarget介面指標, 所以我們自己寫一個類CMyOleDropTarget從COleDropTarget類派生,並且在實現IDropTarget介面,此類的代碼在這就 不列出了,請下載示範 程式,參考檔案MyOleDropTarget.h和MyOleDropTarget.cpp。我們看CLhpHtmlView中 OnGetDropTarget的代碼
HRESULT CLhpHtmlView::OnGetDropTarget(LPDROPTARGET pDropTarget, LPDROPTARGET* ppDropTarget ) { m_DropTarget.SetIEDropTarget(pDropTarget); LPDROPTARGET pMyDropTarget; pMyDropTarget = (LPDROPTARGET)m_DropTarget.GetInterface(&IID_IDropTarget); if(pMyDropTarget) { *ppDropTarget = pMyDropTarget; pMyDropTarget->AddRef(); return S_OK; } return S_FALSE; }
m_DropTarget即為自訂的處理拖放的對象。這樣就能通過在從CLhpHtmlView派生的類中重載OnDragEnter、 OnDragOver、 OnDrop、OnDragLeave虛函數來處理拖放了。在這裡順帶講一下視圖是怎樣處理拖放的。 要使視圖處理拖放,首先在視圖裡添加一個COleDropTarget(或衍生類別)成員變數,如CLhpHtmlView中的 “CMyOleDropTarget m_DropTarget;”,再在 視圖建立時調用COleDropTarget對象的Register,即把視圖與COleDropTarget對象關聯起來,如CLhpHtmlView 中的“m_DropTarget.Register(this);”,再對拖放 觸發的事件進行相應的處理, OnDragEnter 把某對象拖入到視圖時觸發,在此檢測拖入的對象是不是視圖想接受的對象,如是返回“DROPEFFECT_MOVE”表示接受此對象,如
if(pDataObject->IsDataAvailable(CF_HDROP))// 被拖對象是檔案嗎? return DROPEFFECT_MOVE;
OnDragOver 被拖對象在視圖上移動,同OnDragEnter一樣檢測拖入對象,如果要接受此對象返回“DROPEFFECT_MOVE”。 OnDrop 拖著被拖對象在視圖上放開滑鼠,在這裡對拖入對象做出處理; OnDragLeave 拖著被拖對象離開視圖。 C++的代碼寫好了,但事情還沒完,還必須在網頁裡用指令碼對拖放事件進行處理, 即頁面裡哪個元素要接受拖放對象哪個元素就要處理ondragenter、ondragover、ondrop,代碼其實很簡單,讓事件的傳回值為 false即可,這樣 C++的代碼才有機會處理拖放事件,代碼如下:
...... <td ondragenter="event.returnValue = false" ondragover="event.returnValue = false" / ondrop="event.returnValue = false"> ......
如果要使整個視圖都接受拖放,則在Body元素中處理此三個事件。 注意:別忘了讓工程對OLE的支援即在初始化應用程式時調用AfxOleInit()。
怎樣禁止網頁元素的選取
用網頁做介面時多數情況下是不希望網頁上的元素是能夠被滑鼠選中的, 要使網頁元素不能被選中做法是:給瀏覽器的“宿主資訊標記”加上DOCHOSTUIFLAG_DIALOG標記。
“宿主資訊標記”用N個標記位來控制瀏覽器的許多性質,如:
- 禁用瀏覽器的3D的邊緣;
- 禁止捲軸;
- 禁用指令碼;
- 定義雙擊處理的方式;
- 禁用瀏覽器的自動完成功能;
...... 更多詳情請參考MSDN的DOCHOSTUIFLAG協助。
怎樣修改“宿主資訊標記”?
在CDocHostSite中實現IDocHostUIHandler, 在GetHostInfo方法中呼叫瀏覽器的OnGetHostInfo虛函數,在虛函數OnGetHostInfo中便可指定“宿主資訊標記”,如:
HRESULT CLhpHtmlView::OnGetHostInfo(DOCHOSTUIINFO * pInfo) { pInfo->cbSize = sizeof(DOCHOSTUIINFO); pInfo->dwFlags = DOCHOSTUIFLAG_DIALOG | DOCHOSTUIFLAG_THEME | DOCHOSTUIFLAG_NO3DBORDER | DOCHOSTUIFLAG_SCROLL_NO; pInfo->dwDoubleClick = DOCHOSTUIDBLCLK_DEFAULT; return S_OK; }
用指令碼也可實現: 在Head中加入指令碼:
document.onselectstart=new Function(‘‘return false‘‘);
或者
<body onselectstart="return false">。
其它
在CLhpHtmlView中還提供了幾個函數, 修改網頁元素的內容:
BOOL PutElementHtml(CString ElemID,CString Html);
取表單元素的值:
BOOL GetElementValue(CString ElemID,CString& Value);
設定表單元素的值:
BOOL PutElementValue(CString ElemID,CString Value);
給表單元素設定焦點:
void ElementSetFocus(CString EleName);
利用MFC實現瀏覽器的定製與擴充(JavaScript與C++互動)