Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

[How to] Hook on to Shell to receive its messages?


  • Please log in to reply
73 replies to this topic
jk7800
  • Members
  • 39 posts
  • Last active: Jul 28 2009 08:41 PM
  • Joined: 06 Jan 2008
Hi.
I've done a small script using Your RegisterHookShellWindow function, SKAN. It creates a vista-like fading when a new window is created. Maybe it can be an example? :)

Gui +LastFound
DllCall("RegisterShellHookWindow",UInt,WinExist())
ShellHook:=DllCall("RegisterWindowMessage",Str,"SHELLHOOK")
OnMessage(ShellHook,"Message")
Return

Message(wParam,lParam)
{
    exclude=#32770   ;If you don’t want to fade certain windows (don’t forget to use a separator)
    if(wParam=1)  ;HSHELL_WINDOWCREATED is 1
    {
        IfWinExist, ahk_id %lParam%
        {
            WinGetClass, class, ahk_id %lParam%
            If(InStr(exclude, class)>0)
                Return
            WinSet, Transparent, 0, ahk_id %lParam%
            Loop 8
            {
                Sleep, 1
                Trans:=A_Index*32-1
                WinSet, Transparent, %Trans%, ahk_id %lParam%
            }
            WinSet, Transparent, OFF, ahk_id %lParam%
        }
    }
}

Hope you like it.

jk7800
  • Members
  • 39 posts
  • Last active: Jul 28 2009 08:41 PM
  • Joined: 06 Jan 2008
thewer, you can also try to change the work area:

SysGet, WorkArea, MonitorWorkArea

left := 0
right := A_ScreenWidth-0
top := 0
bottom := A_ScreenHeight-30-WorkAreaBottom ;WorkAreaBottom is needed to don't remove the place occupied by taskbar

VarSetCapacity( area, 16, 0 )
EncodeInteger( left, 4, &area, 0 )  ;Stores the region coordinates to memory
EncodeInteger( top, 4, &area, 4 )
EncodeInteger( right, 4, &area, 8 )
EncodeInteger( bottom, 4, &area, 12 )
DllCall( "SystemParametersInfo", "uint", 0x2F, "uint", 0, "uint", &area, "uint", 0 )

EncodeInteger( p_value, p_size, p_address, p_offset )
{
   loop, %p_size%
      DllCall( "RtlFillMemory"
         , "uint", p_address+p_offset+A_Index-1
         , "uint", 1
         , "uchar", ( p_value >> ( 8*( A_Index-1 ) ) ) & 0xFF )
}

Hope I helped.

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005

Hope you like it.


Nice jk7800 :)

I get a flicker when the windows is made transparent on Creation.
FYI, though it cannot be fully eliminated, adding the following lines reduces it:

Process, Priority,, High
SetBatchlines -1

:)

thewer
  • Members
  • 13 posts
  • Last active: Mar 12 2010 08:16 AM
  • Joined: 12 Feb 2008
Hi -
sorry for the late reply (I'm moving at the moment and needed some time to set up my system again).

@lexiKos:
Thanks - this would be a solution, just not sure I understand all of Skan's appbar at the moment. But I think an invisible child window of the taskbar would do the trick...

@jk7800:
Thanks a lot, too - this sounds easy enough even for me! :D

Well, more questions to come for sure... ;)

netboom
  • Members
  • 118 posts
  • Last active: May 21 2015 04:59 PM
  • Joined: 06 Jul 2008
Hi thanks for the code it was just what i'm looking for.. although i'm having trouble adapting it.

I want to switch between two windows every time i press "a" how would i change the script to release the focus and then reapply it? heres what i have so far but i'm not sure how to let the focus go.

WinGet, myarray, List, ahk_class ATL:00420130,,gamers

a::

SetBatchLines -1
Process, Priority,, High
DetectHiddenWindows, On                         ; Since Notepad is launched hidden

IfWinActive, ahk_id %myarray1%
{
	
	
	;WinSet, AlwaysOnTop, Off, ahk_id %myarray1%
	;WinSet, AlwaysOnTop, On, ahk_id %myarray2%
	;WinActivate, ahk_id %myarray2%
	
	;current = ahk_id %myarray2%
	current = %myarray2%
	goto, nextwin
}
IfWinActive, ahk_id %myarray2%
{
	
	;WinSet, AlwaysOnTop, Off, ahk_id %myarray2%
	;WinSet, AlwaysOnTop, On, ahk_id %myarray1%
	;WinActivate, ahk_id %myarray0%
	;current = ahk_id %myarray1%
	current = %myarray1%
	goto, nextwin
}

MsgBox, %current%
nextwin:



hnp := WinExist(ahk_id %current%)                ; Obtain hwnd
WinSetUnMovable( hnp )                          ; Make the window unmovable
;WinSet, AlwaysOnTop, On, ahk_id %hnp%           ; Flag it Always-On-Top
 
; SHELLHOOK method to detect active window -----------------------------------------------
; Refer Tips N Tricks : http://www.autohotkey.com/forum/viewtopic.php?p=123323#123323

Gui +LastFound
hWnd := WinExist()
DllCall( "RegisterShellHookWindow", UInt,hWnd )
MsgNum := DllCall( "RegisterWindowMessage", Str,"SHELLHOOK" )
OnMessage( MsgNum, "ShellMessage" )

; ----------------------------------------------------------------------------------------

OnExit, QuitScript
WinActivate, ahk_id %hnp%
Return ;                                                 // End of Auto-Execute Section //

ShellMessage( wParam,lParam ) {
  global hnp
  If ( wParam=4 && lParam<>hnp ) ; any window other than notepad is activated
       WinActivate, ahk_id %hnp%
  If ( wParam=2 && lParam=hnp ) ; if Notepad window is closed/destroyed
       ExitApp
}

WinSetUnMovable( hwnd ) {
  hSysMenu:=DllCall("GetSystemMenu","Int",hWnd,"Int",FALSE)
  nCnt:=DllCall("GetMenuItemCount","Int",hSysMenu)
  DllCall("RemoveMenu","Int",hSysMenu,"UInt",nCnt-6,"Uint","0x400")
  DllCall("DrawMenuBar","Int",hWnd)
}   

QuitScript:
 ;PostMessage, 0x112, 0xF060,,, ahk_id %hnp%
 ExitApp
Return


helper
  • Guests
  • Last active:
  • Joined: --

Hi thanks for the code it was just what i'm looking for.. although i'm having trouble adapting it.

I want to switch between two windows every time i press "a" how would i change the script to release the focus and then reapply it?


Here is the (untested) code with most commented lines removed, and with
important re-arrangement of the code blocks/functions.

It may still not work, but the re-arrangement should increase your chance of success.
SetBatchLines -1 
Process, Priority,, High 
WinGet, myarray, List, ahk_class ATL:00420130,,gamers ; <---- gets list of window handles

OnExit, QuitScript 

Gui +LastFound 
hWnd := WinExist() 
DllCall( "RegisterShellHookWindow", UInt,hWnd ) 
MsgNum := DllCall( "RegisterWindowMessage", Str,"SHELLHOOK" ) 
OnMessage( MsgNum, "ShellMessage" ) 

Return ;                                                 // End of Auto-Execute Section // 
; ---------------------------------------------------------------------------------------- 
a:: 
IfWinActive, ahk_id %myarray1% 
{ 
   current = %myarray2% 
   goto, nextwin 
} 
IfWinActive, ahk_id %myarray2% 
{ 
   current = %myarray1% 
   goto, nextwin 
} 
return
; ---------------------------------------------------------------------------------------
nextwin: 
  if ( lastCurrent = current)					  ; if current window was last processed, return
    return
  lastCurrent := current					  	  ; update last processed window
; MsgBox, %current% 
;  hnp := WinExist(ahk_id %current%)               ; Obtain hwnd 
  hnp := current						; <----- current already has window handle
  WinActivate, ahk_id %hnp% 
  WinSetUnMovable( hnp )                          ; Make the window unmovable 
  WinSet, AlwaysOnTop, On, ahk_id %hnp%           ; Flag it Always-On-Top 
  return
; ----------------------------------------------------------------------------------------

; SHELLHOOK method to detect active window ----------------------------------------------- 
; Refer Tips N Tricks : http://www.autohotkey.com/forum/viewtopic.php?p=123323#123323 

ShellMessage( wParam,lParam ) { 
  global hnp 
  If ( wParam=4 && lParam<>hnp ) ; any window other than ahk_id %hnp%  is activated 
       WinActivate, ahk_id %hnp% 
  If ( wParam=2 && lParam=hnp ) ; if ahk_id %hnp%  window is closed/destroyed 
       ExitApp 
} 
; -----------------------------
WinSetUnMovable( hwnd ) { 
  hSysMenu:=DllCall("GetSystemMenu","Int",hWnd,"Int",FALSE) 
  nCnt:=DllCall("GetMenuItemCount","Int",hSysMenu) 
  DllCall("RemoveMenu","Int",hSysMenu,"UInt",nCnt-6,"Uint","0x400") 
  DllCall("DrawMenuBar","Int",hWnd) 
}    
; -----------------------------
QuitScript: 
 ;PostMessage, 0x112, 0xF060,,, ahk_id %hnp% 
 ExitApp 
Return


helper
  • Guests
  • Last active:
  • Joined: --

a:: 
IfWinActive, ahk_id %myarray1% 
{ 
   current = %myarray2% 
   goto, nextwin 
} 
IfWinActive, ahk_id %myarray2% 
{ 
   current = %myarray1% 
   goto, nextwin 
} 
return

On re-examining the code, if the main body of the previously posted code does what you want, this code will have to be re-written to suit your needs. Once one of the windows has been tagged as "always on top and in focus", your a:: hotkey will not work because the tagged window will always be active. ;)

Murp-e
  • Members
  • 531 posts
  • Last active: Sep 27 2011 11:44 AM
  • Joined: 12 Jan 2007
SKAN,

Thanks for the great scripts. Is it possible to use the method described in "How to Hook on to Shell to receive its messages?" to execute code when a standard "Save as" window is created? I've been using the following code for testing:
#Persistent 
#singleinstance force
SetBatchLines, -1 
Process, Priority,, High 

Gui +LastFound 
hWnd := WinExist() 

DllCall( "RegisterShellHookWindow", UInt,hWnd ) 
MsgNum := DllCall( "RegisterWindowMessage", Str,"SHELLHOOK" ) 
OnMessage( MsgNum, "ShellMessage" ) 
Return 

ShellMessage( wParam,lParam ) { 
  If ( wParam = 1 ) ;  HSHELL_WINDOWCREATED := 1 
     { 
      WinGetClass, class, ahk_id %lParam% 
      traytip, New Window, New "%class%"-class window created.
      if class = #32770
       msgbox, Fired on a "#32770"-class window!
     } 
}

The traytip pops up for all new windows, but not for any "Save as" type windows. The kind of window I'm talking about is the kind that pops up when you click "File -> Save as" in for example Notepad. The ahk class is #32770, but since the ShellMessage doesn't fire nothing happens. Do you have any advise on this?

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005
Unfortunately, SHELLHOOK method will detect only top level windows.
The file save dialog is a child window of notepad.
So, notepad will be detected but not its child window.

Murp-e
  • Members
  • 531 posts
  • Last active: Sep 27 2011 11:44 AM
  • Joined: 12 Jan 2007
Thanks, that explains it. If anyone knows of something similar I could apply to child windows I much appreciate hearing about it.

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005
You could try [tool] WinEventHook Messages posted by Serenity especially the popup blocker example

Visioneer
  • Members
  • 287 posts
  • Last active: Sep 17 2017 10:07 PM
  • Joined: 19 Nov 2007
Great works SKAN,

This thread is so long that I fear that the very important:
How to Hook on to Shell to receive its messages is
lost in the sauce.

But anyway, could you add an experiment or thread or PM me
on how to get instant onMessage notification of when a screensaver
activates. Hopefully it should work on W98-XP-Vista all windows
versions.

This thread says that your technique could do this but I can't see it anywhere. orbik said in:
<!-- m -->http://www.autohotke...topic31038.html<!-- m -->

This sounds like a job for the shell hook method explained here <!-- m -->http://www.autohotke... ... 323#123323<!-- m -->
You'll get notified immediately when the screensaver starts instead of waiting inside a loop.


Thanks

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005
Visioneer, Sorry for the late reply.

How to get instant onMessage notification of when a screensaver activates.


Process, Priority,, High
Gui +LastFound
hWnd := WinExist()
DllCall( "RegisterShellHookWindow", UInt,hWnd )
MsgNum := DllCall( "RegisterWindowMessage", Str,"SHELLHOOK" )
OnMessage( MsgNum, "ShellMessage" )
Return

ShellMessage( wParam,lParam ) {
  If ( wParam = 1 ) ;  HSHELL_WINDOWCREATED := 1
     {
       WinGet, PN, ProcessName, ahk_id %lParam%
       If ( SubStr(PN,-3) = ".scr" )
          SetTimer, ScreenSaverHandler, -1
     }
}

ScreenSaverHandler:
 Send {Esc}                    ; Cancel ScreenSaver
 MsgBox, ScreenSaver was detected and cancelled immediately
Return

Hopefully it should work on W98-XP-Vista all windows versions.



I hope.

Drugwash
  • Members
  • 1078 posts
  • Last active: May 24 2016 04:20 PM
  • Joined: 07 Sep 2008
RegisterShellHookWindow does not exist in Win98SE's user32.dll so the above doesn't work. Not sure about WinME, but I guess the info at MSDN is accurate that it has only been implemented beginning with Win2000.

aandroyd
  • Members
  • 6 posts
  • Last active: Aug 10 2010 09:14 PM
  • Joined: 28 Jan 2009
SKAN you are the greatest! this has helped out so much :-D

a couple notes i have: on experiment 3 (the volume OSD), where you have
If ( wParam = 12 AND ( (lParam>>16) >= 8 OR (lParam>>16) <= 10) )you should have
If ( wParam = 12 AND ( (lParam>>16) >= 8 AND (lParam>>16) <= 10) )otherwise the OSD triggers for every wParam=12 event

also, for anybody out there using a standard DELL multimedia keyboard (such as SK-8135 ), it might be helpful to note that the volume wheel uses (lParam>>16)=4106 for volume up and (lParam>>16)=4105 for volume down
-AJ