Posted: September 21, 2007 at 6:47 pm | Tags: blog, cache, html, linux, openssl, redhat, server, unix, web
转至: http://blog.csdn.net/baitianhai/archive/2004/10/27/155461.aspx
最近在鼓捣redhat linux,想自己以源代码方式安装软件,不想用rpm方式安装。
首先从httpd开始,先卸载在安装倒是比较容易,不过后来像添加ssl功能,发现编译的时候需要用openssl的安装目录,本人比较愚笨,一顿好找也没有找到,于是就想把openssl也以源代码方式安装。先卸载,此时出现问题,系统好多东西依赖于openssl的库,我查了好多资料也没找到什么办法,于是我最后一狠心,用rpm -e –nodeps给卸载了,然后手动安装了openssl,然后重新启动,这下坏了,好多服务都起不来了,smb,ssh等等,图形模式也起不来了,我欲哭无泪。
因为我是在虚拟机上安装的,smb起不来了,我只能重新安装系统了。这次安装我大多数东西都没选择,一路安装完毕,结果在文本方式发现vi编辑没有颜色了,哎,也不知道是少装了那个东西弄得(各位谁知道麻烦告诉告诉我一下),只能按照猜测重新安装了又添加了一些东西。不过幸运的vi高亮显示功能又有了,遗憾的是具体是那个软件我还是不清楚。有了上次的教训我不敢轻易卸掉系统原来的openssl了,我从网上搜索到了一篇安装openssl的英文文章,地址在 http://www.devside.net/web/server/linux/openssl 我按照上面说的安装了zlib,openssl。步骤简介如下(怕以后忘了)
安装zlib
Home : http://www.gzip.org/zlib/
Package(linux source) : http://www.gzip.org/zlib/
Our Configuration
Install to : /usr/local
Module types : dynamically and staticly loaded modules, *.so and *.a
Build Instructions
zlib library files are placed into /usr/local/lib and zlib header files are placed into /usr/local/include, by default.
Build static libraries
…/zlib-1.2.1]# ./configure
…/zlib-1.2.1]# make test
…/zlib-1.2.1]# make install
Build shared libraries
…/zlib-1.2.1]# make clean
…/zlib-1.2.1]# ./configure –shared
…/zlib-1.2.1]# make test
…/zlib-1.2.1]# make install
…/zlib-1.2.1]# cp zutil.h /usr/local/include
…/zlib-1.2.1]# cp zutil.c /usr/local/include
/usr/local/lib should now contain…
libz.a
libz.so -> libz.so.1.2.1
libz.so.1 -> libz.so.1.2.1
libz.so.1.2.1
/usr/local/include should now contain…
zconf.h
zlib.h
zutil.h
[Optional] Instructions for non-standard placement of zlib
Create the directory that will contain zlib
…/zlib-1.2.1]# mkdir /usr/local/zlib
Follow the given procedure above, except
…/zlib-1.2.1]# ./configure –prefix=/usr/local/zlib
Update the Run-Time Linker
/etc/ld.so.cache will need to be updated with the new zlib shared lib: libz.so.1.2.1
For standard zlib installation…
Add /usr/local/lib to /etc/ld.so.conf, if specified path is not present
/etc]# ldconfig
If zlib was installed with a prefix…
Add /usr/local/zlib/lib to /etc/ld.so.conf
/etc]# ldconfig
安装openssl
Download
Home : http://www.openssl.org/
Package(source) : openssl-0.9.7d.tar.gz
Our Configuration
install to : /usr/local/ssl
module types : dynamically and staticly loaded modules, *.so *.a
Build Instructions
…/openssl-0.9.7d]# ./config
–prefix=/usr/local/ssl
[default location]
shared
[in addition to the usual static libraries, create shared libraries]
zlib-dynamic
[like "zlib", but has OpenSSL load the zlib library dynamically when needed]
…/openssl-0.9.7d]# ./config -t
[display guess on system made by ./config]
…/openssl-0.9.7d]# make
…/openssl-0.9.7d]# make test
…/openssl-0.9.7d]# make install
Update the Run-time Linker
ld.so.cache will need to be updated with the location of the new OpenSSL shared libs: libcrypto.so.0.9.7 and libssl.so.0.9.7
Sometimes it is sufficient to just add these two files to /lib, but we recommend you follow these instructions instead.
Edit /etc/ld.so.conf
Add /usr/local/ssl/lib to the bottom.
…]# ldconfig
Update the PATH
Edit /root/.bash_profile
Add /usr/local/ssl/bin to the PATH variable.
Re-login
Testing
…]# openssl version
Should display OpenSSL 0.9.7d 17 Mar 2004
If an older version is shown, your system contains a previously installed OpenSSL.
Repeate the steps in Update the PATH, except place the specified location at the start of the PATH variable.
[the older openssl, on most systems, is located under /usr/bin]
[the command 'which openssl' should display the path of the openssl that your system is using]
/usr/local/ssl/bin]# ./openssl version should display the correct version.
但是我最后没有得到想要的结果,系统原来的openssl还是没能卸载掉,我该怎么做那?我继续搜索资料,哈,幸运的我找了,在一个国内论坛上是这么说的
cd /usr/local/ssl/lib
ln -s libcrypto.so.0.9.7 libcrypto.so.2
ln -s libssl.so.0.9.7 libssl.so.2
//最后要刷新系统的动态连接库配置
echo /usr/local/ssl/lib >> /etc/ld.so.conf
ldconfig -v
这下子我豁然开朗,原来依赖的那2个文件是个软链接啊,我把它修改为我现在真正的openssl库文件不是就行了吗?于是一顿忙碌后,我终于执行了 rpm -e -nodeps ,然后重新启动系统,一路运行下去,全是绿灯。一时间感觉自己好幸福啊
为了这个问题我查了国内的几个比较大的unix/linux网站都没找到资料,不过从这里http://bbs.netbuddy.org/unix/737.html还是找到了(国外的E文大概意思能看懂,但是查找起来还是没找到,也不知道这方面好点的网站),
Posted: May 21, 2007 at 10:53 am | Tags: html, ie, shell, web, windows, 开发, 技术, 浏览器, 类
内容
实现和IE浏览器交互的几种方法的介绍
—- 1.引言
—- 如何实现对IE浏览器中对象的操作是一个很有实际意义问题,通过和IE绑定的DLL我们可以记录IE浏览过的网页的顺序,分析用户的使用行为和模式。我们可以对网页的内容进行过滤和翻译,可以自动填写网页中经常需要用户填写的Form内容等等,我们所有的例子代码都是通过VC来表示的,采用的原理是通过和IE对象的接口的交互来实现对IE的访问。实际上是采用COM的技术,我们知道COM是和语言无关的一种二进制对象交互的模式,所以实际上我们下面所描述的内容都可以用其他的语言来实现,比如VB,DELPHI,C++ Builder等等。
—- 2.IE实例遍历实现
—- 首先我们来看系统是如何知道当前有多少个IE的实例在运行。
—- 我们知道在Windows体系结构下,一个应用程序可以通过操作系统的运行对象表来和这些应用的实例进行交互。但是IE当前的实现机制是不在运行对象表中进行注册,所以需要采用其他的方法。我们知道可以通过ShellWindows集合来代表属于shell的当前打开的窗口的集合,而IE就是属于shell的一个应用程序。
—- 下面我们描述一下用VC实现对当前 IE实例的进行遍历的方法。IShellWindows是关于系统shell的一个接口,我们可以定义一个如下的接口变量:
SHDocVw::IShellWindowsPtr m_spSHWinds;
然后创建变量的实例:
m_spSHWinds.CreateInstance
(__uuidof(SHDocVw::ShellWindows));
通过IShellWindows接口的方法GetCount
可以得到当前实例的数目:
long nCount = m_spSHWinds- >GetCount();
通过IShellWindows接口的方法Item
可以得到每一个实例对象
IDispatchPtr spDisp;
_variant_t va(i, VT_I4);
spDisp = m_spSHWinds->Item(va);
然后我们可以判断实例对象是不是
属于IE浏览器对象,通过下面的语句实现:
SHDocVw::IWebBrowser2Ptr spBrowser(spDisp);
assert(spBrowser != NULL)
—-在得到了IE浏览器对象以后,我们可以调用IWebBrowser2Ptr接口的方法来得到当前的文档对象的指针: MSHTML::IHTMLDocument2Ptr spDoc(spBrowser->GetDocument());
—- 然后我们就可以通过这个接口对这个文档对象进行操作,比如通过Gettitle得到文档的标题。
—- 我们在浏览网络的时候,一般总会同时开很多IE的实例,如果这些页面都是很好的话,我们可能想保存在硬盘上,这样,我们需要对每一个实例进行保存,而如果我们采用上面的原理,我们可以得到每一个IE的实例及其网页对象的接口,这样就可以通过一个简单的程序来批量的保存当前的所有打开的网页。采用上面介绍的方法实现了对当前IE实例的遍历,但是我们希望得到每一个IE实例所产生的事件,这就需要通过DLL的机制来实现。
—- 3.和IE相绑定的DLL的实现
—- 我们介绍一下如何建立和IE进行绑定的DLL的实现的过程。为了和IE的运行实例进行绑定,我们需要建立一个能够和每一个IE实例进行绑定的DLL。IE的启动过程是这样的,当每一个IE的实例启动的时候,它都会在注册表中去寻找这个的一个CLSID,具体的注册表的键位置为:
HKEY_LOCALL_MACHINESOFTWAREMicrosoftWindows
CurrentVersionExplorerBrowser Helper Objects
—- 当在这个键位置下存在CLSIDs的时候,IE会通过使用CoCreateInstance()方法来创建列在该键位置下的每一个对象的实例。注意对象的CLSIDs必须用子键而非启动过程是这样的,当每一个IE的实例启动的时候名字值的形式表现,比如{DD41D66E-CE4F-11D2-8DA9-00A0249EABF4} 就是一个有效的子键。我们使用DLL的形式而非EXE的形式的原因是因为DLL和IE实例运行在同一个进程空间里面。每一个这种形式的DLL必须实现接口IObjectWithSite,其中方法SetSite必须被实现。通过这个方法,我们自己的DLL就可以得到一个指向IE COM对象的IUnknown的指针,实际上通过这个指针我们就可以通过COM对象中的方法QueryInterface来遍历所有可以得到的接口,这是COM的基本的机制。当然我们需要的只是IWebBrowser2这个接口。
—- 实际上我们建立的是一个COM对象,DLL只不过是COM对象的一种表现形式。我们建立的COM对象需要建立和实现的方法有:
—-1. IOleObjectWithSite接口的方法SetSite必须实现。实际上IE实例通过这个方法向我们的COM对象传递一个接口的指针。假设我们有一个接口指针的变量,不妨设为:
—-CComQIPtr< IWebBrowser2, &IID_IWebBrowser2 > m_myWebBrowser2;
—- 我们就可以在方法SetSite中把这个传进来的接口指针赋给m_myWebBrowser2。 2. 在我们得到了指向IE COM对象的接口后,我们需要把自己的DLL和IE实例所发生的事件相关连,为了实现这个目的,需要介绍两个接口:
—-(1) IConnectionPointContainer。:
—-CComQIPtr< IWebBrowser2, &这里使用这个接口的目的是用来根据它得到的IID来建立和DLL的一个特定的连接。比如我们可以进行如下的定义:
CComQIPtr< IConnectionPointContainer,
&IID_IConnectionPointContainer >
spCPContainer(m_myWebBrowser2);
—-然后,我们需要把所有IE中发生的事件和我们的DLL进行通讯,可以使用 IConnectPoint。
—-(2) IConnectPoint。通过这个接口,客户可以对连接的对象开始或者是终止一个advisory循环。IConnectPoint有两个主要的方法,一个为Advice,另一个为Unadvise。对于我们的应用来说,Advise是用来在每一个IE发生的事件和DLL之间建立一个通道。而Unadvise就是用来终止以前用Advise建立的通知关系。比如我们可以定义IConnectPoint接口如下: CComPtr< IConnectionPoint > spConnectionPoint;
—- 然后,我们要使所有在IE实例中发生的事件和我们的DLL相关,可以使用 如下的方法:
hr = spCPContainer->FindConnectionPoint(
DIID_DWebBrowserEvents2, &spConnectionPoint);
—-然后我们通过IConnectPoint接口的方法Advice使每当IE有一个新的事件发生的时候,都能够让我们的DLL知道。可以用如下的语句实现:
hr = spConnectionPoint- >Advise(
(IDispatch*)this, &m_dwIDCode);
—-在把IE实例中的事件和我们的DLL之间建立联系以后,我们可以通过IDispatch接口的Invoke()方法来处理所有的IE的事件。
—-3. IDispatch接口的Invoke()方法。IDispatch是从IUnknown中继承的一个接口的类型,通过COM接口提供的任何服务都可以通过IDispatch接口来实现。IDispatch::Invoke的工作方式同vtbl幕后的工作方式是类似的,Invoke将实现一组按索引来访问的函数,我们可以对Invoke方法进行动态的定制以提供不同的服务。Invoke方法的表示如下:
STDMETHOD(Invoke)(DISPID dispidMember,REFIID
riid, LCID lcid, WORD wFlags,
DISPPARAMS * pdispparams, VARIANT * pvarResult,
EXCEPINFO * pexcepinfo, UINT * puArgErr);
—-其中,DISPID是一个长整数,它标识的是一个函数。对于IDispatch的某一个特定的实现,DISPID都是唯一的。IDispatch的每一个实现都有其自己的IID,这里dispidMemeber实际上是可以认为是和IE实例所发生的每一个事件相关的方法,比如:DISPID_BEFORENAVIGATE2,DISPID_NAVIGATECOMPLETE2等等。 这个方法中另外一个比较重要的参数是DISPPARAMS,它的结构如下:
typedef struct tagDISPPARAMS
{
VARIANTARG* rgvarg;
//VARIANTARG是同VARAIANT相同的,可以在
//OAIDL.IDL中找到。所以实际上rgvarg是一个参数数
//组
DISPID* rgdispidNameArgs; //命名参数的DISPID
unsigned int cArgs; //表示数组中元素的个数
unsigned int CnameArgs; //命名元素的个数
}DISPPARAMS
—-要注意的是每一个参数的类型都是VARIANTARG,所以在IE和我们DLL之间可以传递的参数类型的数目是有限的。只有那些能够被放到VARIANTARG结构中的类型才可以通过调度接口进行传递。 比如对于事件DISPID_NAVIGATECOMPLETE2来说:第一个参数表示IE在访问的URL的值,类型是VT_BYREF|VT_VARIANT。注意DISPID_NAVIGATECOMPLETE2等DISPID已经在VC中被定义,我们可以直接进行使用。 如上说述,我们在方法Invoke中可以得到所有IE实例所发生的事件,我们可以把这些数据放到文件中进行事后的分析,也可以放到一个列表框中实时的显示。
—- 4.微软的HTML文档对象模型和应用分析
—- 下面我们来看如何得到网页文档的接口:网页文档的接口为IHTMLDocument2,可以通过调用IE COM对象的get_Document方法来得到网页的接口。使用如下的语句:
hr = m_spWebBrowser2- >get_Document(&spDisp);
CComQIPtr< IHTMLDocument2,
&IID_IHTMLDocument2 > spHTML;
spHTML = spDisp;
—- 这样我们就得到了网页对象的接口,然后我们就可以对网页进行分析,比如通过IHTMLDocument2提供的方法get_URL我们可以得到和该网页相关的URL的地址值,通过get_forms方法可以该网页中所有的Form对象的集合。实际上W3C组织已经制定了一个DOM(Document Objec Model)标准,当然这个标准不仅仅是针对HTML,同时还是针对XML制定的。W3C组织只是定义了网页对象的接口,不同的公司可以采用不同的语言和方法进行具体的实现。按照W3C组织定义的网页对象被认为是动态的,即用户可以动态的对网页对象里面所包含的每一个对象进行操作。这里的对象可以是指一个输入框,也可以是图象和声音等对象。同时按照W3C的正式文档的说明,网页对象是可以动态增加和删除的。事实上,很少有厂商实现了DOM定义的所有功能。微软对网页对象的定义也基本上是按照这个标准实现的。但是当前的接口还不支持动态的增加和删除元素,但是可以对网页中的基本元素进行属性的修改。比如IHTMLElementCollection表示网页中一些基本的元素的集合,IHTMLElement表示网页中的一个基本的元素。而象IHTMLOptionElement接口就表示一个特定的元素Option。基本的元素都有setAttribute和geAttribute方法来动态的设置和得到元素的名称和值。
—- 较为常见的一个应用是我们能够分析网页中是否有需要填写的Forms,如果这个网址的Forms以前已经填写过而且数据我们已经保存下来的话,我们就可以把数据自动放到和该URL下的Forms的相关的位置中去。另外,我们可以总结网页上需要填写的Form的数据项,先对这些数据项进行赋值,以后碰到有相同的数据项的时候就自动把我们赋值的内容填写进去。实际上Form是对象,Form中包含的元素,比如INPUT,OPTION,SELECT等类型的输入元素都是对象。
—- 另外一个可以想到的应用是自动对网页中的文本进行翻译,因为我们可以修改网页中任何对象的属性,所以我们可以把里面不属于本国语言的部分自动翻译成本国语言,当然真正的实现还要靠自然语言理解方面技术的突破,但是IE浏览器的接口和对象的形式使我们能够灵活的控制整个IE,无论是从事件对象还是到网页对象。
—- 5.小结
—- 上面我们分析了如何得到所有IE的实例,同时介绍了和IE实例相捆绑的DLL的详细的实现机制,同时对网页的对象化进行了分析。并且介绍了几个相关的应用和实现的方法及存在的技术问题。IE是一个组件化的以COM为基础的浏览器,它具有强大的功能,同时为应用开发者留下了广阔的空间,当然它也存在体积比较大,速度相对比较慢的缺点。但是它的体系结构代表了微软先进的创新的技术,因此具有强大的生命力。
Posted: May 21, 2007 at 10:12 am | Tags: class, html, ie, server, toolbar, web, windows, wtl
转至: http://www.codeproject.com

Credits and Acknowlegements
This module is based on the ATL DeskBand Wizard article that was created by Erik Thompson. My thanks goes to him for producing a great wizard that saves you the nity grity of creating DeskBands.
Please note that this project does not use MFC, for all those MFC die hards that want to use MFC in their Tool Bands I suggest you down load the KKBar sample from microsofts MSDN site.
The KBBar Sample can be downloaded from here
Creating the ToolBand Module
You will need to install the ATL DeskBand Wizard in order to create ToolBands. Please follow the instruction in this article.
The best way to kick start a Tool band project is to use the ATL COM App Wizard. The COM Object needs to be in-proc therefore choose ‘DLL’ as the Server Type. The rest of the options can be kept in there default state. (Note this project does not use MFC, as the project is based on ATL and WTL)
Once you have a ATL COM Project, You can use the ATL DeskBand Wizard to create the Initial Tool Band.
Adding Support for WTL
You will require the WTL Libraries, these can be downloaded from the microsoft site
See Installation of WTL
The following header files needs to be added to stdafx.h file
atlapp.hatlwin.hatlctrls.hatlmisc.h
You can create your toolbar in the usual way via the resource editor, Once you have your toolbar you need to create the toolbar dynamically. The CBandToolBarCtrl is inherited from CToolBarCtrl and is used to create the toolbar dynamically.
DWORD dStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT; HWND hWnd = m_wndToolBar.CreateSimpleToolBarCtrl(hWndChild, IDR_TOOLBAR_TEST, FALSE, dStyle);
This is done in the RegisterAndCreateWindow function that is called from SetSite method.
Message Reflection
The best way to handle the messages of the toolbar is to let the control handle its own messages via "Message Reflection". The best way to reflect the messages is to create an invisible control that acts as the parent for the toolbar. The invisible control will reflect the toolbar messages back to itself. See CBandToolBarReflectorCtrl class for the invisible control that will be used.
The following code shows the parent child relationship that is used to achieve Message Reflection.
BOOL CToolBandObj::RegisterAndCreateWindow(){ RECT rectClientParent; ::GetClientRect(m_hWndParent, &rectClientParent); HWND hWndChild = m_wndInvisibleChildWnd.Create(m_hWndParent, rectClientParent, NULL, WS_CHILD); DWORD dStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT; HWND hWnd = m_wndToolBar.CreateSimpleToolBarCtrl(hWndChild,
IDR_TOOLBAR_TEST, FALSE, dStyle); m_wndToolBar.SetExtendedStyle(TBSTYLE_EX_DRAWDDARROWS); m_wndToolBar.m_ctlBandEdit.m_pBand = this; return ::IsWindow(m_wndToolBar.m_hWnd);}
The following Macros are used to identify the reflected messages from the ordinary messages. e.g WM_COMMAND reflected comes back as OCM_COMMAND.
#define OCM_COMMAND_CODE_HANDLER(code, func) \if(uMsg == OCM_COMMAND && code == HIWORD(wParam)) \{ \ bHandled = TRUE; \ lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \ if(bHandled) \ return TRUE; \}#define OCM_COMMAND_ID_HANDLER(id, func) \if(uMsg == OCM_COMMAND && id == LOWORD(wParam)) \{ \ bHandled = TRUE; \ lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \ if(bHandled) \ return TRUE; \}#define OCM_NOTIFY_CODE_HANDLER(cd, func) \if(uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code) \{ \ bHandled = TRUE; \ lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \ if(bHandled) \ return TRUE; \}
Browser Navigation
In order to Navigate on the browser you need to instantiate the IWebBrowser2 COM Object. This is usually done on the SetSite Method e.g.
IServiceProviderPtr pServiceProvider = pUnkSite;if (_Module.m_pWebBrowser) _Module.m_pWebBrowser = NULL; if(FAILED(pServiceProvider->QueryService(SID_SWebBrowserApp, IID_IWebBrowser, (void**)&_Module.m_pWebBrowser)))return E_FAIL;
Once you have the COM Object Instantiated, you can move to your URL using the navigate method
_variant_t varURL = _bstr_t(www.codeproject.com); _variant_t varEmpty;_Module.m_pWebBrowser->Navigate2(&varURL, &varEmpty, &varEmpty, &varEmpty, &varEmpty);
Drag and Drop Edit and ComboBox Control
The CBandEditCtrl class is inherited from a WTL CEdit control that has drag and drop facility. i.e. you can drag text from the browser straight to the CEdit Control.
The CBandComboBoxCtrl class is inherited from a WTL CComboBox control that has drag and drop facility. i.e. you can drag text from the browser straight to the CComboBox Control.

The Edit control in this sample module allows you to drag a URL from Explorer or any other Dragable enabled container. Once you have dropped the URL the toolband will go to that site.
Configurable Toolbar Button Styles
The CBandToolBarCtrl class allows you to have the follwoing button styles on the toolbar
- Image and Text on the right
- Image and Text on the bottom
- Image only



Pop-up Menu Tracking
A pop up menu is used to get to the configuration options

ToolTips
This has been taken from MSDN to explain why you need to handle the tooltips on the toolbar your self.
Tool tips are automatically displayed for buttons and other controls contained in a parent window derived from CFrameWnd. This is because CFrameWnd has a default handler for the TTN_GETDISPINFO notification, which handles TTN_NEEDTEXT notifications from tool tip controls associated with controls.
However, this default handler is not called when the TTN_NEEDTEXT notification is sent from a tool tip control associated with a control in a window that is not a CFrameWnd, such as a control on a dialog box or a form view. Therefore, it is necessary for you to provide a handler function for the TTN_NEEDTEXT notification message in order to display tool tips for child controls.
This can be easily done in WTL by using the following Message Handler in the overriden ToolBar Control
NOTIFY_CODE_HANDLER(TTN_NEEDTEXT, OnToolbarNeedText)
The following is the code that loads the tool tips from the resources and sets the tool tip text.
LRESULT CBandToolBarCtrl::OnToolbarNeedText(int , LPNMHDR pnmh, BOOL& bHandled) { CString sToolTip; if (idCtrl != 0) { if (!sToolTip.LoadString(idCtrl)) { bHandled = FALSE; return 0; } } LPNMTTDISPINFO pttdi = reinterpret_cast<LPNMTTDISPINFO> (pnmh);pttdi->lpszText = MAKEINTRESOURCE(idCtrl); pttdi->hinst = _Module.GetResourceInstance(); pttdi->uFlags = TTF_DI_SETITEM; return 0;}
Update the Status Bar
You can update the status bar using the browser method put_StatusText, this method can be used typically in the WM_MENUSELECT event
The following is the code that loads up the menu text from the resources and displays it on the browser status bar.
Collapse
LRESULT CBandToolBarCtrl::OnMenuSelect(UINT , WPARAM wParam, LPARAM lParam, BOOL& bHandled) { WORD nID = LOWORD(wParam); WORD wFlags = HIWORD(wParam); CString sStatusBarDesc; if ( !(wFlags & MF_POPUP) ) { if (nID != 0) { if (!sStatusBarDesc.LoadString(nID)) { bHandled = FALSE; return 0; } int nPos = sStatusBarDesc.Find(_T("\n")); if (nPos != -1) { sStatusBarDesc = sStatusBarDesc.Left(nPos+1); _Module.m_pWebBrowser-> put_StatusText(_bstr_t(sStatusBarDesc)); return 0; } } } return 0;}
How to add a Chevron to your toolband
In order to add a chevron to your toolband you need to add the DBIMF_USECHEVRON flags to your GetBandInfo method in the DBIM_MODEFLAGS mask.
... if(pdbi->dwMask == DBIM_MODEFLAGS) { pdbi->dwModeFlags = DBIMF_NORMAL | DBIMF_VARIABLEHEIGHT | DBIMF_USECHEVRON | DBIMF_BREAK; }...
This basically add the ability to show the chevron, if you want to see it appear on your toolband, then you must make sure the pdbi->ptMinSize.x value is less then your pdbi->ptActual.x value (Again this values can be set in the GetBandInfo method.
In order to handle the events of the button in the chevron menu, you must subclass the rebar control which is hosting your toolbar. The following steps have been used to sublass the rebar control
1. Find the rebar control – This can be achieved by getting the browsers window handle and searching for all its child windows, until you find the rebar control.
2. Once you have found the rebar control you can simply subclass it using an ATL CContainedWindow.
BOOL CBandToolBarCtrl::SetBandRebar() { HWND hWnd(NULL); _Module.m_pWebBrowser->get_HWND((long*)&hWnd); if (hWnd == NULL) return FALSE; m_ctlRebar.m_hWnd = FindRebar(hWnd); if (m_ctlRebar.m_hWnd == NULL) return FALSE; m_RebarContainer.SubclassWindow(m_ctlRebar); return TRUE; }
Once you have subclass the window, the events should reach the toolbar class.
Append to the Browser Context Menu

I tried to duplicate the google and codeproject toolband right mouse browser context menu searches without any luck, until I looked at the binary resources, I found that you can extend the internet explorer menu by adding the option in the registry. This can easily be achieved by adding an entry in your .rgs file.
HKCU{ NoRemove Software { NoRemove Microsoft { NoRemove 'Internet Explorer' { NoRemove MenuExt { ForceRemove '&Sample Toolband Serach' = s'res: { val Contexts = b '10' } } } } }}
Note the value of the registry item (a html script that exist in the resources of the module).
see MENUSERACH.HTM under HTML in the module resource to see what the script is doing
Posted: March 24, 2007 at 9:50 pm | Tags: class, java, javascript, server, shell, web, windows
转至http://www.codeproject.com
Introduction
Having recieved a number of requests for a tutorial of sorts on developing Internet Explorer Toolbars with the RBDeskband and CWindowImpl wizards that I created, I have come up with a simple sample toolbar which can be used as a reference when developing your own toolbars or explorer bars. The tutorial will walk you through the stages of developing a toolbar for IE that is very similar to the Address bar that is already present in IE. I wanted to do a tutorial that would provide a realistic sample and would produce an end result that could be used by others after the tutorial was finish. So, the tutorial is going to show you how to develop an IE toolbar to get stock quote information from The Motley Fool website. So with that, let us get started.
Prequisites
This tutorial assumes that you already know how to program in C++ and know some information about ATL and COM. To work through this tutorial, you will need the following installed on your development machine:
- Visual C++6 installed
- RBDeskBand ATL Object Wizard (Version 2.0) [get it here]
- CWindowImpl ATL Object Wizard [get it here]
The Framework
The IE toolbar consists of a COM component supporting IDeskband and a few other necessary interfaces for which IE looks for when loading registered toolbars, explorer bars and deskbands. The RBDeskband ATL Object Wizard provides most of the framework for this article. What we will need to do is create our project, a new COM object to house our toolbar, and a few CWindowImpl classes using the CWindowImpl ATL Object Wizard. Then connecting these parts together we will produce the IE toolbar in the picture at the top of the article. Visually the toolbar consists of an editbox and a toolbar with one button on it. In actuality the toolbar consists of the fore mentioned and a non visible window that is used to reflect messages to the Toolbar window, which will process or forward messges to itself and the edit box.
Creating The Shell
We will not work through the steps in creating the shell for our toolbar.
Creating The Project
- If you have not done so already, start Visual C++6.
- Then, from the File menu select New menu item; the New Dialog pops up.
- In the New Dialog, select the Projects tab, if not already selected.
- Select ATL COM AppWizard from the list view, if not already selected.
- In the Project name, type "MotleyFool". See Figure 1.
- Click the OK Button.
Figure 1. New Dialog.
- The ATL COM AppWizard will kick in.
- Clicking the Finish Button, accepting the default AppWizard attributes. See Figure 2.
- The New Project Information Dialog will present itself requesting confirmation of your project settings.
- Click the OK Button.
Figure 2. ATL COM AppWizard.
Creating The DeskBand Object
Now that we have our project container we need to add our IDeskBand derived component so that the DLL actually exposes something.
- From the Insert menu, select New ATL Object menu item; the ATL Object Wizard dialog is invoked.
- In the ATL Object Wizard dialog, select the RadBytes Category. If this category is missing then make sure that the RBDeskband and CWindowImpl ATL Object Wizards are installed.
- Next select the DeskBand item from the Objects list.
- Click the Next button to invoke the ATL Object Wizard Properties dialog for the Deskband object. See Figure 3.
- On the Names property page, type "StockBar" into the Short Name field. See Figure 4.
- Select the DeskBand ATL Object Wizard property page
- Check the Internet Explorer Toolbar checkbox. See Figure 5.
- Click the OK button on the ATL Object Wizard Properties Dialog. The ATL Object Wizard will create the files necessary for our DeskBand’s base implementation.
Figure 3. ATL Object Wizard.
Figure 4. ATL Object Wizard Properties – Names.
Figure 5. ATL Object Wizard Properties – DeskBand ATL Object Wizard
Now our project has the DeskBand implementation that we will modify to produce the toolbar pictured at the top of the article. First we will create the window classes we will need and then come back to the Desbkand object and update it to use our window classes.
Creating The Window Classes
So back in the Framework section we said that we would need three window classes. One for the Edit Box, one for the toolbar, and one for message reflection back to the toolbar. Let us now create these window classes.
The Edit Window
We need to create a derived class from the standard EDIT button window class because we are going to be adding methods to our class to help support functionality of the toolbar. This is one reason why we cannot use a CContainedWindow object directly.
- From the Insert menu, select New ATL Object menu item; the ATL Object Wizard dialog is invoked.
- In the ATL Object Wizard dialog, select the RadBytes Category. If this category is missing then make sure that the RBDeskband and CWindowImpl ATL Object Wizards are installed.
- Next select the CWindowImpl item from the Objects list.
- Click the Next button to invoke the ATL Object Wizard Properties dialog for the Deskband object. See Figure 3.
- On the Names property page, type "EditQuote" into the Short Name field.
- Select the CWindowImpl property page. See Figure 6.
- Select the SUPERCLASS radio button from the DECLAR_WND_* group.
- In the Window Class Name field, type "EDITQUOTE".
- In the Original Class Name list, select the EDIT listbox item. See Figure 7.
- Click the OK button on the ATL Object Wizard Properties Dialog. The ATL Object Wizard will create the files necessary for our CWindowImpl derived class implementation.
Figure 6. ATL Object Wizard Properties – Names.
Figure 7. ATL Object Wizard Properties – CWindowImpl.
The Toolbar Window
We need to create a derived class from the standard TOOLBARCLASSNAME window class because we are going to be adding methods to our class to help support functionality of the toolbar. It will also be the parent for the edit box and the window which the IE host will request from our DeskBand.
- From the Insert menu, select New ATL Object menu item; the ATL Object Wizard dialog is invoked.
- In the ATL Object Wizard dialog, select the RadBytes Category. If this category is missing then make sure that the RBDeskband and CWindowImpl ATL Object Wizards are installed.
- Next select the CWindowImpl item from the Objects list.
- Click the Next button to invoke the ATL Object Wizard Properties dialog for the Deskband object. See Figure 3.
- On the Names property page, type "MFToolbar" into the Short Name field.
- Select the CWindowImpl property page. See Figure 8.
- Select the SUPERCLASS radio button from the DECLAR_WND_* group.
- In the Window Class Name field, type "MOTLEYFOOLTOOLBAR".
- In the Original Class Name list, select the TOOLBARCLASSNAME listbox item. See Figure 9.
- Click the OK button on the ATL Object Wizard Properties Dialog. The ATL Object Wizard will create the files necessary for our CWindowImpl derived class implementation.
Figure 8. ATL Object Wizard Properties – Names.
Figure 9. ATL Object Wizard Properties – CWindowImpl.
The Reflection Window
We need to create a reflection window. It’s just a CWindowImpl window implmented class. We are going to be adding a small bit of functionality just to create the toolbar object and be able to access the toolbar member from our deskband class.
- From the Insert menu, select New ATL Object menu item; the ATL Object Wizard dialog is invoked.
- In the ATL Object Wizard dialog, select the RadBytes Category. If this category is missing then make sure that the RBDeskband and CWindowImpl ATL Object Wizards are installed.
- Next select the CWindowImpl item from the Objects list.
- Click the Next button to invoke the ATL Object Wizard Properties dialog for the Deskband object. See Figure 3.
- On the Names property page, type "ReflectionWnd" into the Short Name field. See Figure 10.
- We will not change any of the CWindowImpl property page values this time.
- Click the OK button on the ATL Object Wizard Properties Dialog. The ATL Object Wizard will create the files necessary for our CWindowImpl derived class implementation.
Figure 10. ATL Object Wizard Properties – Names.
Adding The Details
Now that we have our window classes available we can add our functionality for our toolbar to the appropriate window classes. Let us start with the deepest window class and work our way back out.
The EditQuote Details
For the EditQuote implementation, we need to be able to process keystrokes from the user and let the host that created our deskband object know our edit box has focus. To accomplish the first part, we need to look ahead and see that our DeskBand object will be implementing the IInputObject interface. So the host will query for that interface and know that we want to recieve messages and be given the chance to recieve focus. When the host sends our band messages to process they come through the IInputObject::TranslateAccelerator method. Our DeskBand will implement this method and it is best if our edit box, which will process the message, copy the TranslateAcceleratorIO method definition so our deskband can forward the message easily through a logical method call.
Figure 11. FileView Pane.
In the FileView pane (See Figure 11), double click the EditQuote.h item under Header Files. This will open the header file in the editing area. We now need to define the method definition for TranslateAcceleratorIO. To do this, add below the virtual CEditQuote destructor the following line of code:
STDMETHOD(TranslateAcceleratorIO)(LPMSG lpMsg);
Now Open the EditQuote.cpp source file and add the implementation of TranslateAcceleratorIO to the file
STDMETHODIMP CEditQuote::TranslateAcceleratorIO(LPMSG lpMsg){ TranslateMessage(lpMsg); DispatchMessage(lpMsg); return S_OK;}
Now our DeskBand implementation can call this message and the edit box will process the key strokes properly. But wait, our edit box should notify the toolbar to load the quote details entered if the key stroke is the enter key. For this, we will need to define a message id and send that message to the parent window to process. In the EditQuote.h header file below the include statement, add the definition of our message id as shown below in bold.
#include <commctrl.h>const int WM_GETQUOTE = WM_USER + 1024;
In our EditQuote.cpp file we will add code to our TranslateAcceleratorIO method to process the enter key. Add the code below in bold to the EditQuote.cpp file.
STDMETHODIMP CEditQuote::TranslateAcceleratorIO(LPMSG lpMsg){ int nVirtKey = (int)(lpMsg->wParam); if (VK_RETURN == nVirtKey) { lpMsg->wParam = 0; ::PostMessage(GetParent(), WM_GETQUOTE, 0, 0); return S_OK; } TranslateMessage(lpMsg); DispatchMessage(lpMsg); return S_OK;}
Now our edit box will notify the parent when the user presses the enter key so that the parent can retrieve the requested ticker symbol details, this part will be implemented when we get to the toolbar details.
The first part of the Edit boxes implementation is finished. Now we need to be able for the edit box to have the deskband notify the host that we have focus or that we don’t have focus any longer. To do this we will need to add a method for the deskband to pass us it’s address so that we can call a method of the deskband class. These next steps will involve adding code to the CEditQuote class and to our Deskband class implementation.
Open the EditQuote.h file and add a forward reference to the CStockBar class so that we can defined our methods and members in our class header without knowing the implementation details of our deskband class, add the line in bold.
#include <commctrl.h>const int WM_GETQUOTE = WM_USER + 1024;class CStockBar;
For our class to notify the host that our deskband has focus, we need to add a message handler for EN_SETFOCUS. Add the command code handler code below in bold to your EditQuote.h file.
BEGIN_MSG_MAP(CEditQuote) COMMAND_CODE_HANDLER(EN_SETFOCUS, OnSetFocus) END_MSG_MAP()
Then add the method definition for OnSetFocus to the header file below the commented out handler prototypes as follows below in bold.
LRESULT OnSetFocus(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
Before we implement the OnSetFocus method, we need to define a method for our deskband to tells of it’s address and to retain that address for later use. Add the following lines of code to your EditQuote.h file below the TranslateAcceleratorIO definition.
void SetBand(CStockBar* pBand);private: CStockBar* m_pBand;
Now we can move to your EditQuote.cpp source file and implement the message handler, the SetBand method, and update the TranslateAcceleratorIO method for focus change. At the top of the EditQuote.cpp file add the following includes to the include list as shown below in bold.
#include "stdafx.h"#include "EditQuote.h"#include "MotleyFool.h"#include "StockBar.h"
Now when we can use the methods of the CStockBar class in our code. Add to the end of the constructor, the initalization of m_pBand. Don’t forget the colon operator.
CEditQuote::CEditQuote(): m_pBand(NULL){}
Next we will add the SetBand implementation to our CEditQuote class. Notice that since it is not a com object we don’t call AddRef or Release on it. It’s just a pointer to the class and when it’s destroyed our CEditQuote instance will also be destroyed. We could have also done this inline in our header file.
void CEditQuote::SetBand(CStockBar* pBand){ m_pBand = pBand;}
Next we need to add our message handler for our EN_SETFOCUS message. Add the code below to the end of the EditQuote.cpp source file.
LRESULT CEditQuote::OnSetFocus(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled){ if (m_pBand) m_pBand->FocusChange(TRUE); return 0;}
We have one more section of code to add to our CEditQuote implementation then we can move to our CStockBar class to define and implement the FocusChange method. Add the following code to the CEditQuote TranslateAcceleratorIO method as shown in bold. We add this code so the host knows that we are no longer needing messages.
STDMETHODIMP CEditQuote::TranslateAcceleratorIO(LPMSG lpMsg){ int nVirtKey = (int)(lpMsg->wParam); if (VK_RETURN == nVirtKey) { lpMsg->wParam = 0; ::PostMessage(GetParent(), WM_GETQUOTE, 0, 0); return S_OK; } else if (WM_KEYDOWN == lpMsg->message && nVirtKey == VK_TAB) { if (m_pBand) m_pBand->FocusChange(FALSE); return S_FALSE; } TranslateMessage(lpMsg); DispatchMessage(lpMsg); return S_OK;}
Open the StockBar.h header file and add the definition of FocusChange to it as shown below in bold.
public: void FocusChange(BOOL bHaveFocus);
Now open the StockBar.cpp source file and add the implementation of FocusChange to it at the bottom.
void CStockBar::FocusChange(BOOL bHaveFocus){ if (m_pSite) { IUnknown* pUnk = NULL; if (SUCCEEDED(QueryInterface(IID_IUnknown, (LPVOID*)&pUnk)) && pUnk != NULL) { m_pSite->OnFocusChangeIS(pUnk, bHaveFocus); pUnk->Release(); pUnk = NULL; } }}
We have finished off the work needed for the edit box to work properly in our toolbar. Now we need to build our toolbar up so that it has a button and contains our edit box. Then we will add the nessecities to our reflection window and update our IDeskBand to provide the correct information to our host. We are almost there. If you were to compile the project and run it, it would except that the band would look like the following in figure X.
The MFToolbar Details
For the implementation of the MFToolbar window, we need to be able to have it do the following things. It must be able to process the WM_GETQUOTE message from the EditQuote window, communicate with the web browser in which the toolbar is located, create the buttons and place the child windows on itself, forward messages to the EditQuote child window and size itself appropriately to the users actions.
So, the first thing we should do since our toolbar is going to contain an instance of CEditQuote is include the header file for the CEditQuote class. We will do this by opening the MFToolbar.h file and inserting the include statement for the CEditQuote class as shown in bold below.
#include <commctrl.h>#include "EditQuote.h"
Next we need to add a member to our toolbar class for the CEditQuote class. We will do this by adding a private section to the end of our class and defining a member variable as shown below in bold.
CMFToolbar(); virtual ~CMFToolbar();private: CEditQuote m_EditWnd;
Now that we have our member defined for our EditQuote window, we need to forward window messages to it so that keyboard inputs are processed appropriately. We do this by updating the toolbar message map to chain messages to our member as shown below in bold.
BEGIN_MSG_MAP(CMFToolbar) CHAIN_MSG_MAP_MEMBER(m_EditWnd) END_MSG_MAP()
Looking forward, our deskband will need to get the EditQuote member to deterimine if it has focus and also to make it function. We could just expose the EditQuote member directly by having made it a public member instead of private, but by making it private we can expose a method that will expose our member giving us flexibility later to modify the class if the need should arise. So to expose the EditQuote member, we will add a fuction to our toolbar class to return the reference to the EditQuote member. In the toolbar header file, add the method definition and implementation below in bold to it.
CMFToolbar(); virtual ~CMFToolbar(); inline CEditQuote& GetEditBox() {return m_EditWnd;};
Now we will create our toolbar window. Our toolbar consists of the EditQuote box and a button with an icon and text on it. To house the icon, our toolbar will need an image list handle to send to the toolbar window. So we need to add a few things to our toolbar header file before we go and implement the toolbar’s creation. The first thing we will add is the member variable for our image list. Add the line in bold below to your toolbar header file.
private: CEditQuote m_EditWnd; HIMAGELIST m_hImageList;
Then we will add a message handler to our toolbar’s message map and define the message handlers function definition to our header file and the follow lines of code in bold to your header file.
BEGIN_MSG_MAP(CMFToolbar) CHAIN_MSG_MAP_MEMBER(m_EditWnd) MESSAGE_HANDLER(WM_CREATE, OnCreate) END_MSG_MAP() LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
Before we can implement our toolbar’s creation, we need to create a icon resource that our toolbar button will use next to its text. So go to the resource view and add a new icon to the project resources. You can do this by right clicking on "MotleyFool resources" and selecting "Insert…" from the context menu. In the Insert Resource dialog box, select Icon from the Resource type list and click the New button. This will insert a blank icon resource into your project. Rename the icon’s resource ID by right clicking on the icon resource in the resource view and selecting the properties menu item from the context menu. Change the id to IDI_MOTLEY. Then draw or graciously borrow an icon from The Motley Fool to use on the toolbar. I graciously borrowed the icon from their website and adapted it into the icon.
Now we can implement it our toolbars creation. Open the MFToolbar source file and implement the details of the toolbar creation as described below.
First we need to include the project resource file so we can use the icon ID in our code. Add the line in bold below to our toolbar’s source file as shown.
#include "stdafx.h"#include "resource.h"#include "MFToolbar.h"
Next we need to update our constructor implementation. We need to initialize our handle to the image list by setting it to NULL. Don’t forget the colon.
CMFToolbar::CMFToolbar(): m_hImageList(NULL){}
Next we need to update our destructor, it should destroy the image list and destroy the window if it has not yet been destroyed.
CMFToolbar::~CMFToolbar(){ ImageList_Destroy(m_hImageList); if (IsWindow()) DestroyWindow();}
Before we can implement our toolbar’s creation, we need to add a resource symbol to our project for the toolbar button’s ID. We could just use a #define statement at the top of the source file, but for cleanliness and since we are already including the resource.h file, we will add it to our resource file. Go to the "View" menu and select "Resource Symbols" menu item. Click the "New" button on the Resource Symbols dialog. Then enter a name of "IDM_GETQUOTE" and click OK. Then close the Resource Symbols dialog.
Now we can create our toolbar, we defined the OnCreate method in our header file and need to now implement it. Add the following function and its implementation to the end of the toolbar source file.
Collapse
LRESULT CMFToolbar::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){ SendMessage(m_hWnd, TB_SETEXTENDEDSTYLE, 0, (LPARAM)TBSTYLE_EX_MIXEDBUTTONS); SendMessage(m_hWnd, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0); SendMessage(m_hWnd, TB_SETMAXTEXTROWS, 1, 0L); TCHAR* pCaption = _T("Get Quote"); int iIndex = ::SendMessage(m_hWnd, TB_ADDSTRING, 0,(LPARAM)pCaption); HICON hMotley = LoadIcon(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDI_MOTLEY)); m_hImageList = ImageList_Create(16,16, ILC_COLOR16, 1, 0); int iImageIndex = ImageList_AddIcon(m_hImageList, hMotley); DestroyIcon(hMotley); ::SendMessage(m_hWnd, TB_SETIMAGELIST, 0, (LPARAM)m_hImageList); TBBUTTON Button; ZeroMemory((void*)&Button, sizeof(TBBUTTON)); Button.idCommand = IDM_GETQUOTE; Button.fsState = TBSTATE_ENABLED; Button.fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT; Button.dwData = 0; Button.iString = iIndex; Button.iBitmap = 0; ::SendMessage(m_hWnd, TB_INSERTBUTTON, 0, (LPARAM)&Button); RECT rect = {0,0,0,0}; m_EditWnd.Create(m_hWnd, rect, NULL, WS_CHILD|WS_VISIBLE, WS_EX_CLIENTEDGE); m_EditWnd.SetFont(static_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT))); return 0;}
If you try to compile at this point, you will see that there are unresolved externals for the image list method calls. We need to add a library to the project. To do this select the "Project|Settings" menu item. On the Project Settings dialog, Select All Configurations from the "Settings For" combo box. Then select the "Link" tab and append to the "Object/Library modules" edit box "comctl32.lib". Then click OK. If you compile the project now, it will compile successfully and the image list unresolved externals will disappear.
We still have a few things we need to do to the Toolbar window. It needs to process Command messages, resopnd to WM_GETQUOTE messages, and resize itself. Let’s conquer the latter first.
To orgainze the tooblar correctly, we should have the toolbar responsd to WM_SIZE messages. To do this, we will add to our tooblar header file a message handler for the WM_SIZE message and add a function definition for OnSize which WM_SIZE messages will be sent to. Open our toolbar header file and add the lines in bold below to it as shown.
BEGIN_MSG_MAP(CMFToolbar) CHAIN_MSG_MAP_MEMBER(m_EditWnd) MESSAGE_HANDLER(WM_CREATE, OnCreate) MESSAGE_HANDLER(WM_SIZE, OnSize) END_MSG_MAP() LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
Now we need to implement our OnSize function. Open the toolbar source file and add the function implementation below to the end of the file.
Collapse
LRESULT CMFToolbar::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){ RECT wndRect, btnRect; GetClientRect(&wndRect); ::SendMessage(m_hWnd, TB_GETITEMRECT, 0, (LPARAM)&btnRect); wndRect.right -= (btnRect.right - btnRect.left); SendMessage(TB_SETINDENT, wndRect.right - wndRect.left); wndRect.right -= 3; m_EditWnd.MoveWindow(&wndRect, FALSE); return 0;}
We still need to respond to user input for the toolbar button and from the edit box when the user presses the enter key. What we want the toolbar to do is tell the web browser host to navigate to the motely fool website and retrieve the stock quotes requested. First we need for the Deskband object to tell our toolbar window what the web browser instance is so that the toolbar window can communicate with it. To do this, we will add a private member variable and a public method in which the deskband can set the web browser instance. Our window will then use the member variable set to tell the web browser where to navigate and what to retrieve.
To do this, open the toolbar header file and add the lines in bold to the file.
CMFToolbar(); virtual ~CMFToolbar(); inline CEditQuote& GetEditBox() {return m_EditWnd;}; void SetBrowser(IWebBrowser2* pBrowser);private: CEditQuote m_EditWnd; HIMAGELIST m_hImageList; IWebBrowser2* m_pBrowser;
Now, open the toolbar source file. We will update the constructor and initialize our member variable to null. Then we will update the toolbar destructor and release the member variable if it hasn’t been. Then we will implement the SetBrowser method.
Initialize the web browser member variable.
CMFToolbar::CMFToolbar(): m_hImageList(NULL), m_pBrowser(NULL){}
Release the web browser object if held.
CMFToolbar::~CMFToolbar(){ ImageList_Destroy(m_hImageList); SetBrowser(NULL); if (IsWindow()) DestroyWindow();}
Implement SetBrowser()
void CMFToolbar::SetBrowser(IWebBrowser2* pBrowser){ if (m_pBrowser) m_pBrowser->Release(); m_pBrowser = pBrowser; if (m_pBrowser) m_pBrowser->AddRef();}
If you try and compile the project, you will notice that IWebBrowser2 is undefine in our header file. This is because we need to update our stdafx.h header file to include system files that define IWebBrowser2. To do this, open stdafx.h and add the following lines in bold to the file, then recompile.
extern CComModule _Module;#include <atlcom.h>#include <atlwin.h>#include <shlguid.h>#include <shlobj.h>
Now we can add message handlers for WM_COMMAND and WM_GETQUOTE to our toolbar class to handle the toolbar button being pressed and the enter key being pressed in the edit box by the user. To do this, we will need to add to our toolbar header file message handlers and function definitions for WM_COMMAND and WM_GETQUOTE. We will also need to add a private method which both will call if they need to to preform the same functionality (better than repeating code that does the same thing). So let’s add the message handlers to the header file.
Collapse
BEGIN_MSG_MAP(CMFToolbar) CHAIN_MSG_MAP_MEMBER(m_EditWnd) MESSAGE_HANDLER(WM_CREATE, OnCreate) MESSAGE_HANDLER(WM_SIZE, OnSize) MESSAGE_HANDLER(WM_COMMAND, OnCommand) MESSAGE_HANDLER(WM_GETQUOTE, OnGetQuote) END_MSG_MAP() LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); LRESULT OnGetQuote(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
Now we can add the function delcaration for our GetQuote privaet method.
private: CEditQuote m_EditWnd; HIMAGELIST m_hImageList; IWebBrowser2* m_pBrowser; void GetQuote();
Now let’s switch to our source file and implement our message handler functions and the GetQuote method. Add the code below to the end of the toolbar source file.
Collapse
LRESULT CMFToolbar::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){ if (!HIWORD(wParam)) { long lSite = LOWORD(wParam); if ( lSite == IDM_GETQUOTE) { GetQuote(); return 0; } } return -1;}LRESULT CMFToolbar::OnGetQuote(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){ GetQuote(); return 0;}void CMFToolbar::GetQuote(){ if (m_pBrowser) { VARIANT vEmpty; VariantInit(&vEmpty); m_pBrowser->Stop(); _bstr_t bsSite; if (m_EditWnd.GetWindowTextLength()) { BSTR bstrTickers = NULL; m_EditWnd.GetWindowText(&bstrTickers); bsSite = "http: bsSite += bstrTickers; SysFreeString(bstrTickers); } else bsSite = "http: m_pBrowser->Navigate(bsSite, &vEmpty, &vEmpty, &vEmpty, &vEmpty); }}
If you try to compile, you will notice that _bstr_t is undefined. That is because the class is defined in comdef.h. We need to add this to our stdafx.h header file so that we can use it as well as any other class in our project (which we will need to for IInputObject). Open the stdafx.h header file and add the lines in bold to the file as indicated.
#include <shlobj.h>#include <comdef.h>
Our implementation of the toolbar window is complete. Now we can move on to the Reflection window which creates our toolbars and forwards command messages to it.
The Reflection Window Details
For the Reflection Window, it’s only purpose is to create the toolbar window (which it doesn’t need to really do, but by doing so eases message forwarding) and forward messages to it. The reflection window is not visible, it’s just a layer added so that message from the toolbar get to the toolbar. If we didn’t have this window present, toolbar messages would get sent to the parent window (which we do not control) and we would never get them. This is not good since we need to respond to WM_COMMAND messages from the toolbar. Thus the need for the reflection window. So let’s create the toolbar window and the message forwarding for it.
Open the ReflectionWnd.h header file. We will need to include the toolbar header file and add a private member variable to our reflection window to create it and to pass it to the message chain. First things first, add the include statement below so we can use the CMFToolbar class.
#include <commctrl.h>#include "MFToolbar.h"
Next add a private member variable to the end of the reflection window class for the toolbar as shown below.
CReflectionWnd(); virtual ~CReflectionWnd();private: CMFToolbar m_ToolbarWnd;
Next update the reflection window message map to forward messages to the toolbar window as shown below.
BEGIN_MSG_MAP(CReflectionWnd) CHAIN_MSG_MAP_MEMBER(m_ToolbarWnd) END_MSG_MAP()
We will also need a public function for our deskband class to get at our toolbar window. We will do the same as we did with the EditQuote window by providing a function to get at the member variable indirectly. Add the line of code in bold below to the header file as indicated.
CReflectionWnd(); virtual ~CReflectionWnd(); inline CMFToolbar& GetToolBar() { return m_ToolbarWnd;};
Lastly, we need to create the toolbar window and will do so in the WM_CREATE message handler for our reflection window. Add the code below in bold to the reflection window header file. Then we will implement the OnCreate method in the source file.
BEGIN_MSG_MAP(CReflectionWnd) MESSAGE_HANDLER(WM_CREATE, OnCreate) CHAIN_MSG_MAP_MEMBER(m_ToolbarWnd) END_MSG_MAP() LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
Now open the ReflectionWnd.cpp source file and add the implementation of OnCreate to its end.
const DWORD DEFAULT_TOOLBAR_STYLE = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | WS_TABSTOP | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT | TBSTYLE_TRANSPARENT | TBSTYLE_LIST | TBSTYLE_CUSTOMERASE | TBSTYLE_WRAPABLE | CCS_TOP | CCS_NODIVIDER | CCS_NOPARENTALIGN | CCS_NORESIZE;LRESULT CReflectionWnd::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){ RECT rect; GetClientRect(&rect); m_ToolbarWnd.Create(m_hWnd, rect, NULL, DEFAULT_TOOLBAR_STYLE); return 0;}
You will notice that we defined a constant for the toolbar style. This was done to make the code more readable.
The only thing left to do to the reflection window code is update the destructor to destory the window if it’s still present.
CReflectionWnd::~CReflectionWnd(){ if (IsWindow()) DestroyWindow();}
Finishing Off The Deskband Toolbar
All that’s left is for our deskband to create the toolbar window, have the host use the toolbar window, remove the unused IPersistStream implementation, implement IInputObject (for focus control) and do some code tweaking. So lets wrap this toolbar up. Open the StockBar.h header file. Remove the following lines of code that are in bold since we moved them to our stdafx.h for our other classes to also use.
#include "resource.h" // main symbols#include <shlguid.h>#include <shlobj.h>
Next remove the following line from the class delcaration.
public IPersistStream,
The top of the class declaration should now look like this,
class ATL_NO_VTABLE CStockBar : public CComObjectRootEx<CComSingleThreadModel>, public CComCoClass<CStockBar, &CLSID_StockBar>, public IDeskBand, public IObjectWithSite, public IDispatchImpl<IStockBar, &IID_IStockBar, &LIBID_MOTLEYFOOLLib>{
Next scroll down to the COM Map and remove the following two lines of code,
COM_INTERFACE_ENTRY(IPersist) COM_INTERFACE_ENTRY(IPersistStream)
Your COM Map should now look like this,
BEGIN_COM_MAP(CStockBar) COM_INTERFACE_ENTRY(IStockBar) COM_INTERFACE_ENTRY(IOleWindow) COM_INTERFACE_ENTRY_IID(IID_IDockingWindow, IDockingWindow) COM_INTERFACE_ENTRY(IObjectWithSite) COM_INTERFACE_ENTRY_IID(IID_IDeskBand, IDeskBand) COM_INTERFACE_ENTRY(IDispatch)END_COM_MAP()
Scroll down the header file further and remove the sections of function declarations for IPersist and IPersistStream, which includes the following lines.
public: STDMETHOD(GetClassID)(CLSID *pClassID);public: STDMETHOD(IsDirty)(void); STDMETHOD(Load)(IStream *pStm); STDMETHOD(Save)(IStream *pStm, BOOL fClearDirty); STDMETHOD(GetSizeMax)(ULARGE_INTEGER *pcbSize);
There should now be nothing related to IPersist or IPersistStream between the IDockingWindow and IStockBar function declaration sections.
Now we need to remove the IPersist and IPersistStream function implementations from the StockBar.cpp source file. Find the GetClassID, IsDirty, Load, Save, and GetSizeMax function implementations and remove them from the file. They should be directly above the FocusChange Method we added earlier.
Now we can start adding code to our deskband. Open the stockbar.h header file and add the include for the reflection window class as shown below in bold.
#include "resource.h" // main symbols#include "ReflectionWnd.h"
Next, find the protected section at the end of the file and replace the line
HWND m_hWnd;
with
CReflectionWnd m_ReflectWnd;
If you try to compile, you will find that it will be unsuccessful since we have removed m_hWnd and have not removed all occurances of m_hWnd from the class source file. We will replace all occurances with more appropriate code for our Reflection window and toolbar window. Open the StockBar.cpp source file, Remove the following line from the class constructor
m_hWnd(NULL),
your class constructor should now look as follows with a SetBand call added,
CStockBar::CStockBar(): m_dwBandID(0), m_dwViewMode(0), m_bShow(FALSE), m_bEnterHelpMode(FALSE), m_hWndParent(NULL), m_pSite(NULL){ m_ReflectWnd.GetToolBar().GetEditBox().SetBand(this);}
Next, update the RegisterAndCreateWindow function by replacing the temporary m_hWnd construction with the Reflection Window construction. Your RegisterAndCreateWindow implementation should look as follows:
BOOL CStockBar::RegisterAndCreateWindow(){ RECT rect; ::GetClientRect(m_hWndParent, &rect); m_ReflectWnd.Create(m_hWndParent, rect, NULL, WS_CHILD); return m_ReflectWnd.GetToolBar().IsWindow();}
As we scroll through the code, we should fix some other things. A toolbar has a default height of 22 so we need to update our GetBandInfo method so that all the y measurements are 22 not 20. We also want our Integral sizing to be non sizeable so we need to set the DBIM_INTEGRAL x and y values to 0. While we are at it, we should fix the title of our toolbar so it says "The Motley Fool". You’ll find this constant defined near the top of the source file, update it now.
We will now update the GetWindow call so that the toolbar window handle is returned and not the invalid m_hWnd variable. Update your GetWindow method so it looks as follows,
STDMETHODIMP CStockBar::GetWindow(HWND* phwnd){ HRESULT hr = S_OK; if (NULL == phwnd) { hr = E_INVALIDARG; } else { *phwnd = m_ReflectWnd.GetToolBar().m_hWnd; } return hr;}
Now we need to update teh CloseDW method so that it does not destory our window buy hide it. We do this much like the MFC CToolbar class does, the class destructor will destroy the window. Your CloseDW method should look as follows,
STDMETHODIMP CStockBar::CloseDW(unsigned long dwReserved){ ShowDW(FALSE); return S_OK;}
Working our way through our class implementation, we will update the next method that needs updating. Update the ShowDW class to show or hide the toolbar window which the host is using. Your ShowDW class should look as follows,
STDMETHODIMP CStockBar::ShowDW(BOOL fShow){ m_bShow = fShow; m_ReflectWnd.GetToolBar().ShowWindow(m_bShow ? SW_SHOW : SW_HIDE); return S_OK;}
We are almost done modifying the CStockBar class we need to do one last bit of updating. We need to modify the SetSite implementation to release the browser window that the toolbar may be using if we have a IInputObjectSite object and we need to query the OleCommandTarget’s ServiceProvider for the IWebBrowser2 interface which we will then set to our toolbar. The modified parts of the SetSite method implementation are below in bold.
Collapse
STDMETHODIMP CStockBar::SetSite(IUnknown* pUnkSite){ if(m_pSite) { m_ReflectWnd.GetToolBar().SetBrowser(NULL); m_pSite->Release(); m_pSite = NULL; } if(pUnkSite) { IOleWindow *pOleWindow = NULL; m_hWndParent = NULL; if(SUCCEEDED(pUnkSite->QueryInterface(IID_IOleWindow, (LPVOID*)&pOleWindow))) { pOleWindow->GetWindow(&m_hWndParent); pOleWindow->Release(); } if(!::IsWindow(m_hWndParent)) return E_FAIL; if(!RegisterAndCreateWindow()) return E_FAIL; if(FAILED(pUnkSite->QueryInterface(IID_IInputObjectSite, (LPVOID*)&m_pSite))) { return E_FAIL; } IWebBrowser2* s_pFrameWB = NULL; IOleCommandTarget* pCmdTarget = NULL; HRESULT hr = pUnkSite->QueryInterface(IID_IOleCommandTarget, (LPVOID*)&pCmdTarget); if (SUCCEEDED(hr)) { IServiceProvider* pSP; hr = pCmdTarget->QueryInterface(IID_IServiceProvider, (LPVOID*)&pSP); pCmdTarget->Release(); if (SUCCEEDED(hr)) { hr = pSP->QueryService(SID_SWebBrowserApp, IID_IWebBrowser2, (LPVOID*)&s_pFrameWB); pSP->Release(); _ASSERT(s_pFrameWB); m_ReflectWnd.GetToolBar().SetBrowser(s_pFrameWB); s_pFrameWB->Release(); } } } return S_OK;}
If you try to compile and use the toolbar right now, it will function partially. Tabbing and input control will not work correctly since we have yet to implement IInputObject for our deskband. Let’s do that now since it’s the last bit of code we will write for our simple deskband. You may also notice that the Toolbars context menu and View|Toolbars menus still say CStockBar Class. we will fix this problem in the Finishing Touches section below.
IInputObject Implementation
To get tabbing and input control to work correctly for any deskband is quite simple. You need but to implement IInputObject. The host will query our deskband to see if this interface is implemented and if it is will call the methods to see if we require input focus and let us also process messages from the user through the host. To do this, open the stockbar.h header file. To the stockbar class declaration add the line below in bold,
class ATL_NO_VTABLE CStockBar : public CComObjectRootEx<CComSingleThreadModel>, public CComCoClass<CStockBar, &CLSID_StockBar>, public IDeskBand, public IObjectWithSite, public IInputObject, public IDispatchImpl<IStockBar, &IID_IStockBar, &LIBID_MOTLEYFOOLLib>{
Next scroll down to the COM Map and add an entry for IInputObject as shown below in bold,
BEGIN_COM_MAP(CStockBar) COM_INTERFACE_ENTRY(IStockBar) COM_INTERFACE_ENTRY(IInputObject) COM_INTERFACE_ENTRY(IOleWindow) COM_INTERFACE_ENTRY_IID(IID_IDockingWindow, IDockingWindow) COM_INTERFACE_ENTRY(IObjectWithSite) COM_INTERFACE_ENTRY_IID(IID_IDeskBand, IDeskBand) COM_INTERFACE_ENTRY(IDispatch)END_COM_MAP()
Next add the following section of function declarations to your header file, I placed mine before the IStockBar section.
public: STDMETHOD(HasFocusIO)(void); STDMETHOD(TranslateAcceleratorIO)(LPMSG lpMsg); STDMETHOD(UIActivateIO)(BOOL fActivate, LPMSG lpMsg);
All that remains is to implement these three functions. Add the function implementations below to the end of the stockbar.cpp source file.
Collapse
STDMETHODIMP CStockBar::HasFocusIO(void){ if (m_ReflectWnd.GetToolBar().m_hWnd == ::GetFocus()) return S_OK; if (m_ReflectWnd.GetToolBar().GetEditBox().m_hWnd == ::GetFocus()) return S_OK; return S_FALSE;}STDMETHODIMP CStockBar::TranslateAcceleratorIO(LPMSG lpMsg){ return m_ReflectWnd.GetToolBar().GetEditBox().TranslateAcceleratorIO(lpMsg);}STDMETHODIMP CStockBar::UIActivateIO(BOOL fActivate, LPMSG lpMsg){ if(fActivate) { m_ReflectWnd.GetToolBar().GetEditBox().SetFocus(); } return S_OK;}
Our toolbar is functionaly done, compile, run it and see. It works as described and is fairly simple. Let’s put some finishing UI touches on it for IE and our users to use.
Finishing Touches
The are only 2 finishing touches to make, One is to fix the context menu text. The other is to add button support to the main IE toolbar. Let’s do them in order.
To fix the context menu text problem, open the StockBar.rgs project file and change all occurances of "StockBar Class" to "The Motley Fool Quotes". Compile it, run it, and see. While you only need to change one of them, it’s nicer if they all match.
Now let’s add button support for our toolbar. Update the stockbar.rgs file contents by appending the text below to it’s contents.
Collapse
HKLM{ Software { Microsoft { 'Internet Explorer' { Extensions { ForceRemove {A26ABCF0-1C8F-46e7-A67C-0489DC21B9CC} = s 'The Motley Fool Quotes' { val BandClsid = s '{A6790AA5-C6C7-4BCF-A46D-0FDAC4EA90EB}' val ButtonText = s 'The Motley Fool' val Clsid = s '{E0DD6CAB-2D10-11D2-8F1A-0000F87ABD16}' val 'Default Visible' = s 'Yes' val 'Hot Icon' = s '%MODULE%,425' val Icon = s '%MODULE%,425' val MenuStatusBar = s 'The Motley Fool Stock Quote Toolbar' val MenuText = s 'The Motley Fool' } } } } }}
The replace the 425 with the id from resource.h of IDI_MOTLEY. Also replace the BandClsid value with the GUID of our toolbar, the above values represent the source code for the article. Now compile the toolbar again. Then start IE and right click on the Standard Buttons toolbar, Select "Customize" from the context menu. Scroll down the Available toolbar buttons listbox and find "The Motley Fool" item, See Figure 12. Select it and click the Add button in the middle of the dialog. The item will move to the right as in Figure 13. Click the Close Button. You’ll see the button added as shown in the before figure 14 and after figure 15.
Figure 12. CustomizeToolbar – Available Toolbar Buttons.
Figure 13. Customize Toolbar – Current Toolbar Buttons.
Figure 14. IE Standard Buttons – Before.
Figure 15. IE Standard Buttons – After.
Conclusion
While this tutorial is long hopefully the explaination was clear. From writing this tutorial it is easy to see that the RBDeskband ATL Object Wizard has some room for improvement but provided enough of a base for us to develop our simple example. In the end you can see that the toolbar we created is much like the Address bar. The differences lie in how MS implemented theirs versus how I implemented mine. As always feedback is welcome. Enjoy.
About Erik Thompson
Site Builder |
Erik lives in Redmond, Washington. He works as a Senior Software Engineer specializing in C++, COM, ATL and the middle-tier and now .NET. When he isn’t coding for work, he can be found trying to extend Internet Explorer with yet another Desk band or simplifying his development process with ATL Object Wizards.
He spends his free time snowboarding, mountain biking, reading, dining out at those hidden finds.
Click here to view Erik Thompson’s online profile.
|
Other popular ATL articles:
|
Posted: March 24, 2007 at 9:38 pm | Tags: class, html, web, 类
定制浏览器
作者:冯明德
浏览器控件是个典型的Active控件,提供了大量的接口及自动化对象,可以灵活的加以控制,需要的时候,可以通过这些接口控制浏览器的行为,或提供相应的出接口定制浏览器。
一、概述
浏览器对象CLSID:
CLSID_WebBrowser
提供的主要接口
IWebBrowser2 浏览器的接口
当文档建立后,可以得到相应的文档接口,文档中各标记元素的接口。
在DHTML中,大量的对象和事件就是又这些接口提供和管理的。
IHTMLDocument2
IHTMLWindow2
IHTMLEventObj
IHTMLElement
….
浏览器还将调用宿主提供的接口,以发出事件或给用户提供定制机会。
出接口
DIID_DWebBrowserEvents2
DIID_HTMLDocumentEvents
DIID_HTMLWindowEvents
(ICustomDoc)
IDocHostUIHandler
二、事件的相应
除了使用MFC缺省的事件响应机制外,也可以自建事件接受器,来响应事件
也就是,在封装对象中提供DIID_DWebBrowserEvents2 接口,然后将此接口作为接受器连接到浏览器对象。
一种做法是
在派生类中,使用MFC建立接口方案提供一个DIID_DWebBrowserEvents2接口对象嵌套成员。
class CFMDBrowser : public CWebBrowser{ ... //事件接收器接口 //DWebBrowserEvents //这是一个IDispatch分发接口 BEGIN_INTERFACE_PART(BrowserEventSink,DWebBrowserEvents) STDMETHOD(GetTypeInfoCount)(UINT *pctinfo); STDMETHOD(GetTypeInfo)(UINT iTInfo,LCID lcid,ITypeInfo **ppTInfo); STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR *rgszNames,UINT cNames, LCID lcid,DISPID *rgDispId); STDMETHOD(Invoke)(DISPID dispIdMember,REFIID riid,LCID lcid, WORD wFlags,DISPPARAMS *pDispParams, VARIANT *pVarResult,EXCEPINFO *pExcepInfo, UINT *puArgErr); END_INTERFACE_PART(BrowserEventSink) DWORD m_dwEventSinkCookie; ...}
这是一个接收器接口,无需添入到对象的接口表中。
(无需:BEGIN_INTERFACE_MAP、END_INTERFACE_MAP)
这是一个以分发接口(IDispatch)作为出接口的典型例子。在接口函数的实现中。Invoke负责又分发ID调用不同的虚拟函数。(事件函数作为虚拟函数,供派生类重载)
STDMETHODIMP CFMDBrowser::XBrowserEventSink::Invoke(DISPID dispIdMember,REFIID riid,LCID lcid, WORD wFlags,DISPPARAMS *pDispParams, VARIANT *pVarResult,EXCEPINFO *pExcepInfo, UINT *puArgErr){ METHOD_PROLOGUE(CFMDBrowser,BrowserEventSink) //将事件分发到各虚拟函数 //分发ID的定义见 exdispid.h switch(dispIdMember) { case DISPID_BEFORENAVIGATE: ... HRESULT hr=pThis->OnBeforeNavigate(..) //事件对应的虚拟函数 ... break; case DISPID_NAVIGATECOMPLETE: ... case ... case ...}
建立与浏览器的连接
得到IConnectionPointContainer接口,查找与DIID_DWebBrowserEvents对应的接收器,建立连接,记录连接的标号(m_dwEventSinkCookie);
BOOL CFMDBrowser::Connect(){ IUnknown *p_Unk=GetControlUnknown(); if(p_Unk==NULL) return FALSE; BOOL bOK=FALSE; //查找连接点对象 IConnectionPointContainer *i_cpc=0; HRESULT hr=p_Unk->QueryInterface(IID_IConnectionPointContainer, (void **)(&i_cpc)); if (SUCCEEDED(hr)) { IConnectionPoint *i_cp=0; hr=i_cpc->FindConnectionPoint(DIID_DWebBrowserEvents,&i_cp); if (SUCCEEDED(hr)) { hr=i_cp->Advise(&m_xBrowserEventSink,&m_dwEventSinkCookie); i_cp->Release(); bOK=TRUE; } i_cpc->Release(); } return bOK;}
结束时,断开与浏览器的连接
BOOL CFMDBrowser::DisConnect(){ IUnknown *p_Unk=GetControlUnknown(); if(p_Unk==NULL) return FALSE; BOOL bOK=FALSE; //查找连接点对象 IConnectionPointContainer *i_cpc=0; HRESULT hr=p_Unk->QueryInterface(IID_IConnectionPointContainer, (void **)(&i_cpc)); if (SUCCEEDED(hr)) { IConnectionPoint *i_cp=0; hr=i_cpc->FindConnectionPoint(DIID_DWebBrowserEvents,&i_cp); if (SUCCEEDED(hr)) { hr=i_cp->Unadvise(m_dwEventSinkCookie); i_cp->Release(); bOK=TRUE; } i_cpc->Release(); } return bOK;}
三、定制浏览器UI
浏览器提供了IDocHostUIHandler出接口,向用户查询界面特性
可以提供这个接口,与浏览器连接上,在其实现中,定制界面
1.建立接口
class CFMDBrowser : public CWebBrowser{ ... //IDocHostUIHandler接口,控制浏览器界面 BEGIN_INTERFACE_PART(UIHandlerSink,IDocHostUIHandler) STDMETHOD(ShowContextMenu)(DWORD,POINT*,IUnknown*,IDispatch*); STDMETHOD(GetHostInfo)(DOCHOSTUIINFO*); STDMETHOD(ShowUI)(DWORD, IOleInPlaceActiveObject*, IOleCommandTarget*, IOleInPlaceFrame*, IOleInPlaceUIWindow*); STDMETHOD(HideUI)(); STDMETHOD(UpdateUI)(); STDMETHOD(EnableModeless)(INT); STDMETHOD(OnDocWindowActivate)(INT); STDMETHOD(OnFrameWindowActivate)(INT); STDMETHOD(ResizeBorder)(LPCRECT,IOleInPlaceUIWindow*,INT); STDMETHOD(TranslateAccelerator)(LPMSG,const GUID*,DWORD); STDMETHOD(GetOptionKeyPath)(LPOLESTR*,DWORD); STDMETHOD(GetDropTarget)(IDropTarget*,IDropTarget**); STDMETHOD(GetExternal)(IDispatch**); STDMETHOD(TranslateUrl)(DWORD,OLECHAR*,OLECHAR**); STDMETHOD(FilterDataObject)(IDataObject*,IDataObject**); END_INTERFACE_PART(UIHandlerSink) ...}
无需添加接口映射
2.连接到浏览器
需要在NavigateComplete时间发生后,得到
ICustomDoc接口,由此接口的
SetUIHandler成员设置UI接口。
//设置界面接口IDispatch *i_dispatch=0;if (SUCCEEDED(i_dispatch=pThis->GetDocument())){ IHTMLDocument2 *i_htmldoc2=0; if (SUCCEEDED(i_dispatch->QueryInterface(IID_IHTMLDocument2, (void **)(&i_htmldoc2)))) { // force connection of IDocHostUIHandler ICustomDoc *i_customdoc=0; if (SUCCEEDED(i_htmldoc2->QueryInterface( IID_ICustomDoc, (void **)(&i_customdoc)))) { i_customdoc->SetUIHandler( &(pThis->m_xUIHandlerSink)); i_customdoc->Release(); } } i_dispatch->Release();}
3.在接口的实现中,控制用户界面
例如更改右键菜单
在STDMETHOD(ShowContextMenu)(DWORD,POINT*,IUnknown*,IDispatch*);
的实现中:
HRESULT CFMDBrowser::ShowContextMenu(DWORD,POINT*,IUnknown*,IDispatch*){ ..建立自己的菜单 return S_OK; }