Detect events in other apps?

Just starting out? Need help? Post your questions and find answers here.
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Detect events in other apps?

Post by PB »

Is it possible to detect events in other apps? I basically want to add menus
to another app's window (which I can do) but then have my app know when
these menus are selected.
BrendanE
User
User
Posts: 63
Joined: Tue Nov 11, 2003 2:04 pm
Location: Derbyshire, England

Post by BrendanE »

Hi,
You need to write a hook function (never done it myself but have looked into it.....)

look here for something to get you started.....

http://msdn.microsoft.com/library/defau ... ooks32.asp
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Post by PB »

> You need to write a hook function

I thought so, but I'm not sure how to start. Your link will help, thanks.
Sparkie
PureBatMan Forever
PureBatMan Forever
Posts: 2307
Joined: Tue Feb 10, 2004 3:07 am
Location: Ohio, USA

Post by Sparkie »

Facing the challenge you presented, I've put together a hook/dll that works fine here on WinXP. I'm still cleaning this up a bit so I'm not posting the entire code at this time. I figured I'd post this, hoping it helps you in getting started. :)

This was my first attempt at creating a DLL and my first attempt using a hook/DLL. I must say that PB and jaPBe both make it easier than I had expected 8) :D

My main app (menutext.pb) uses

Code: Select all

hDLL = OpenLibrary(0, "mnutxt.dll")
hmyHook = SetWindowsHookEx_(#WH_MSGFILTER, GetProcAddress_(hDLL, "MyMessageProc"), hDLL, 0)
...
...
...
End
UnhookWindowsHookEx_(hmyHook) 
CloseLibrary(0)
Then the DLL I created (mnutxt.dll), handles the menu messages and then sends back the menu text to the app that created the hook.

Inside the DLL I used the following:

Code: Select all

ProcedureDLL MyMessageProc(code.l, wParam.l, lParam.l)
MENUITEMINFO ;- structure needed for GetMenuItemInfo_()
FindWindow_() ;- to find my app to display menu text
GetMenu_() ;- to get handle to menu being selected
GetMenuItemInfo_() ;- to get the menu item text
FindWindowEx_() ;- to find my TextGadget for displaying the menu text found
SendMessage_() ;- to send text to my TextGadget
CallNextHookEx_() ;- for procedure return
There's most likely more than one way to get the results you are looking for, so don't take mine as the last word. :wink:
What goes around comes around.

PB 5.21 LTS (x86) - Windows 8.1
BrendanE
User
User
Posts: 63
Joined: Tue Nov 11, 2003 2:04 pm
Location: Derbyshire, England

Post by BrendanE »

Hi Sparkie,

I also had a play with writing a hook the same way pretty much.. except I have some exported DLL functions to install and remove the hook. I give the DLL a callback function to call my App with when a message is passed through... trouble is it's not working as I expected - it appears that my hook function is only getting messages that are destined for my own app window - and not for all apps under the desktop thread as the MSDN docs suggest. Any ideas what I've done wrong without me posting the code?
Sparkie
PureBatMan Forever
PureBatMan Forever
Posts: 2307
Joined: Tue Feb 10, 2004 3:07 am
Location: Ohio, USA

Post by Sparkie »

@BrendanE

The code for the hook I'm using works pretty good so far. It works on most windows, but not all. :? Right now it's set up so it only catches menu item clicks on menu items whose content is of the string type.

I should have it cleaned up enough to post some code later tonight or early tomorrow. I'm new to DLL's and hooks, so my code will definately need some expert clean up. Even so, maybe it will help you in your project. :)

As for your current problem, it's hard to say what the problem is without seeing some of the code. I do know (I think) that in order for the hook to work outside your app, you must use a shared DLL.

Whst type of hook are you specifying in SetWindowsHookEx_() idHook parameter?
What goes around comes around.

PB 5.21 LTS (x86) - Windows 8.1
BrendanE
User
User
Posts: 63
Joined: Tue Nov 11, 2003 2:04 pm
Location: Derbyshire, England

Post by BrendanE »

Sparkie,
Thanks for that - yes I've done it just as you have - the hook function is in a shared dll - as is the installHook function below...

Code: Select all

ProcedureDLL.l installHook(hDLL, *hookFunction)
  hHook =  SetWindowsHookEx_(#WH_MSGFILTER,	*hookFunction, hDLL, 0)
EndProcedure


ProcedureDLL.l MenuFilter(code.l, wParam.l, lParam.l) 
  If *callBackFunction <> 0
    *msg.MSG = lParam
    If code = #MSGF_MENU
      If *msg\message = #WM_MENUSELECT
        ; a menu item has been selected
        CallFunctionFast(*callBackFunction, *msg\hwnd, *msg\wParam, *msg\lParam)
      EndIf
    EndIf
  EndIf
  
  ProcedureReturn CallNextHookEx_(hHook, code, wParam, lParam)
EndProcedure


.............. in my app I'm calling this to set up the hook

CallFunction(0, "installHook", hDLL, GetProcAddress_(hDLL, "MenuFilter"))


my hook function simply check for any #MSGF_MENU code and calls back a callback function (which is in my app).... which works fine for the app events themselves - but I see nothing for event desitined for any other windows.... very puzzling.

I'm not writing any specific app - it was an intruiging learning excercise - seems like I still have to learn a few things ;)
Sparkie
PureBatMan Forever
PureBatMan Forever
Posts: 2307
Joined: Tue Feb 10, 2004 3:07 am
Location: Ohio, USA

Post by Sparkie »

@BrendanE - Here's what I have so far. It's not complete but it is 85% functional in that not all menu items are being detected at this time. Tested and working on WinXP with PB3.91F

I'm posting this so you can see what is working for me and maybe it will give you a clue as to what might be going wrong in your code.

This is my dll...
mnutxt.dll

Code: Select all

ProcedureDLL MyMessageProc(code.l, wParam.l, lParam.l)
  #MIIM_ID = $2
  #MIIM_TYPE = $10
  #MF_POPUP = $10
  #MSGF_MENU = $2
  #WM_MENUSELECT = $11F
  winText$ = Space(256)                                 ; init buffer for window text
  
  mItem.MENUITEMINFO                                    ; Structure for menu info
  mItem\cbSize = SizeOf(MENUITEMINFO)                   ; required
  mItem\fMask = #MIIM_TYPE | #MIIM_ID                   ; mask flag(s)
  
  hMyWin = FindWindow_("WindowClass_0","Get_Menu_Info") ; our window for displaying results
  *mymsg.MSG = lParam                                   ; MSG structure holds info
  menuMessage = *mymsg\message                          ; get menu message
  
  If code = #MSGF_MENU And menuMessage = #WM_MENUSELECT ; only concerned with menu being selected
    hMenu = *mymsg\lParam                               ; handle to menu
    menuType = *mymsg\wParam>>16 & $FFFF                ; hiword of wparam = menuitem with or without submenu?
    menuIndex = *mymsg\wParam & $FFFF                   ; loword of wparam = menu index or menuitem ID
    
    If menuType&#MF_POPUP <>0                           ; determine if menuitem is a popup
      subYN.l = #True                                   ; item is a popup
    Else
      subYN.l = #False                                  ; item is not a popup
    EndIf
    
    menuText$ = ""                                      ; init string holder to null                               
    mItem\dwTypeData = @menuText$                       ; init null string into mItem
    GetMenuItemInfo_(hMenu, menuIndex, subYN, @mItem)   ; first call gets the string size
    menuText$ = Space(mItem\cch+1)                      ; add 1 to string size
    mItem\dwTypeData = @menuText$                       ; put sized string into mItem
    mItem\cch +1                                        ; add one to string size (SDK says so)
    GetMenuItemInfo_(hMenu, menuIndex, subYN, @mItem)   ; second call puts the text into mItem
    GetWindowText_(*mymsg\hwnd, @winText$, 256)         ; get text of calling window for display    
    
    hWinHndGadget = ChildWindowFromPoint_(hMyWin, 120, 10)        ; locate TextGgadget to display window handle
    SendMessage_(hWinHndGadget, #WM_SETTEXT, 0, Str(*mymsg\hwnd)) ; send window handle to my app gadget
    
    hWinTxtGadget = ChildWindowFromPoint_(hMyWin, 120, 30)        ; locate TextGadget to display window text
    SendMessage_(hWinTxtGadget, #WM_SETTEXT, 0, winText$)         ; send window text to my app gadget    
    
    hMnuIdGadget = ChildWindowFromPoint_(hMyWin, 120, 70)         ; locate TextGadget to display Menu ID
    SendMessage_(hMnuIdGadget, #WM_SETTEXT, 0, Str(mItem\wID))    ; send menu id to my app gadget
    
    hMenuTxtGadget = ChildWindowFromPoint_(hMyWin, 120, 90)       ; locate TextGadget to display Menu text
    SendMessage_(hMenuTxtGadget, #WM_SETTEXT, 0, menuText$)       ; send menu text to my app gadget
  EndIf
  
  ProcedureReturn CallNextHookEx_(@MyMessageProc(), code, wParam, lParam)
EndProcedure
And my main app. Not much to look at but then this is just a learn-to-hook project for me. ;)

menuhook.pb

Code: Select all

Enumeration
  #Window_0
EndEnumeration

Enumeration
  #Window_Handle_Label
  #Window_Handle
  #Window_Text_Label
  #Window_Text
  #Menu_ID_Label
  #Menu_ID
  #Menu_Text_Label
  #Menu_Text
  #Button_Hook
  #Button_Quit
EndEnumeration

If OpenWindow(#Window_0, 0, 0, 550, 160, #PB_Window_ScreenCentered | #PB_Window_SystemMenu, "Get_Menu_Info")
  If CreateGadgetList(WindowID(0))
    TextGadget(#Window_Handle_Label, 10, 10, 100, 20, "Window Handle:")
    TextGadget(#Window_Handle, 120, 10, 420, 20, "")
    
    TextGadget(#Window_Text_Label, 10, 30, 100, 20, "Window Text:")
    TextGadget(#Window_Text, 120, 30, 420, 40, "")
    
    TextGadget(#Menu_ID_Label, 10, 70, 100, 20, "Menu Item ID:")
    TextGadget(#Menu_ID, 120, 70, 420, 20, "")
    
    TextGadget(#Menu_Text_Label, 10, 90, 100, 20, "Menu Item Text:")
    TextGadget(#Menu_Text, 120, 90, 420, 20, "")
    
    ButtonGadget(#Button_Hook, 10, 130, 150, 20, "Start hooking menus")
    ButtonGadget(#Button_Quit, 470, 130, 70, 20, "Quit")
  EndIf
  SetWindowPos_(WindowID(#Window_0),#HWND_TOPMOST,0,0,0,0,#SWP_NOMOVE|#SWP_NOSIZE) ; keep window on top
EndIf

Repeat
  
  Event = WaitWindowEvent()
  
  Select Event
    
    Case #PB_Event_Gadget
      
      Select EventGadgetID()
        Case #Button_Hook
          If GetGadgetText(#Button_Hook) = "Start hooking menus"
            hDLL = OpenLibrary(0, "mnutxt.dll")
            If hDLL
              hmyHook = SetWindowsHookEx_(#WH_MSGFILTER, GetProcAddress_(hDLL, "MyMessageProc"), hDLL, 0)
              SetGadgetText(#Button_Hook, "Stop hooking menus")
            Else
              MessageRequester("Error", "Not able to open file: mnutxt.dll", #MB_ICONERROR)
            EndIf
            
          ElseIf EventGadgetID() = #Button_Hook And GetGadgetText(#Button_Hook) = "Stop hooking menus"
              UnhookWindowsHookEx_(hmyHook) 
              CloseLibrary(0)
              hDLL = #False
              SetGadgetText(#Window_Handle, "")
              SetGadgetText(#Window_Text, "")
              SetGadgetText(#Menu_ID, "")
              SetGadgetText(#Menu_Text, "")
              SetGadgetText(#Button_Hook, "Start hooking menus")
          EndIf
          
        Case #Button_Quit
          quit = #True
      EndSelect
      
      
    Case #PB_Event_CloseWindow
      quit = #True

  EndSelect

Until quit = #True
UnhookWindowsHookEx_(hmyHook) 
CloseLibrary(0)
hDLL = #False
End
What goes around comes around.

PB 5.21 LTS (x86) - Windows 8.1
BrendanE
User
User
Posts: 63
Joined: Tue Nov 11, 2003 2:04 pm
Location: Derbyshire, England

Post by BrendanE »

@Sparkie, thanks alot, that's great. It works just fine for me too - now to go and figure out what's wrong with my code!

Thanks.
Wolf
Enthusiast
Enthusiast
Posts: 232
Joined: Sat Apr 03, 2004 12:00 pm
Location: S.T

Post by Wolf »

Thanks Sparkie.

Your codes is always great :wink:
Sparkie
PureBatMan Forever
PureBatMan Forever
Posts: 2307
Joined: Tue Feb 10, 2004 3:07 am
Location: Ohio, USA

Post by Sparkie »

You are both very welcome. Glad I could help. :)
What goes around comes around.

PB 5.21 LTS (x86) - Windows 8.1
funk.munich
User
User
Posts: 11
Joined: Wed Apr 26, 2006 9:27 pm

Post by funk.munich »

Hi Sparkie,

it's long time ago that you have entered this code but only now I have read it
and maybe you can give me a short assist.

I would like to check buttons but I don't find any information about it.

Do you know if it is possible? And if yes, where I can find more information
about it?

Many thanks in advance,
Daniel

BTW, is it possible to check if the text from a button is truncated or not.
[ Save ]

-> truncated
[ Sav ]
Sparkie
PureBatMan Forever
PureBatMan Forever
Posts: 2307
Joined: Tue Feb 10, 2004 3:07 am
Location: Ohio, USA

Post by Sparkie »

Wow, that was some ugly noobie code by me. :oops:

I am not exactly sure what it is you are trying to accomplish here Daniel. Are you trying to detect button clicks or menu clicks :?:
What goes around comes around.

PB 5.21 LTS (x86) - Windows 8.1
acidburn
User
User
Posts: 23
Joined: Mon Aug 07, 2006 1:37 pm

Post by acidburn »

hello!

how about detecting text in the text box? is it possible?
Post Reply