利用MFC实现浏览器的定制与扩展(JavaScript与C++交互)

原文地址: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;
	} 

	IHTMLElementPtr	pElem=NULL;
	hr = pdispReserved->QueryInterface(IID_IHTMLElement, (void**)&pElem);
	if(hr != S_OK)
	{
		oleWnd->Release();
		return S_OK;
	} 

	IHTMLElementPtr	pParentElem=NULL; 

	_bstr_t	tagID;
	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);
时间: 2024-10-14 08:27:22

利用MFC实现浏览器的定制与扩展(JavaScript与C++交互)的相关文章

利用BHO实现浏览器劫持

1.简介 BHO 全名: Browser Helper Object 即浏览器辅助对象 它是微软推出的作为浏览器对第3方程序开发的交互接口的标准. 通过这个接口就可以编写代码来拓展浏览器, 获取浏览器行为等. 因此同样给了恶意代码的可乘之机. 恶意代码可以通过注册插件等手段来对浏览器进行劫持. 借助BHO,可以写一个进程内的COM对象,这个对象在每次启动时都加载. BHO对象依托于浏览器主窗口, BHO对象与浏览器实例生命周期是一致的 此外, BHO是个COM进程内服务, 注册于注册表某一键下.

利用jQuery判断浏览器的版本和类型

利用jQuery判断浏览器的版本:现在各种版本的浏览器满天飞,不能说是一种坏事,因为版本多了就会出现竞争,能够提高产品的质量,给用户带来了好处,但是也给程序员带来了无穷的烦恼.由于不同版本的浏览器可能会对同样的代码有不同的解读,所以要根据不同的浏览器写不同的代码,所以就要对浏览器的版本和类型进行判断.代码实例如下: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta

android 下 利用webview实现浏览器功能

android 下 利用webview实现浏览器功能: 1.界面添加WEBVIEW控件. 2.在界面.JAVA代码页面(protected void onCreate(Bundle savedInstanceState) 方法中)添加如下代码: //#region WebView wb=(WebView)findViewById(R.id.Wb_Main); //设置WebView属性,能够执行Javascript脚本 wb.getSettings().setJavaScriptEnabled(

利用MFC编写计算器

端午节这两天没什么事,就用MFC写了一个简单的计算器,界面做的也比较简单,如下图1,可以进行简单的加.减.乘和除功能,小数点显示这块做的不是很好,比如输入1.2,不会一个个的显示,而是先显示"1",后同时显示".2",还有就是遇到0.00时,显示的也不够人性化,哎,就这样吧... 图1 1.建立工程:New -> Projects,选择Win32 MFC AppWizard(exe),并输入工程(counter)名字及设置好路径,点击OK,选择"Di

android利用WebView实现浏览器的封装

android提供了封装浏览器的接口,可以让开发者利用自己的view显示网页内容.今天又实现研究了一下,利用WebView显示浏览器内容,还可以利用 WebViewClient显示自己需要的内容. 参考:http://developer.android.com/reference/android/webkit/WebView.html 效果如下: 上面两张图分别是首页的截图,当点击java时的截图.可以看到在浏览器上面已经没有地址栏了.这个是利用WebViewClient显示的内容.相关代码如下

Firefox 浏览器的DOM原型扩展

我不想挑起IE与Firefox之间的争论,我只想说说Firefox浏览器有而IE里没有的一个功能,对DOM里的对象原型的扩展. 在DOM里的window.document.element.event等这些对象在Firefox(或者说Mozilla核心的浏览器)里都有与之对应的原型:Window.HTMLDocument.HTMLElement.Event等,对于这些原型扩展之后,那些window.document等对象就“自动”拥有某些成员属性或者成员方法了.举个简单的例子,比如在IE里都有一个

浏览器中的XML与JavaScript

浏览器中的XML与JavaScript 在处理XML前,你需要在JavaScript中获取它.这一部分展示了一些不同的方法用来在JavaScript中获取XML并且对它进行处理. XML的节点类型 在我们研究如何处理XML前,先来了解下XML中不同的节点及类型.如果是HTML,了解这些节点就没必要了,但由于XML的可扩展性和结构的不确定性,了解这些固有节点类型就显得犹为重要了. 下面是XML 中12种不同的节点(表格取自W3School中文站点): 节点类型 描述 Document 表示整个文档

如何利用好chrome控制台这个神器好好调试javascript代码

上面的文章已经大致介绍了一下console对象具体有哪些方面以及基本的应用,下面简单介绍一下如何利用好chrome控制台这个神器好好调试javascript代码(这个才是我们真正能用到实处的地方) 1.先说一下源码定位 大家打开测试网页   看到页面右下方有一个推荐的图标吗?右击推荐图标,选择审查元素,打开谷歌控制台,如下图所示 我们现在想知道votePost方法到底在哪?跟着我这样做,在Console面板里面输入votePost然后回车 直接点击上图标红的链接,控制台将定位到Sources面板

利用 Chromium Embedded Framework (CEF) 定制提取 Flash 视频的浏览器

功能介绍: 利用 CEF 分析网页源码, 提取 flash 视频的代码. 提取的视频代码 LoadString 和 JS 两种方式重新插入到浏览器. (CEF_3.2171.1979_win32 - Chromium Verison 39.0.2171.95 + VS2010) 按钮说明: Flash 网页全部载入后单击 Flash 按钮,提取 flash 视频的代码 Fix LoadString 方式重新插入到浏览器 JS Fix JS 方式重新插入到浏览器 SizeN 控制视频大小 (Siz