接下来,我们要为IE增加一个按钮(注意不是toolbar,toolbar要复杂得多),基本这是一个注册表的魔术.打开RayBHO.rgs, 添加
- HKLM
- {
- NoRemove Software
- {
- NoRemove Microsoft
- {
- NoRemove 'Internet Explorer'
- {
- NoRemove Extensions
- {
- ForceRemove '{1AC31710-6759-484f-A129-A70C55485DA1}'
- {
- val ButtonText = s 'Hello,World'
- val Icon = s '%MODULE%,201'
- val HotIcon = s '%MODULE%,202'
- val CLSID = s '{1FBA04EE-3024-11d2-8F1F-0000F87ABD16}'
- val ClsidExtension = s '{057F3E68-6C2E-40A5-A641-E8CF9D6766F3}'
- val 'Default Visible' = s 'yes'
- }
- }
- }
- }
- }
- }
HKLM
{
NoRemove Software
{
NoRemove Microsoft
{
NoRemove 'Internet Explorer'
{
NoRemove Extensions
{
ForceRemove '{1AC31710-6759-484f-A129-A70C55485DA1}'
{
val ButtonText = s 'Hello,World'
val Icon = s '%MODULE%,201'
val HotIcon = s '%MODULE%,202'
val CLSID = s '{1FBA04EE-3024-11d2-8F1F-0000F87ABD16}'
val ClsidExtension = s '{057F3E68-6C2E-40A5-A641-E8CF9D6766F3}'
val 'Default Visible' = s 'yes'
}
}
}
}
}
}
当然,你也可以把这一项放在HKCU(Current User)下,这样的话,该Button只对当前用户起作用.
这些注册表项说明如下:
- ForceRemove '{1AC31710-6759-484f-A129-A70C55485DA1}' -- 该extersion的CLSID,请自己用GUID这个程序生成.
-
- val ButtonText = s 'Hello,World'
-
- val Icon = s '%MODULE%,201'
-
- val HotIcon = s '%MODULE%,202'
-
- val CLSID = s '{1FBA04EE-3024-11d2-8F1F-0000F87ABD16}'
-
- val ClsidExtension = s '{057F3E68-6C2E-40A5-A641-E8CF9D6766F3}'
-
- val 'Default Visible' = s 'yes'
ForceRemove '{1AC31710-6759-484f-A129-A70C55485DA1}' -- 该extersion的CLSID,请自己用GUID这个程序生成.
val ButtonText = s 'Hello,World' // 按钮上的文字说明
val Icon = s '%MODULE%,201' // 按钮的图标,可以是icon的绝对路径,也可以和我的例子一样从资源文件里加载.
val HotIcon = s '%MODULE%,202'// 鼠标悬停时按钮的图标,与Icon类似.
val CLSID = s '{1FBA04EE-3024-11d2-8F1F-0000F87ABD16}' //该CLSID意思为可执行,此值有特定含义,请小心修改.
val ClsidExtension = s '{057F3E68-6C2E-40A5-A641-E8CF9D6766F3}' // 这个是RayBHO的CLSID,即表示该按钮的动作连接到RayBHO这个com上,具体值有所不同,必须查询你自己的rgs文件得到.
val 'Default Visible' = s 'yes'//按钮可见.
当然你也可以不使用COM来响应按钮的动作,另外两个键Exec和Script,可以设置响应的程序或者脚本..这个不是重点.
现在编译,然后从IE的自定义工具栏将这个按钮拖出来...如图所示:
点点看.....结果呢? 当然是不起作用!
因为除以上步骤外,该com 对象还必须实现 IOleCommandTarget接口。
IOleCommandTarget包含QueryStatus和Exec两个方法,其中QueryStatus方法会被IE调用来获得当前菜单的状态. 当工具条按钮被点击时,com 对象的 IOleCommandTarget::exec 方法被调用,此时ncmdid 的值为 1;当菜单项被点击时,ncmdid 的值为 2。这样开发者就能区分工具条按钮和菜单项这两个不同操作
首先让CRayBHO继承IOleCommandTarget接口,最后我们得到这样得一个继承树
- class ATL_NO_VTABLE CRayBHO :
- public CComObjectRootEx<CComSingleThreadModel>,
- public CComCoClass<CHelloWorldBHO, &CLSID_HelloWorldBHO>,
- public IObjectWithSiteImpl<CHelloWorldBHO>,
- public IDispatchImpl<IHelloWorldBHO, &IID_IHelloWorldBHO, &LIBID_HelloWorldPluginLib, 1 , 0 >,
- public IDispEventImpl<1 ,CHelloWorldBHO,&DIID_DWebBrowserEvents2,&LIBID_SHDocVw,1 ,1 >,
- public IOleCommandTarget
class ATL_NO_VTABLE CRayBHO :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CHelloWorldBHO, &CLSID_HelloWorldBHO>,
public IObjectWithSiteImpl<CHelloWorldBHO>,
public IDispatchImpl<IHelloWorldBHO, &IID_IHelloWorldBHO, &LIBID_HelloWorldPluginLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
public IDispEventImpl<1,CHelloWorldBHO,&DIID_DWebBrowserEvents2,&LIBID_SHDocVw,1,1>,
public IOleCommandTarget
再COM_MAP里增加
- COM_INTERFACE_ENTRY(IOleCommandTarget)
COM_INTERFACE_ENTRY(IOleCommandTarget)
最终得到
- BEGIN_COM_MAP(CHelloWorldBHO)
- COM_INTERFACE_ENTRY(IHelloWorldBHO)
- COM_INTERFACE_ENTRY(IObjectWithSite)
- COM_INTERFACE_ENTRY(IOleCommandTarget)
- COM_INTERFACE_ENTRY(IDispatch)
- END_COM_MAP()
BEGIN_COM_MAP(CHelloWorldBHO)
COM_INTERFACE_ENTRY(IHelloWorldBHO)
COM_INTERFACE_ENTRY(IObjectWithSite)
COM_INTERFACE_ENTRY(IOleCommandTarget)
COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()
声明IOleCommandTarget的两个方法
-
- STDMETHOD(Exec)( const GUID*, DWORD nCmdID, DWORD, VARIANTARG*, VARIANTARG* pvaOut);
- STDMETHOD(QueryStatus)( const GUID* pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT* pCmdText);
// IOleCommandTarget
STDMETHOD(Exec)(const GUID*, DWORD nCmdID, DWORD, VARIANTARG*, VARIANTARG* pvaOut);
STDMETHOD(QueryStatus)(const GUID* pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT* pCmdText);
然后实现之,基本我们的重点放在Exec方法上...所以先给出QueryStatus的实现
- STDMETHODIMP CRayBHO::QueryStatus(const GUID* pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT* pCmdText)
- {
- if (cCmds == 0 ) return E_INVALIDARG;
- if (prgCmds == 0 ) return E_POINTER;
- prgCmds[ 0 ].cmdf = OLECMDF_ENABLED;
-
- return S_OK;
- }
STDMETHODIMP CRayBHO::QueryStatus(const GUID* pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT* pCmdText)
{
if (cCmds == 0) return E_INVALIDARG;
if (prgCmds == 0) return E_POINTER;
prgCmds[0].cmdf = OLECMDF_ENABLED;
return S_OK;
}
在Exce方法中,可以放入你的响应逻辑,或者更简单的,只是一个MessageBox响应. 这里我给出一段实际的Video Player的代码,这个代码可以为按钮添加下拉菜单,而这个菜单实际是保存在资源文件中的!并且你可以看到如何在Exce响应菜单上点击事件.
- STDMETHODIMP CRayBHO::Exec( const GUID*, DWORD nCmdID, DWORD, VARIANTARG*, VARIANTARG*)
- {
- if (m_spUnkSite == 0 || m_spWebBrowser == 0 ) return S_OK;
- HRESULT hRes = S_OK;
-
- CComPtr<IDispatch> pDocDisp;
- CComQIPtr<IHTMLDocument2> pHtmlDoc2;
- hRes = m_spWebBrowser->get_Document(&pDocDisp);
-
- if (SUCCEEDED(hRes) && pDocDisp)
- {
- hRes = pDocDisp->QueryInterface(IID_IHTMLDocument2, (void **)&pHtmlDoc2);
- if (SUCCEEDED(hRes) && pHtmlDoc2)
- {
- SHANDLE_PTR nBrowser = 0 ;
- m_spWebBrowser->get_HWND(&nBrowser);
- HWND hWndParent = (HWND)nBrowser;
-
- POINT pt;
- GetCursorPos(&pt);
-
- HINSTANCE hInstance = _AtlBaseModule.GetModuleInstance();
-
- HMENU hMenu = LoadMenu(hInstance,MAKEINTRESOURCE(IDR_MENU_POPUP));
- HMENU hMenuTrackPopup = GetSubMenu(hMenu, 0 );
-
- if (hMenuTrackPopup && hWndParent)
- {
- BOOL bIsChevron = FALSE;
- HWND hWndMenuParent = NULL;
- HWND hWndToolBar = NULL;
-
- hWndMenuParent = hWndParent;
- hWndToolBar = WindowFromPoint(pt);
-
- if (m_bIsIe7)
- {
- HWND hWndIe7ActiveTab = hWndParent;
- HWND hWnd = GetWindow(hWndParent, GW_CHILD);
-
-
-
- if (hWnd)
- {
- TCHAR szClassName[MAX_PATH];
- while (hWnd)
- {
- memset(szClassName,0 ,MAX_PATH);
- GetClassName(hWnd, szClassName, MAX_PATH);
- if (_tcscmp(szClassName,_T("TabWindowClass" ))==0 )
- {
-
- if (IsWindowVisible(hWnd))
- {
- hWnd = GetWindow(hWnd, GW_CHILD);
- while (hWnd)
- {
- memset(szClassName,0 ,MAX_PATH);
- GetClassName(hWnd, szClassName, MAX_PATH);
-
- if (_tcscmp(szClassName,_T("Shell DocObject View" ))==0 )
- {
- hWnd = FindWindowEx(hWnd, NULL, _T("Internet Explorer_Server" ), NULL);
- if (hWnd) hWndIe7ActiveTab = hWnd;
- break ;
- }
- hWnd = GetWindow(hWnd, GW_HWNDNEXT);
- }
- }
- }
- hWnd = GetWindow(hWnd, GW_HWNDNEXT);
- }
- }
-
- if (hWndIe7ActiveTab) hWndMenuParent = hWndIe7ActiveTab;
-
-
- }
-
- int nIDCommand = -1 ;
- BOOL bRightAlign = FALSE;
- if (hWndToolBar)
- {
- ScreenToClient(hWndToolBar,&pt);
- int nButton = (int )::SendMessage(hWndToolBar, TB_HITTEST, 0 , (LPARAM)&pt);
- if (nButton>0 )
- {
- TBBUTTON pTBBtn;
- memset(&pTBBtn, 0 ,sizeof(TBBUTTON));
- if (::SendMessage(hWndToolBar, TB_GETBUTTON, nButton, (LPARAM)&pTBBtn))
- {
- nIDCommand = pTBBtn.idCommand;
- RECT rcButton;
- if (::SendMessage(hWndToolBar,TB_GETRECT,nIDCommand,(LPARAM)&rcButton))
- {
- pt.x = rcButton.left;
- pt.y = rcButton.bottom;
- ClientToScreen(hWndToolBar,&pt);
-
- RECT rcWorkArea;
- SystemParametersInfo(SPI_GETWORKAREA, 0 ,(LPVOID)&rcWorkArea,0 );
- if (rcWorkArea.right-pt.x<150 )
- {
- bRightAlign = TRUE;
- pt.x = rcButton.right;
- pt.y = rcButton.bottom;
- ClientToScreen(hWndToolBar,&pt);
- }
- }
- }
- }
- else
- {
- GetCursorPos(&pt);
- bIsChevron = TRUE;
- }
- }
-
- UINT nFlags = TPM_NONOTIFY|TPM_RETURNCMD|TPM_LEFTBUTTON;
- if (bRightAlign) nFlags |= TPM_RIGHTALIGN;
- else nFlags |= TPM_LEFTALIGN;
-
-
- if (nIDCommand!=-1 && !bIsChevron) ::SendMessage(hWndToolBar, TB_PRESSBUTTON, nIDCommand, MAKELPARAM(1 ,0 ));
-
- int nCommand = TrackPopupMenu(hMenuTrackPopup, nFlags, pt.x, pt.y, 0 , hWndMenuParent, 0 );
-
- if (nIDCommand!=-1 && !bIsChevron) ::SendMessage(hWndToolBar, TB_PRESSBUTTON, nIDCommand, MAKELPARAM(0 ,0 ));
-
-
-
-
- BOOL bFound = FALSE;
- switch (nCommand)
- {
- case ID_CHIMP:
- {
- MessageBox(hWndParent,_T("Play Video" ),_T("IEVideo --Ray" ), MB_OK|MB_ICONEXCLAMATION);
- }
- break ;
- case ID_SELECT:
- {
- MessageBox(hWndParent,_T("Select Video" ),_T("IEVideo --Ray" ), MB_OK|MB_ICONEXCLAMATION);
-
- }
- break ;
- case ID_STOP:
- {
- MessageBox(hWndParent,_T("Stop Video" ),_T("IEVideo --Ray" ), MB_OK|MB_ICONEXCLAMATION);
- }
- break ;
- case ID_ABOUT:
- {
- MessageBox(hWndParent,_T("About IEVideo" ),_T("IEVideo --Ray" ), MB_OK|MB_ICONEXCLAMATION);
- }
- break ;
- }
- }
- }
- }
- return S_OK;
- }
转载出处: http://www.cnblogs.com/jcss2008/archive/2009/05/05/1449665.html