接下来,我们要为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'
}
}
}
}
}
}
当然,你也可以把这一项放在HKCU(Current User)下,这样的话,该Button只对当前用户起作用.
这些注册表项说明如下:
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, /*wMajor =*/ 1, /*wMinor =*/ 0>,
public IDispEventImpl<1,CHelloWorldBHO,&DIID_DWebBrowserEvents2,&LIBID_SHDocVw,1,1>,
public IOleCommandTarget
再COM_MAP里增加
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()
声明IOleCommandTarget的两个方法
// 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;
}
在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);
// looking for the Internet Explorer_Server window
// this window should be a parent for TrackPopupMenu
if(hWnd)
{
TCHAR szClassName[MAX_PATH];
while(hWnd)
{
memset(szClassName,0,MAX_PATH);
GetClassName(hWnd, szClassName, MAX_PATH);
if(_tcscmp(szClassName,_T("TabWindowClass"))==0)
{
// the active tab should be visible
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;
//strHWndMenuParent = _ltoa(hWndMenuParent, 10);
}
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;
// draw pressed button
if(nIDCommand!=-1 && !bIsChevron) ::SendMessage(hWndToolBar, TB_PRESSBUTTON, nIDCommand, MAKELPARAM(1,0));
// popup the menu
int nCommand = TrackPopupMenu(hMenuTrackPopup, nFlags, pt.x, pt.y, 0, hWndMenuParent, 0);
// release the button
if(nIDCommand!=-1 && !bIsChevron) ::SendMessage(hWndToolBar, TB_PRESSBUTTON, nIDCommand, MAKELPARAM(0,0));
//CStringArray* m_EvNameArr = new CStringArray();
//m_EvNameArr->Add(strHWndMenuParent);
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;
}
最后的效果如下:
很有意思的是, 我被认为是windows的粉丝,但其实我工作里搞的是linux的driver. 论坛里的风气常常喜欢比较A比较B,或者痛斥A痛斥B, 但你深入了解了么?
- 大小: 32.2 KB
- 大小: 19.3 KB
分享到:
相关推荐
a little bit huge FUcking guy this bitch web!
欧胜微电子有限公司(伦敦股票交易所:WLF.L)日前宣布:作为世界上音效最好的音频数字模拟转换器(DAC),其AudioPlus Pure Sound高端音频系列中的旗舰芯片WM8741,在Linn公司新的Akurate DS数字流源的音效体验中起到了...
AT指令集 全球定位系统(GPS)系统由于性能优异,在民用上应用范围很广。其可以用于空中交通管理、大地精密测量、摄影测量、监测地壳运动、火山活动、野外调查和勘探的...本文主要介绍与短消息开发相关的GSM AT指令。
NULL 博文链接:https://raylinn.iteye.com/blog/650850
工具“l9000cassdecode”可用于对 Linn9000 和 LinnSequencer 的数据盒(磁带)格式进行解码。 根据数据盒内容,提取 Linn9000 相关文件,例如以下文件类型:DSQ、MSQ、ALL、ASQ、ADS、AMS、ALM、SND、KIT。 可选:...
根据数据盒带的内容,提取与Linn9000相关的文件,例如,使用以下文件类型:DSQ,MSQ,ALL,ASQ,ADS,AMS,ALM,SND,KIT。 可选:tar文件导出。 注意:例如,可以通过包含在项目“ linn9000fs”中的工具“ l9000fs...
NULL 博文链接:https://raylinn.iteye.com/blog/743336
NULL 博文链接:https://raylinn.iteye.com/blog/670006
NULL 博文链接:https://raylinn.iteye.com/blog/520213
Linn-Wilhelmsen-js1-ma1
linn-gaarder-js1-ca
用于Volumio的BubbleUPnP服务器安装程序 这是一个直接在Volumio系统上安装BubbleUPnP Server的帮助程序工具。 可用于流化潮汐和Qobuz(使用MDP)。 您需要的是OpenHome渲染... 由于,现在只能通过SSH安装第三方或开发
在 Kinsky 中创建播放列表很棒,我想远程保存它们,如果您使用 Linn 的 Songbox,您可以这样做。 播放列表上的每个曲目都是一个 URI,它允许灵活地从多个媒体服务器创建播放列表,此外元数据的 URI 也与播放列表中的...
用亲和层析法从PhaseoZus lunatus Linn vel aff的种子中纯化出一种对人类A型血专一的凝集素.该凝集素的粗浸提液都只对A型血细胞凝集,而对 B、O型绝不凝集.当纯化的凝集素浓度为0.98μg/mL时,即能凝集A型血细胞,...
快来体验MinGW64 for Windows 64,即x86_64-w64-mingw32,这是 GCC 在 Windows 平台上的移植,和 Cygwin 不...目前版本 4.7.0 ,该发布由我(ray_linn)编译,如发现任何问题,请到 http://mingw-w64.sf.net/上提问。
使用ANTLR之后,我在一天之内就完成了整个编译器前端的开发工作,从而能够迅速开始处理真正的业务逻辑。从那时起,我就被它强大的功能所深深吸引。简而言之,ANTLR能够解决别的工具无法解决的问题。 软件改变了...
采用乙醇浸提法对飞扬草多酚进行提取,并开展了飞扬草多酚...抗氧化性研究表明,飞扬草提取液能清除・OH自由基,在多酚质量浓度为3.759 mg/mL时,清除率约为50%,说明清除能力较强,这为飞扬草药用开发和利用奠定了理论基础。
D-Link路由器当交换机配置步骤.doc
以湿地植物菖蒲为研究对象,在水培条件下观察3个浓度梯度的氮磷污水(处理组1、2、3依次为N:40 mg/L、P:4 mg/L;N:80 mg/L、P:8 mg/L;N:120 mg/L、P:12 mg/L)对其胁迫后的根系释氧和通气组织的变化规律,研究...