我搞定了,有三种方法。
有人想知道,说一下,我就贴出来。
我的帖子打错了,是WM_INITMENU。

解决方案 »

  1.   

    我搞定了,有三种方法。
    有人想知道,说一下,我就贴出来。
    (还有,我的帖子打错了,是对WM_INITMENU进行拦截,发现程序流程根本未到这里.
    当然,其他的什么WM_INITMENUPOPUP,WM_CONTEXTMENU...也是一样。
      

  2.   

    就这个问题,MicroSoft官方站点的说法是:
    A common requirement of hosting the WebBrowser control is the ability to override or add to the context menus that are displayed as the result of a right-click in the browser window. This is of particular interest to applications that are using the WebBrowser control to view rich content but do not want the user to know that HTML is being viewed. This is also advantageous for applications that do not want the user to be able to view the HTML source for the content. 
    There are two techniques available to achieve this. The first involves the use of the IDocHostUIHandler interface and allows an application to disable or replace the context menus. The second technique involves the use of the registry and allows the existing context menus to be extended.
    From  Topic:"Browser Overview"  Web Workshop provided 
    CCustomControlSite::XDocHostUIHandler::ShowContextMenu method Called from MSHTML to display a context menu.
    From    Q236312
        具体涉及的600多行代码还只是能做到在CHtmlView中不显示IE的快捷菜单,离我的要求还差很多。这里我也证实了IE既不是把菜单定义放在注册表中,也不是我设想的另一种方法。方法很复杂的。而且,我在我的Win95+IE4.0+VC6.0+ 401comupd平台上,实做了一下,竟然是无效页面错。MicroSoft的示例平台是WinNT。
    就这个问题,我的做法是:
    你有没有用过NetAnts,他实现了将固定的菜单项加到IE的快捷菜单上(我正是了解了NetAnts的做法后,才在MicroSoft官方站点上得到详细的文档的)。
    我查了一下注册表,在
    HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuEx下NetAnts加了两个主键,比如一个是Download &All by NetAnts。在HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt\Download &All by NetAnts
    下的一个字符串表明"c:\PROGRA~1\NETANTS\NAGetAll.htm",IE将加载NAGetAll.htm,但不会显示该文件 (MicroSoft的文档中说是将该文件加载到一个隐藏的对话框中) 。下面列出NAGetAll.htm:
    <script language="VBScript">
    On Error Resume Next
    set NetAntsApi = CreateObject( "NetAnts.API" )
    if err<>0 then
    Alert("NetAnts not properly installed on this PC!")
    else
    set links = external.menuArguments.document.links
    ReDim params(links.length*2)
    params(0)=external.menuArguments.document.Url
    for i = 0 to links.length-1
    params(i*2+1)=links(i).href
    params(i*2+2)=links(i).innerText
    next 
    NetAntsApi.AddUrlList params
            end if
    </script>
    看过去就是生成对象,从网页里获得信息,调用方法。
    我能不能采用类似的方法?我的项目是一个上下文无关文法的所有分析表的构造软件。我本来的想法是在IE的快捷菜单上加一项Popup的,他下面就列出所有的文法项目(MF_POPUP)和该文法的表项目(MF_STRING)。我实现了两个TabView,用户可能关掉TabView,所以我得在菜单里再列出所有的文法项目和该文法的表项目。我可以在框架的下拉菜单中列出,并不一定要在IE的快捷菜单上列出。但这样似乎我的软件连快捷菜单都没了(IE的明显不是我的)。
    我现在的想法是在我的软件的客户端第一次启动时,操纵注册表,在里面加上一项:列出所有文法和表格(&L)。也启动一个.htm文件。在他里面也创建一个自动化对象RidIE,也调用一个方法MsgDispatch,这个方法也是启动GF(或则GF已经启动),再去得到GF的App对象,再就是在某一位置(或则当前的位置)TrackPopupMenu,因为有多少文法是无法事先得知的,所以不能用MFC的消息映射机制,
    解决方法有两种。
    一种是使用未公开的技术:
    BOOL TrackPopupMenu(UINT nFlag,int x,int y,CWnd* pWnd,LPCRECT lpRect=NULL);
    第一个未写入文档的特性是:该函数的第一个参数nFlag还可以取另外两个值:TPM_NONOTIFY与TPM_RETURNCMD。从它们的名字可以看出来,TPM_NONOTIFY的作用是使TrackPopupMenu函数不发送菜单消息通知应用程序。TPM_RETURNCMD的作用是使函数将本该发送出去的菜单消息作为返回值返回。这时函数的返回值是UINT类型的,就是选中的菜单ID。这就是该函数第二个未写入文档的特性。注意,这个技术将一直有效,因为在新的TrackPopupMenuEx函数中,该技术被公开了。
    这样,不用担心什么用来接收菜单命令消息的窗口,我设为NULL。
    方法MsgDispatch由主框架去得到两个TabView,再利用这一技术我可以在那个被IE间接调用的方法MsgDispatch中,根据TrackPopupMenu的返回值决定怎样去发消息给两个TabView,让他们负责去切换(参见TabView处)。
    比如:返回值是IDM_GRAMMA+302,则就是TabViewG的第四项和TabViewI的第三项。
    另一种解决方法是正规的:
    就是去重载CMainFrame::OnCmdMsg(实际上是CcmdTarget的)。对ID大于IDM_GRAMMA的都处理(发消息给TabView),不处理的返回0。我用spy程序看了一下,消息没有发到view窗口来,而且view窗口离
    Internet Explorer_Server对象还有两级距离,我想还有一种可行的办法就是,先取到该窗口句柄,然后用子类化技术截取该消息。。而且所得到的效果是最理想的,和我的预计是一样的效果。我模拟在CMainFrame中截获WM_INITMENU,再InsertMenu了一项,非常好。实现起来,也是较容易的。正如你说的那样:从View到Internet Explorer_Server还有两级。我看了一下是ShellEmbedding和ShellDocObjectView。因此,我可以用SDK函数EnumChildWindows和回调函数EnumChildProc来得到Internet Explorer_Server的句柄,在EnumChildProc(第二次被调用)里完成子类化的工作。
    MicroSoft官方意见效果不太好,又要了解IE的内部架构和一系列的接口,而且实现起来代码量很大(MicroSoft已经提供),奇怪的无效页面错。
    Nothing is impossible in the digital world--OUR WORLD.