Detect Close button click on other windows
Detect Close button click on other windows
Hi, does anyone know how to detect a Close button click on a third-party window, to cancel the click and then do something to that window first instead? I want to make a window animate in a specific way before closing, so I need to detect when Close is clicked to cancel the #WM_CLOSE message to it, animate it, then send my own #WM_CLOSE message to do the actual close.
Re: Detect Close button click on other windows
1- Create a Transparent window with the size of the Close button
2- Create a watchdog Thread
3- Keep detecting the position of the third-party window(if you can )
4- keep moving the transparent window on top of the third-party window Close Button
Now you can know when the third-party Close button just clicked
From here do what you want to do then Close that Window
Good luck
# 2:
- You can use Low Level Mouse Hook to intercept Left & Right Mouse Button down & Button up
- Once it is detected raise a flag and get the Cursor position
- If the Cursor position within the Close Button area do what you want to do
- Else let it go
2- Create a watchdog Thread
3- Keep detecting the position of the third-party window(if you can )
4- keep moving the transparent window on top of the third-party window Close Button
Now you can know when the third-party Close button just clicked
From here do what you want to do then Close that Window
Good luck
# 2:
- You can use Low Level Mouse Hook to intercept Left & Right Mouse Button down & Button up
- Once it is detected raise a flag and get the Cursor position
- If the Cursor position within the Close Button area do what you want to do
- Else let it go
Egypt my love
Re: Detect Close button click on other windows
Hi Rashad. Your first method is what I've currently got going, but it has the drawback that sometimes a user will click the Close button of an inactive background window, so my fake little window isn't going to be over it (it's only over the active window). I don't want to parse all open windows and stick a fake one over them all, hence this coding question.
The mouse hook idea sounds good, but I'm worried that it won't (or can't) intercept a Close click to an inactive window as well. I'll experiment and see.
The mouse hook idea sounds good, but I'm worried that it won't (or can't) intercept a Close click to an inactive window as well. I'll experiment and see.
Re: Detect Close button click on other windows
Hi BarryG
The Global Hook will do the job(I hope)
Go with it
The Global Hook will do the job(I hope)
Go with it
Code: Select all
Global hhkLLMouse
Procedure MouseHook(nCode, wParam, lParam)
*p.MOUSEHOOKSTRUCT = lParam
Select wParam
Case #WM_LBUTTONDOWN , #WM_RBUTTONDOWN
x = *p\pt\x
y = *p\pt\y
If x > 1700 And x < 1850
ProcedureReturn 1
Else
Debug x
Debug y
EndIf
EndSelect
ProcedureReturn CallNextHookEx_(0, nCode, wParam, lParam)
EndProcedure
OpenWindow(0, 0, 0, 300, 100, "Global Hook", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
hhkLLMouse = SetWindowsHookEx_(#WH_MOUSE_LL, @MouseHook(), GetModuleHandle_(0), 0)
Repeat
Select WaitWindowEvent (10)
Case #PB_Event_CloseWindow
UnhookWindowsHookEx_(hhkLLMouse)
Quit = 1
EndSelect
Until Quit = 1
UnhookWindowsHookEx_(hhkLLMouse)
End
Egypt my love
- netmaestro
- PureBasic Bullfrog
- Posts: 8433
- Joined: Wed Jul 06, 2005 5:42 am
- Location: Fort Nelson, BC, Canada
Re: Detect Close button click on other windows
RASHAD: It's an unowned 3rd party window. Different ballgame.
Here's how I would do it:
A global hook is necessary if you want to tap into the event queue of an unowned window. This requires a hook procedure located in a compiled DLL. I know it's a pain but there really is no way around this.
Place the following 3 programs in the same folder.
Main Program:
Compiled DLL:
Unowned window to test with:
1. Compile the second code as a shared dll
2. Run the third code
3. Run the first code
4. Close the window titled "Testing123".
The main code watches for the close of the test window using the hook proc in the dll. When the hook proc detects the close attempt, it signals the main program which then:
1. Disables the hook
2. Animates the test window (can't use Animate window here if you don't own the window)
3. Closes the test window
4. Reinstalls the hook for next time
Any questions, just ask. If I'm not around RASHAD or srod or someone will know what's up.
Here's how I would do it:
A global hook is necessary if you want to tap into the event queue of an unowned window. This requires a hook procedure located in a compiled DLL. I know it's a pain but there really is no way around this.
Place the following 3 programs in the same folder.
Main Program:
Code: Select all
Global hook.l, hooklib, address.l, hwndTarget.l
Procedure WinProc(hWnd, msg, wParam, lParam)
result = #PB_ProcessPureBasicEvents
Select msg
Case #WM_USER+100
hwndTarget = lParam
UnhookWindowsHookEx_(Hook)
; Stupid animation
For i=1 To 10
Delay(40)
GetWindowRect_(hwndTarget, @wr.RECT)
MoveWindow_(hwndTarget, wr\left-10, wr\top, wr\right-wr\left, wr\bottom-wr\top, #True)
Delay(40)
GetWindowRect_(hwndTarget, @wr.RECT)
MoveWindow_(hwndTarget, wr\left+10, wr\top, wr\right-wr\left, wr\bottom-wr\top, #True)
Next
SendMessage_(hwndTarget, #WM_SYSCOMMAND, #SC_CLOSE, 0)
While IsWindow_(hwndTarget)
Delay(1)
Wend
Hook = SetWindowsHookEx_(#WH_CBT, address, LibraryID(hooklib), 0)
EndSelect
ProcedureReturn result
EndProcedure
OpenWindow(0,0,0,320,240,"Calling Window",#PB_Window_SystemMenu)
SetWindowCallback(@WinProc())
hooklib = OpenLibrary(#PB_Any, "wh_winproc.dll")
If hooklib
address = GetFunction(hooklib, "CBTProc")
Hook = SetWindowsHookEx_(#WH_CBT, address, LibraryID(hooklib), 0)
Else
MessageRequester("oops!", "Could not open hook dll... quitting.")
EndIf
Repeat
EventID = WaitWindowEvent()
Until EventID = #PB_Event_CloseWindow
UnhookWindowsHookEx_(Hook)
End
Code: Select all
ProcedureDLL AttachProcess(instance)
Global Caller = FindWindow_(0, "Calling Window")
EndProcedure
ProcedureDLL CBTProc(nCode, wParam, lParam)
hwndTarget = FindWindow_(0, "Testing123")
If nCode = #HCBT_SYSCOMMAND
If wParam = #SC_CLOSE
If hwndTarget = GetForegroundWindow_()
PostMessage_(Caller, #WM_USER+100, 0, hwndTarget)
ProcedureReturn 1
EndIf
EndIf
Else
ProcedureReturn CallNextHookEx_(0, nCode, wParam, lParam)
EndIf
EndProcedure
Code: Select all
OpenWindow(0,0,0,320,240,"Testing123",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
StickyWindow(0,1)
Repeat
EventID = WaitWindowEvent()
Until EventID = #PB_Event_CloseWindow
2. Run the third code
3. Run the first code
4. Close the window titled "Testing123".
The main code watches for the close of the test window using the hook proc in the dll. When the hook proc detects the close attempt, it signals the main program which then:
1. Disables the hook
2. Animates the test window (can't use Animate window here if you don't own the window)
3. Closes the test window
4. Reinstalls the hook for next time
Any questions, just ask. If I'm not around RASHAD or srod or someone will know what's up.
BERESHEIT
Re: Detect Close button click on other windows
Thanks for pointing me in the right direction, Netmaestro. However, if I try to use another third-party window, like "Untitled - Notepad", it doesn't work. Yes, I've changed the window name in the DLL code.
Also, if I remove StickyWindow() from the "Testing123" window code, it doesn't close that window after animating, until I move the mouse on it. Not all windows will be sticky, but I should be able to work out a way to fix that.
Also, if I remove StickyWindow() from the "Testing123" window code, it doesn't close that window after animating, until I move the mouse on it. Not all windows will be sticky, but I should be able to work out a way to fix that.
- netmaestro
- PureBasic Bullfrog
- Posts: 8433
- Joined: Wed Jul 06, 2005 5:42 am
- Location: Fort Nelson, BC, Canada
Re: Detect Close button click on other windows
To make it close in all cases, change the SendMessage in the mainprogram to PostMessage:
Should fix that part anyway. For the calculator make sure you have a hwnd for it before proceeding further.
Code: Select all
PostMessage_(hwndTarget, #WM_SYSCOMMAND, #SC_CLOSE, 0)
BERESHEIT
Re: Detect Close button click on other windows
I changed your DLL code to the following so that no window title is needed to be checked, and it works great for the "Testing123" window, but not for any other windows. I don't know why, because it's definitely getting a valid hwnd for the "Testing123" window. Why would the hwnd of any other non-PureBasic window (Notepad) fail?
The hwnd for Notepad (not Calculator) is just hwndTarget, isn't it? That's what the "Testing123" window returns.
The hwnd for Notepad (not Calculator) is just hwndTarget, isn't it? That's what the "Testing123" window returns.
Code: Select all
ProcedureDLL AttachProcess(instance)
Global Caller = FindWindow_(0, "Calling Window")
EndProcedure
ProcedureDLL CBTProc(nCode, wParam, lParam)
hwndTarget = GetForegroundWindow_()
If hwndTarget <> Caller And nCode = #HCBT_SYSCOMMAND And wParam = #SC_CLOSE
PostMessage_(Caller, #WM_USER+100, 0, hwndTarget)
ProcedureReturn 1
Else
ProcedureReturn CallNextHookEx_(0, nCode, wParam, lParam)
EndIf
EndProcedure
- netmaestro
- PureBasic Bullfrog
- Posts: 8433
- Joined: Wed Jul 06, 2005 5:42 am
- Location: Fort Nelson, BC, Canada
Re: Detect Close button click on other windows
If you're on a 64bit OS and running x86 PB the dll won't inject into the calculator. Beyond that, I don't know.
BERESHEIT
Re: Detect Close button click on other windows
That's probably it, then, because that's the case. Your code works with all my PureBasic apps, but not any third-party apps. I'll keep trying. Thanks for your help!
Re: Detect Close button click on other windows
Hi NM
Very glad to see you around
I hope you are doing good
Best wishes to you
I know that it is Third party application
@BarryG
I hope it will satisfy your needs
Very glad to see you around
I hope you are doing good
Best wishes to you
I know that it is Third party application
@BarryG
I hope it will satisfy your needs
Code: Select all
Global hhkLLMouse,hwnd,tx,ty,flag
RunProgram("notepad.exe")
Repeat
hwnd = FindWindow_(0,"Untitled - Notepad")
Until hwnd
Procedure MouseHook(nCode, wParam, lParam)
*p.MOUSEHOOKSTRUCT = lParam
Select wParam
Case #WM_LBUTTONDOWN , #WM_RBUTTONDOWN
x = *p\pt\x
y = *p\pt\y
If x > tx And x < tx+50 And y > ty And y < ty+30
flag = 1
ProcedureReturn 1
Else
;Debug x
;Debug y
EndIf
EndSelect
ProcedureReturn CallNextHookEx_(0, nCode, wParam, lParam)
EndProcedure
Procedure watchdog(par)
Repeat
Delay(100)
GetWindowRect_(hwnd,r.RECT)
tx = r\right - 50
ty = r\top
If flag = 1
flag = 0
result = MessageRequester("GO","You are on Target",#PB_MessageRequester_YesNo)
If result = #PB_MessageRequester_Yes
SendMessage_(hwnd, #WM_SYSCOMMAND, #SC_CLOSE, 0)
Quitt = 1
EndIf
EndIf
Until Quitt = 1
EndProcedure
OpenWindow(0, 0, 0, 300, 100, "Global Hook", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
thread = CreateThread(@watchdog(),30)
hhkLLMouse = SetWindowsHookEx_(#WH_MOUSE_LL, @MouseHook(), GetModuleHandle_(0), 0)
Repeat
Select WaitWindowEvent (10)
Case #PB_Event_CloseWindow
UnhookWindowsHookEx_(hhkLLMouse)
Quit = 1
EndSelect
Until Quit = 1
UnhookWindowsHookEx_(hhkLLMouse)
End
Egypt my love
Re: Detect Close button click on other windows
Doesn't work Rashad; it only appears to because our process launched Notepad. It won't work with existing Notepads.
Netmaestro's solution works but apparently not with my 32-bit app on my 64-bit PC. I don't really want to use the 64-bit version of PureBasic if I can help it, because it reduces my customer base (a lot still use 32-bit Windows, and even I do on an old laptop or two), as well as breaking a few procedures that I can't update to 64-bit code right now.
Netmaestro's solution works but apparently not with my 32-bit app on my 64-bit PC. I don't really want to use the 64-bit version of PureBasic if I can help it, because it reduces my customer base (a lot still use 32-bit Windows, and even I do on an old laptop or two), as well as breaking a few procedures that I can't update to 64-bit code right now.
Re: Detect Close button click on other windows
Just comment
And it will work with existing running Notepad
Be sure you got the right handle
Because the Notepad Title Text depends on the opened file
Tested with PB 5.71 x86-x64 - Windows 10 x64
Code: Select all
;RunProgram("notepad.exe")
Be sure you got the right handle
Because the Notepad Title Text depends on the opened file
Tested with PB 5.71 x86-x64 - Windows 10 x64
Last edited by RASHAD on Sun Jan 26, 2020 8:10 am, edited 1 time in total.
Egypt my love
Re: Detect Close button click on other windows
Oops, you're right! I didn't have hWnd set correctly. Thank you.RASHAD wrote:it will work with existing running Notepad
Be sure you got the right handle