Jump to content
Sign in to follow this  
jiggunjer

Event-based scripting with the windows shell COM object

Recommended Posts

I want to listen for certain windows events like window open/closed. After reading the help I think I need to use ObjCreate('shell.application') and ObjEvent with that object to create/register a listener. The problem is I don't know what interface or events (i.e. the specific event names) are available for the listener. I tried searching MSDN but it is a labyrinth and I'm not that familiar with the programming frameworks/models used by Windows, and all the examples seem to refer to compiled code using .NET or some other api.

Can any1 point me in the right direction? Also is using COM objects considered the 'modern' way to do this, or should I be using some other framework/resources?

Share this post


Link to post
Share on other sites

Share this post


Link to post
Share on other sites

@spudw2k I want to listen to events of an external app. So in the meantime I found winapi's shellhookex(), with shellproc but I can't seem to trigger it when I create new windows after running the script.

 

#include <MsgBoxConstants.au3>
#include <StructureConstants.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>

Global $g_hHook

Example()

Func Example()
    OnAutoItExitRegister("Cleanup")   

    $pcallback = DllCallbackGetPtr(DllCallbackRegister("MyCallback", "long", "int;wparam;lparam"));$WM_SHELL types
    $g_hHook = _WinAPI_SetWindowsHookEx($WH_SHELL, $pcallback, _WinAPI_GetModuleHandle(0))

    MsgBox($MB_SYSTEMMODAL, "", "Click OK, then in notepad type..." & _
            @CRLF & @CRLF & "Jon" & @CRLF & "AutoIt" & @CRLF & @CRLF & "Press Esc to exit script")

    Run("notepad.exe")
    WinWait("[CLASS:Notepad]")
    WinActivate("[CLASS:Notepad]")

    While 1
        Sleep(10)
    WEnd
EndFunc   ;==>Example

Func EvaluateKey()
    
EndFunc   ;==>

; ===========================================================
; callback function
; ===========================================================
Func MyCallback($nCode, $wParam, $lParam)    ; never called
    msgbox(0,"Test","Test")
    If $nCode < 0 Then
        Return _WinAPI_CallNextHookEx($g_hHook, $nCode, $wParam, $lParam)
    EndIf
    If $nCode <> 1 Then
        msgbox(0,"Test","Test")
    EndIf

    Return _WinAPI_CallNextHookEx($g_hHook, $nCode, $wParam, $lParam)
EndFunc   ;==>_KeyProc

Func Cleanup()
    _WinAPI_UnhookWindowsHookEx($g_hHook)
    ;DllCallbackFree($g_hStub_KeyProc)
EndFunc   ;==>Cleanup

 

Edited by jiggunjer
added example script

Share this post


Link to post
Share on other sites

Hello. try something like this.

#include <WinAPIProc.au3>
#include <WinAPI.au3>
#include <WinAPISys.au3>
#include <Array.au3>
#include <GUIConstants.au3>
#include <APISysConstants.au3>


Global $hGUI = GUICreate("GUI")

GUISetState(@SW_SHOW, $hGUI)

GUIRegisterMsg(_WinAPI_RegisterWindowMessage('SHELLHOOK'), 'WM_SHELLHOOK')
_WinAPI_RegisterShellHookWindow($hGUI)



Run("notepad.exe")

Local $nMsg=0
While 1
    $nMsg = GUIGetMsg()
    Select
        Case $nMsg = $GUI_EVENT_CLOSE
            ExitLoop
    EndSelect

WEnd

_WinAPI_DeregisterShellHookWindow($hGUI)
Exit

Func WM_SHELLHOOK($hWnd, $iMsg, $wParam, $lParam)
    #forceref $iMsg
    Switch $wParam
        Case $HSHELL_WINDOWDESTROYED
            ConsoleWrite('Destroyed: ' & @CRLF & _
                    @TAB & 'PID: ' & WinGetProcess($lParam) & @CRLF & _ ; This will be -1.
                    @TAB & 'ClassName: ' & _WinAPI_GetClassName($lParam) & @CRLF & _ ; This will be empty.
                    @TAB & 'hWnd: ' & $lParam & @CRLF) ; This will be the handle of the window closed.
        Case $HSHELL_WINDOWCREATED
            ConsoleWrite('Created: ' & @CRLF & _
                    @TAB & 'PID: ' & WinGetProcess($lParam) & @CRLF & _
                    @TAB & 'ClassName: ' & _WinAPI_GetClassName($lParam) & @CRLF & _
                    @TAB & 'hWnd: ' & $lParam & @CRLF) ; This will be the handle of the window closed.
    EndSwitch
EndFunc   ;==>WM_SHELLHOOK

 

Saludos

Share this post


Link to post
Share on other sites

@Danyfirex Thanks but that raises at least 3 questions for me:

- Do I always need to use an AutoIt GUI to get the shell hook stuff?

- How do you know the parameters WM_SHELLHOOK takes, I can't find it on MSDN :(

- Don't you need to call the next hook in the chain after your callback?

Share this post


Link to post
Share on other sites

Yes You need a handle to a window. But you can create a dummy GUI. Keep it hidden.

Parameters are here https://msdn.microsoft.com/en-us/library/windows/desktop/ms644989(v=vs.85).aspx

No need Next Hook Call.

 

Saludos

Edited by Danyfirex

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By Synaps3
      This script will make it so you can press Alt + "+" in Windows Explorer to select all files with the current file extension. This is something that I wanted for a long time and it should be a feature in Windows, but it's not. The only way to get close is to use the search thing (but then it shows the results excluding everything else) or to group by that type, but I don't want it grouped.
      You can press Alt + Enter right after to open properties on those files or you can press delete to delete only files of that type.
      You need the "Automating Windows Explorer" pack here: https://www.autoitscript.com/forum/topic/162905-automating-windows-explorer/
       
      #include "Includes\AutomatingWindowsExplorer.au3" #include <Array.au3> Opt( "MustDeclareVars", 1 ) HotKeySet("!=", "SelectTypes") Func SelectTypes() ; Windows Explorer on XP, Vista, 7, 8 Local $hExplorer = WinGetHandle("[REGEXPCLASS:^(Cabinet|Explore)WClass$]") If Not $hExplorer Then MsgBox(0, "Explorer", "Could not find Windows Explorer.") Return EndIf $hExplorer = WinActive("[REGEXPCLASS:^(Cabinet|Explore)WClass$]") If Not $hExplorer Then MsgBox(0, "Explorer", "Windows Explorer is not in focus.") Return EndIf ; Get an IShellBrowser interface GetIShellBrowser($hExplorer) If Not IsObj($oIShellBrowser) Then MsgBox(0, "Explorer", "Could not get an IShellBrowser interface.") Return EndIf ; Get other interfaces GetShellInterfaces() ; Get selected files with full path ;GetFiles( $fSelected = False, $fFullPath = False, $fPidl = False, $iMax = 0 ) Local $aAllFiles = GetItems(False, False) Local $aFiles = GetItems(True, False) Local $sExt Local $i If UBound($aFiles) = 1 Then ;MsgBox(0, "Selected", $aFiles[0]) $sExt = StringRight($aFiles[0], StringLen($aFiles[0]) - StringInStr($aFiles[0], ".", 0, -1)) ;MsgBox(0, "Selected", $sExt) For $i = 0 To UBound($aAllFiles) - 1 If StringInStr($aAllFiles[$i], ".") > 0 Then If StringRight($aAllFiles[$i], StringLen($aAllFiles[$i]) - StringInStr($aAllFiles[$i], ".", 0, -1)) = $sExt Then SetSelectedItem($i) EndIf EndIf Next Else MsgBox($MB_ICONWARNING, "Error", "None or multiple items selected!") EndIf EndFunc While 1 GUIGetMsg() Wend  
    • By tarretarretarre
      About AutoIt-Events
      AutoIt-Events is an event Observer and is a core dependency for Autoit-Socket-IO but can be used for any Autoit project.
      Example
      #include "Event.au3" ; Subscribe listeners _Event_Listen(UserCreatedEvent, SendWelcomeMail) _Event_Listen(UserCreatedEvent, RegisterNewsLetter) ; Fire event _Event(UserCreatedEvent, @UserName, "tarre.islam@gmail.com") Func UserCreatedEvent(Const ByRef $oEvent, $name, $email) ; via $oEvent you can pass data to its listeners $oEvent.add("name", $name) $oEvent.add("email", $email) $oEvent.add("id", 1) EndFunc Func SendWelcomeMail(Const $oEvent) MsgBox(64, "Welcome mail sent", "Welcome mail sent to " & $oEvent.item("name") & " with email " & $oEvent.item("email")) EndFunc Func RegisterNewsLetter(Const $oEvent) MsgBox(64, "News letter registred", "News letter bound to user id " & $oEvent.item("id")) EndFunc  
      The code is also available at Github
       
      Autoit-Events-1.0.0.zip
    • By tarretarretarre
      Version 2.x.x and 3.x.x has been moved to branch 3.x
      About Autoit-Socket-IO
      Autoit-Socket-IO is a event driven TCP/IP wrapper heavily inspired from Socket.IO with focus on user friendliness and long term sustainability.
      I constantly want to make this UDF faster and better, so if you have any suggestions or questions (beginner and advanced) Do not hesitate to ask them, I will gladly help!
      Key features
      Simple API 99% data-type serialization thanks to Autoit-Serialize Can easily be extended with your own functionality thanks to Autoit-Events "Educational" examples Data encryption thanks to _<Crypt.au3> Limitations
      Speed. This UDF will sacrifice some speed for convenience Getting started
      Download the script from AutoIt or pull it from the official github repo git@github.com:tarreislam/Autoit-Socket-IO.git and checkout the tag 4.0.0-beta Check out the documentaion Take a look in the examples/ folder Changelog
      To see changes from 3.x.x and 2.x.x please checkout the 3.x branch
      Version 4.0.0-beta (This update break scripts.)
      Code base fully rewritten with Autoit-Events and decoupled to improve code quality and reduce bloat. The new UDF is very different from 3.x.x so please checkout the UPGRADE guide to fully understand all changes Added new documentation documentaion Success stories
      Since December 2017-now I have used version 1.5.0 in an production environment for 150+ clients with great success, the only downtime is planned windows updates and power outages.
       
      Newest version (2020-09-15!)

       
      Older versions (Not supported anymore)
      Autoit-Socket-IO-1.0.0.zip Autoit-Socket-IO-1.1.0.zip Autoit-Socket-IO-1.3.0.zip Autoit-Socket-IO-1.4.0.zip Autoit-Socket-IO-1.5.0.zip
      Autoit-Socket-IO-2.0.0.zip
    • By WoodGrain
      Hi All,
      Trying to open windows explorer to a WebDav location and it's not working quite how I want, on the computers it is setup as a "network location" (as opposed to a "mapped drive", and this unfortunately can't be changed), the "Data" WebDav folder sits directly under "This PC" if that's an easier way to get to it. any suggestions as to what I can correct to get the 2nd example to work?
      ; This works, but I'm trying to avoid this as users normally see the URL style in the 2nd example below $folderToOpen = "\\mycompany.sharepoint.com@SSL\DavWWWRoot\Data" Run("Explorer.exe " & $folderToOpen) ; This does not work, it tries to open the WebDav url in the default web browser $folderToOpen = "https://mycompany.sharepoint.com/Data" Run("Explorer.exe " & $folderToOpen) ShellExecute also opens it in the default browser.
      Saw _WinAPI_ShellOpenFolderAndSelectItems but couldn't get the 2nd example to work.
      If I manually open Windows Explorer and paste in https://mycompany.sharepoint.com/Data it loads the WebDav directory without issue.
      If I have to use the pathing from the first example it is fine, just trying to give users a familiar experience.
      Thanks!
    • By Colduction
      Hello again, i have a code that changes username to favorite, my problem is how to use ObjEvent() function to catch errors, i've red Help File and Forum's Topics but i can't understand too much😐

      Here is a code (I've copied this codes from a user of AutoIt Forum):
       
      $sOldUser = "Administrator" $sNewUser = "Admin" $oUser = ObjGet("WinNT://" & @ComputerName & "/" & $sOldUser & ",user") $oComputer = ObjGet("WinNT://" & @ComputerName) $oNewUser = $oComputer.MoveHere($oUser.ADsPath, $sNewUser) Thanks for your care, I'm new to AutoIt and days should be passed with my coding and practicing to don't bother you :)❤
×
×
  • Create New...