点击“开始”按钮时,如何弹出自定义菜单?好像在哪见过,找不到了。

解决方案 »

  1.   

    是的,忘见在哪见过一个vb的小例子,窗体运行起来后,按钮就被替换了,点击“开始”,执行了一句msgbox,谁那有这个例子?
      

  2.   

    楼主参考一下这个
    http://topic.csdn.net/t/20011122/15/383148.html
      

  3.   

    也不用什么特殊的例子,开始按钮set一个新的parent之后就跑别处去了。同样,也可以将自己的一个按钮setparent到开始处。
      

  4.   

    谢谢各位,搞定了,把代码贴出来:
    'Module
    Option ExplicitPublic lpPrevWndProc     As Long
    Private Declare Function MapWindowPoints Lib "user32" (ByVal hwndFrom As Long, ByVal hwndTo As Long, lppt As Any, ByVal cPoints As Long) As Long
    Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    Private Declare Function PtInRect Lib "user32" (lpRect As RECT, ByVal x As Long, ByVal y As Long) As Long
    Private Declare Function GetClientRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
    Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As LongPrivate Type POINTAPI
            x As Long
            y As Long
    End TypePublic Type RECT
            Left As Long
            Top As Long
            Right As Long
            Bottom As Long
    End TypePrivate Const WM_LBUTTONUP = &H202
        
        
    Public Function ButtonProc(ByVal hw As Long, ByVal uMsg As _
            Long, ByVal wParam As Long, ByVal lParam As Long) _
            As Long Dim pt As POINTAPI
     Dim Rct As RECT
     
         If uMsg = WM_LBUTTONUP Then
        
                  Call GetCursorPos(pt)
                  Call GetClientRect(hw, Rct)
                  Call MapWindowPoints(0, hw, pt, 1)
                  If PtInRect(Rct, pt.x, pt.y) > 0 Then
                        MsgBox "You   had   clicked   the   new   button!"
                  End If
                  
         End If
              
            ButtonProc = CallWindowProc(lpPrevWndProc, hw, _
                  uMsg, wParam, lParam)
                  
    End Function'Form
    Option Explicit
      
    Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
    Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
    Private Declare Function ShowWindow Lib "user32" (ByVal hwnd As Long, ByVal nCmdShow As Long) As Long
    Private Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
    Private Declare Function CreateWindowEx Lib "user32" Alias "CreateWindowExA" (ByVal dwExStyle As Long, ByVal lpClassName As String, ByVal lpWindowName As String, ByVal dwStyle As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hWndParent As Long, ByVal hMenu As Long, ByVal hInstance As Long, lpParam As Any) As Long
    Private Declare Function DestroyWindow Lib "user32" (ByVal hwnd As Long) As Long
    Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As LongConst GWL_WNDPROC = (-4)
    Const WS_CHILD = &H40000000
    Const WM_LBUTTONDOWN = &H201
    Const SW_HIDE = 0
    Const SW_NORMAL = 1Dim tWnd     As Long
    Dim bWnd       As Long
    Dim ncWnd       As LongPrivate Sub Form_Load()
            
    Dim R     As RECT
      
        tWnd = FindWindow("Shell_TrayWnd", vbNullString)
          
        bWnd = FindWindowEx(tWnd, ByVal 0&, "BUTTON", vbNullString)
          
        GetWindowRect bWnd, R
          
        ncWnd = CreateWindowEx(ByVal 0&, "BUTTON", "Hello!", WS_CHILD, 0, 0, R.Right - R.Left, R.Bottom - R.Top, tWnd, ByVal 0&, App.hInstance, ByVal 0&)
        
        lpPrevWndProc = SetWindowLong(ncWnd, GWL_WNDPROC, AddressOf ButtonProc)
        
        ShowWindow ncWnd, SW_NORMAL
          
        ShowWindow bWnd, SW_HIDE
              
    End SubPrivate Sub Form_Unload(Cancel As Integer)
              
            ShowWindow bWnd, SW_NORMAL
              
            DestroyWindow ncWnd
    End Sub
      

  5.   

    楼主使用的是占位法,应该算是不错的方法.
    理论上来说是可以直接hook开始按钮的,希望楼主再接再厉.
      

  6.   

    '模块中
    Option Explicit
    Private Type POINTAPI
            x As Long
            y As Long
    End TypePrivate Const WM_LBUTTONDBLCLK = &H203
    Private Const WM_LBUTTONDOWN = &H201
    Private Const WM_LBUTTONUP = &H202
    Private Const WM_MBUTTONDBLCLK = &H209
    Private Const WM_MBUTTONDOWN = &H207
    Private Const WM_MBUTTONUP = &H208
    Private Const WM_MOUSEACTIVATE = &H21
    Private Const WM_MOUSEFIRST = &H200
    Private Const WM_MOUSEHOVER = &H2A1
    Private Const WM_MOUSELAST = &H209
    Private Const WM_MOUSELEAVE = &H2A3
    Private Const WM_MOUSEMOVE = &H200
    Private Const WM_MOUSEWHEEL = &H20A
    Private Const WM_RBUTTONDBLCLK = &H206
    Private Const WM_RBUTTONDOWN = &H204
    Private Const WM_RBUTTONUP = &H205Private Const WH_MOUSE = 7
    Private Const HC_ACTION = 0
    Private Const WH_MOUSE_LL = 14
      
    Private Declare Function SetWindowsHookEx Lib "user32" Alias _
            "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, _
            ByVal hmod As Long, ByVal dwThreadId As Long) As Long
    Private Declare Function UnhookWindowsHookEx Lib "user32" _
            (ByVal hHook As Long) As Long
    Private Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, _
             ByVal nCode As Long, ByVal wParam As Long, lParam As Any) As Long
    '寻找窗口列表中第一个符合指定条件的顶级窗口(在vb里使用:FindWindow最常见的一个用途是获得ThunderRTMain类的隐藏窗口的句柄;该类是所有运行中vb执行程序的一部分。获得句柄后,可用api函数GetWindowText取得这个窗口的名称;该名也是应用程序的标题)
    Private Declare Function FindWindow Lib "user32" _
                    Alias "FindWindowA" (ByVal lpClassName As String, _
                                         ByVal lpWindowName As String) As Long
    '在窗口列表中寻找与指定条件相符的第一个子窗口
    Private Declare Function FindWindowEx Lib "user32" _
                    Alias "FindWindowExA" (ByVal hWnd1 As Long, _
                                           ByVal hWnd2 As Long, _
                                           ByVal lpsz1 As String, _
                                           ByVal lpsz2 As String) As Long'返回包含了指定点的窗口的句柄。忽略屏蔽、隐藏以及透明窗口
    Private Declare Function WindowFromPoint Lib "user32" _
                    (ByVal xPoint As Long, _
                                             ByVal yPoint As Long) As Long
    '获取鼠标指针的当前位置
    Private Declare Function GetCursorPos Lib "user32" _
                    (lpPoint As POINTAPI) As LongPrivate hHook     As Long         '   handle   of   Hook   Procedure
    Sub EnableHook()
            If hHook = 0 Then
                  hHook = SetWindowsHookEx(WH_MOUSE_LL, AddressOf MouseHookProc, App.hInstance, 0)
            End If
    End Sub
    Sub FreeHook()
    Dim ret     As Long
    If hHook <> 0 Then
            ret = UnhookWindowsHookEx(hHook)
            hHook = 0
    End If
    End Sub
    Private Function MouseHookProc(ByVal code As Long, ByVal wParam As Long, _
                                      ByVal lParam As Long) As Long
        If code < 0 Then
              MouseHookProc = CallNextHookEx(hHook, code, wParam, lParam)
              Exit Function
        End If
    Dim tWnd As Long, bWnd As Long, bWnd2 As Long, pt As POINTAPI    If wParam = WM_LBUTTONDOWN Then
            tWnd = FindWindow("Shell_TrayWnd", vbNullString)
            bWnd = FindWindowEx(tWnd, ByVal 0&, "BUTTON", vbNullString)
            GetCursorPos pt
            bWnd2 = WindowFromPoint(pt.x, pt.y)
            If bWnd2 = bWnd Then
                MouseHookProc = 1       '表示不处理这个讯息
                Debug.Print "被Hook了"
                Exit Function
            End If
        End If
        If wParam = WM_LBUTTONUP Then
            tWnd = FindWindow("Shell_TrayWnd", vbNullString)
            bWnd = FindWindowEx(tWnd, ByVal 0&, "BUTTON", vbNullString)
            GetCursorPos pt
            bWnd2 = WindowFromPoint(pt.x, pt.y)
            If bWnd2 = bWnd Then
                Debug.Print "被Hook了"
                Form1.PopupMenu Form1.mnuS 'mnuS是窗口Form1中的菜单名
                MouseHookProc = 1       '表示不处理这个讯息
                Exit Function
            End If
        End If
        MouseHookProc = 0       '表示要处理这个讯息
        Call CallNextHookEx(hHook, code, wParam, lParam)
    End Function
      
      'Form中
    Private Sub Form_Load()
    Call EnableHook
    End Sub
    Private Sub Form_Unload(Cancel As Integer)
    Call FreeHook
    End Sub
      
      

  7.   

    6楼代码貌似是:得到开始菜单位置及大小,再自己画了一个盖在上面....再对这个自绘的按钮,进行子类化,得到其鼠标单击消息,进而弹出菜单;8楼的流程貌似如下:先挂一个全局鼠标HOOK,再在每次鼠标按下时,检测当前鼠标下面是不是开始按钮..如果是,吃之~~~然后在鼠标抬起时,也检测,如果是,就弹出自定义的菜单,再将此次消息吃之~~以上方法都有用.不过,我建议在基于以上方法之上,还要把WIN键给挂了~~~~以及CTRL + ESC组合键.我这里有一个以前写的打CS用的屏蔽WIN键的代码,也是用的_LL HOOK,因此也只能在2000及以上系统里使用.楼主可以自己添加一下CTRL + ESC的过滤,代码在此下载:http://www.m5home.com/bbs/dispbbs.asp?boardID=10&ID=517&page=1
      

  8.   

    Sorry! 是我理解错了,当我没说 ^_^
      

  9.   

    19L的朋友,你的菜单做了吗?阿勇没有在贴出来的代码里写菜单,当编译成.exe执行时,由于VB出现‘428’错误,
    所以就崩了,还有为什么你的开始没有了?因为Unload事件未来得及执行,因为程序意外崩了嘛!!
      

  10.   

    19L的朋友,你的菜单做了吗?阿勇没有在贴出来的代码里写菜单,当编译成.exe执行时,由于VB出现‘428’错误,
    所以就崩了,还有为什么你的开始没有了?因为Unload事件未来得及执行,因为程序意外崩了嘛!!
      

  11.   

    跨进程子类化也是可以的不过比较麻烦,要么用DLL,要么就内嵌汇编.....因为,总得要完成这几步:一,子类化.
       这一步,在2000及以后系统里,只允许本进程了,因此需要想办法在别人进程里执行SetWindowLong;二,消息传递.
       子类化了,消息还得从目标进程发到本进程;如果要求能修改,还得发回去.三,卸载子类化.
       这一步很重要,同时也需要在目标进程里完成...我这里收藏了一个DLL,等我本本拿回来后就发上来,里面已经封装好了相应的函数,使用起来超简单,很容易就能做到跨进程子类化....
      

  12.   

    ***************************************************************************   思想决定行动,交流产生力量。  
    程序员在深圳QQ群大集   专业分类:   
    程序员在深圳JAVA群4247660   
    程序员在深圳c++群15195967   
    程序员在深圳.NET群Ⅱ:12203296   
    程序员在深圳TCP/IP协议栈开发:16956462   
    程序员在深圳JS & AJAX群:12578377   
    程序员在深圳英语学习群:23864353   
    深序员在深圳VB:11055959   
    程序员在深圳c++Ⅱ17409451   
    程序员在深圳c++群15195967   
    程序员在深圳嵌入式开发群37489763   
    程序员在深圳移动开发群31501597   
    程序员在深圳创业群33653422   不限专业分类:   
    高级群:17538442   
    第三群:2650485   
    第二群:7120862   
    第五群:29537639   
    第四群:28702746   
    第六群:10590618   
    第七群:10543585   
    第八群:12006492   
    第九群:19063074   
    第十群:2883885   
    第十一群:25460595   
    第十二群:9663807   深圳程序员QQ群联盟成立两年多,拥有三十个以上的QQ群,人数达两千多人,有30%以上的成员的经验丰富  的老手,包括国内外顶级大公司的成员(如微软、IBM,SUN,华为)、国内著名高校和研究院成员,和有  丰富实践经验的高级程序(包括参加过上亿元的项目的架构师),有很热爱技术的成员(包括自己写过嵌入  式操作系统),还有少数女程序员。  现推介如下QQ群,如有兴趣速速加入:深程高级群:17538442(此群不欢迎新手,已经在深圳工作的,月薪  6K以下的不欢迎)c++:15195967 .NET:12203296 mobile:31501597嵌入式:37489763 JAVA:4247660     
    ——————————————————————————————————————————    
    希望大家不要认为群能给你送来什么,这只是一个平台,让同等水平的程序员有个交流的机会或许能得到  一点信息或许能带来一点启发。  
    有人说常聊QQ的人肯定技术不怎么样,但其实很多技术高朋友不需要做一些简单的重复劳动所以还是有  时间聊天的。   *****************************************************************************
      

  13.   

    简单的说,子类化就是创建一个新的窗口消息处理过程,并将其插入到原先的默认窗口消息处理过程之前。
    子类化一般有三类:
         1、实例子类化(instance subclassing):从窗口或控件的单一实例截获消息,这种子类化技术最普遍。
         2、全局子类化(global subclassing):能够截获从相同的窗口类创建出来的多个窗口或控件的消息。
         3、超类化(superclassing):和全局子类化很类似,区别在于可以应用在新的窗口类上面。