Is there an "open folder" event Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
superpeter
Posts: 115
Joined: 18 Dec 2020, 05:17

Re: Is there an "open folder" event

Post by superpeter » 27 Feb 2021, 14:11

Oh, there's no folder path since I just wanted to check if a particular file was opened. I'd use your solution to check if a folder was opened.

teadrinker
Posts: 4602
Joined: 29 Mar 2015, 09:41
Contact:

Re: Is there an "open folder" event

Post by teadrinker » 27 Feb 2021, 14:29

If the folder has been opened this doesn't mean that the file has been launched from that folder. :)

superpeter
Posts: 115
Joined: 18 Dec 2020, 05:17

Re: Is there an "open folder" event

Post by superpeter » 27 Feb 2021, 18:23

You're right!

I think the answer is somewhere here: https://www.autohotkey.com/boards/viewtopic.php?p=120546#p120546

But it's way above my pay grade lol.

teadrinker
Posts: 4602
Joined: 29 Mar 2015, 09:41
Contact:

Re: Is there an "open folder" event

Post by teadrinker » 27 Feb 2021, 18:59

If you mean reading the command line of the process, this is an option, but the command line does not have to contain the path to the currently open file.

AutoGiraffe
Posts: 4
Joined: 27 Jul 2021, 14:30

Re: Is there an "open folder" event

Post by AutoGiraffe » 27 Jul 2021, 14:40

teadrinker wrote:
27 Sep 2020, 08:22

Code: Select all

#Persistent
global EVENT_OBJECT_SHOW       := 0x8002
     , EVENT_OBJECT_NAMECHANGE := 0x800C

folderPath := "C:\Program Files"
WatchFolders := Func("IsMyFolderOpened").Bind(folderPath)

Hook := new WinEventHook(EVENT_OBJECT_SHOW, EVENT_OBJECT_NAMECHANGE, "HookProc", Object(WatchFolders))

IsMyFolderOpened(folderPath, hWnd) {
   openedFolderPath := GetFolderPath(hWnd)
   if InStr(openedFolderPath, folderPath . "\") || openedFolderPath = folderPath
      MsgBox, Folder %openedFolderPath% was opened
}

HookProc(hWinEventHook, event, hwnd, idObject, idChild, dwEventThread, dwmsEventTime) {
   static OBJID_WINDOW := 0, CallBack, prevTime := 0
   (!CallBack && CallBack := Object(A_EventInfo))
   if (idObject != OBJID_WINDOW)
      Return
   if !(event = EVENT_OBJECT_SHOW || event = EVENT_OBJECT_NAMECHANGE)
      Return
   WinGetClass, winClass, ahk_id %hwnd%
   if (winClass != "CabinetWClass")
      Return
   if (A_TickCount - prevTime < 300)
      Return
   prevTime := A_TickCount
   CallBack.(hwnd)
}

GetFolderPath(hWnd := "") {
   (!hWnd && hWnd := WinExist("A"))
   WinGetClass, winClass, ahk_id %hWnd%
   if !(winClass ~="Progman|WorkerW|(Cabinet|Explore)WClass")
      Return
   
   if (winClass ~= "Progman|WorkerW")
      Return A_Desktop
   
   for window in ComObjCreate("Shell.Application").Windows {
      if (hWnd = window.HWND && dirPath := window.Document.Folder.Self.Path)
         break
   }
   Return dirPath
}

class WinEventHook
{
   __New(eventMin, eventMax, hookProc, eventInfo := 0, idProcess := 0, idThread := 0, dwFlags := 0) {
      this.pCallback := RegisterCallback(hookProc, "F",, eventInfo)
      this.hHook := DllCall("SetWinEventHook", "UInt", eventMin, "UInt", eventMax, "Ptr", 0, "Ptr", this.pCallback
                                             , "UInt", idProcess, "UInt", idThread, "UInt", dwFlags, "Ptr")
   }
   __Delete() {
      DllCall("UnhookWinEvent", "Ptr", this.hHook)
      DllCall("GlobalFree", "Ptr", this.pCallback, "Ptr")
   }
}
If the Program Files folder or its subfolder is open, a message will appear.
Thank you so much for this. What if one wants to change the monitored folder (while the script is already running)? Or in another case, turning off the folder monitoring completely without exiting the script. Is there a way to do these?

teadrinker
Posts: 4602
Joined: 29 Mar 2015, 09:41
Contact:

Re: Is there an "open folder" event

Post by teadrinker » 27 Jul 2021, 19:31

AutoGiraffe wrote: Is there a way to do these?
Of course.

Code: Select all

#Persistent
global EVENT_OBJECT_SHOW       := 0x8002
     , EVENT_OBJECT_NAMECHANGE := 0x800C

WatchFolders := Func("IsMyFolderOpened").Bind(folderPathObj := [])
pObj := Object(WatchFolders)
Return

$F1:: folderPathObj[1] := SelectFolderEx(, "Select the folder to monitor")
$F2::
   if !InStr( FileExist(folderPathObj[1]), "D" )
      MsgBox, No folder chosen
   else
      Hook := new WinEventHook(EVENT_OBJECT_SHOW, EVENT_OBJECT_NAMECHANGE, "HookProc", pObj)
   Return

$F3:: Hook := ""

IsMyFolderOpened(obj, hWnd) {
   openedFolderPath := GetFolderPath(hWnd)
   if InStr(openedFolderPath, obj[1] . "\") || openedFolderPath = obj[1]
      MsgBox, Folder %openedFolderPath% was opened
}

HookProc(hWinEventHook, event, hwnd, idObject, idChild, dwEventThread, dwmsEventTime) {
   static OBJID_WINDOW := 0, CallBack, prevTime := 0
   (!CallBack && CallBack := Object(A_EventInfo))
   if (idObject != OBJID_WINDOW)
      Return
   if !(event = EVENT_OBJECT_SHOW || event = EVENT_OBJECT_NAMECHANGE)
      Return
   WinGetClass, winClass, ahk_id %hwnd%
   if (winClass != "CabinetWClass")
      Return
   if (A_TickCount - prevTime < 300)
      Return
   prevTime := A_TickCount
   CallBack.(hwnd)
}

GetFolderPath(hWnd := "") {
   (!hWnd && hWnd := WinExist("A"))
   WinGetClass, winClass, ahk_id %hWnd%
   if !(winClass ~="Progman|WorkerW|(Cabinet|Explore)WClass")
      Return
   
   if (winClass ~= "Progman|WorkerW")
      Return A_Desktop
   
   for window in ComObjCreate("Shell.Application").Windows {
      if (hWnd = window.HWND && dirPath := window.Document.Folder.Self.Path)
         break
   }
   Return dirPath
}

class WinEventHook
{
   __New(eventMin, eventMax, hookProc, eventInfo := 0, idProcess := 0, idThread := 0, dwFlags := 0) {
      this.pCallback := RegisterCallback(hookProc, "F",, eventInfo)
      this.hHook := DllCall("SetWinEventHook", "UInt", eventMin, "UInt", eventMax, "Ptr", 0, "Ptr", this.pCallback
                                             , "UInt", idProcess, "UInt", idThread, "UInt", dwFlags, "Ptr")
   }
   __Delete() {
      DllCall("UnhookWinEvent", "Ptr", this.hHook)
      DllCall("GlobalFree", "Ptr", this.pCallback, "Ptr")
   }
}

SelectFolderEx(StartingFolder := "", Prompt := "", OwnerHwnd := 0, OkBtnLabel := "") {
   static OsVersion := DllCall("GetVersion", "UChar")
        , IID_IShellItem := 0
        , InitIID := VarSetCapacity(IID_IShellItem, 16, 0)
                  & DllCall("Ole32.dll\IIDFromString", "WStr", "{43826d1e-e718-42ee-bc55-a1e261c37bfe}", "Ptr", &IID_IShellItem)
        , Show := A_PtrSize * 3
        , SetOptions := A_PtrSize * 9
        , SetFolder := A_PtrSize * 12
        , SetTitle := A_PtrSize * 17
        , SetOkButtonLabel := A_PtrSize * 18
        , GetResult := A_PtrSize * 20
   SelectedFolder := ""
   if (OsVersion < 6) { ; IFileDialog requires Win Vista+, so revert to FileSelectFolder
      FileSelectFolder, SelectedFolder, *%StartingFolder%, 3, %Prompt%
      Return SelectedFolder
   }
   OwnerHwnd := DllCall("IsWindow", "Ptr", OwnerHwnd, "UInt") ? OwnerHwnd : 0
   if !(FileDialog := ComObjCreate("{DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7}", "{42f85136-db7e-439c-85f1-e4075d135fc8}"))
      Return ""
   VTBL := NumGet(FileDialog + 0, "UPtr")
   ; FOS_CREATEPROMPT | FOS_NOCHANGEDIR | FOS_PICKFOLDERS
   DllCall(NumGet(VTBL + SetOptions, "UPtr"), "Ptr", FileDialog, "UInt", 0x00002028, "UInt")
   if (StartingFolder <> "")
      if !DllCall("Shell32.dll\SHCreateItemFromParsingName", "WStr", StartingFolder, "Ptr", 0, "Ptr", &IID_IShellItem, "PtrP", FolderItem)
         DllCall(NumGet(VTBL + SetFolder, "UPtr"), "Ptr", FileDialog, "Ptr", FolderItem, "UInt")
   if (Prompt <> "")
      DllCall(NumGet(VTBL + SetTitle, "UPtr"), "Ptr", FileDialog, "WStr", Prompt, "UInt")
   if (OkBtnLabel <> "")
      DllCall(NumGet(VTBL + SetOkButtonLabel, "UPtr"), "Ptr", FileDialog, "WStr", OkBtnLabel, "UInt")
   if !DllCall(NumGet(VTBL + Show, "UPtr"), "Ptr", FileDialog, "Ptr", OwnerHwnd, "UInt") {
      if !DllCall(NumGet(VTBL + GetResult, "UPtr"), "Ptr", FileDialog, "PtrP", ShellItem, "UInt") {
         GetDisplayName := NumGet(NumGet(ShellItem + 0, "UPtr"), A_PtrSize * 5, "UPtr")
         if !DllCall(GetDisplayName, "Ptr", ShellItem, "UInt", 0x80028000, "PtrP", StrPtr) ; SIGDN_DESKTOPABSOLUTEPARSING
            SelectedFolder := StrGet(StrPtr, "UTF-16"), DllCall("Ole32.dll\CoTaskMemFree", "Ptr", StrPtr)
         ObjRelease(ShellItem)
   }  }
   if (FolderItem)
      ObjRelease(FolderItem)
   ObjRelease(FileDialog)
   Return SelectedFolder
}
By F1 you can choose a folder, by F2 start monitoring, by F3 stop monitoring.

AvtoGiraffe
Posts: 1
Joined: 28 Jul 2021, 00:55

Re: Is there an "open folder" event

Post by AvtoGiraffe » 28 Jul 2021, 00:59

Very much obliged! :thumbup:

Baconfry
Posts: 19
Joined: 07 Jan 2022, 04:07

Re: Is there an "open folder" event

Post by Baconfry » 12 Dec 2024, 15:05

teadrinker wrote:
27 Jul 2021, 19:31

Code: Select all

#Persistent
global EVENT_OBJECT_SHOW       := 0x8002
     , EVENT_OBJECT_NAMECHANGE := 0x800C

WatchFolders := Func("IsMyFolderOpened").Bind(folderPathObj := [])
pObj := Object(WatchFolders)
Return

$F1:: folderPathObj[1] := SelectFolderEx(, "Select the folder to monitor")
$F2::
   if !InStr( FileExist(folderPathObj[1]), "D" )
      MsgBox, No folder chosen
   else
      Hook := new WinEventHook(EVENT_OBJECT_SHOW, EVENT_OBJECT_NAMECHANGE, "HookProc", pObj)
   Return

$F3:: Hook := ""

IsMyFolderOpened(obj, hWnd) {
   openedFolderPath := GetFolderPath(hWnd)
   if InStr(openedFolderPath, obj[1] . "\") || openedFolderPath = obj[1]
      MsgBox, Folder %openedFolderPath% was opened
}

HookProc(hWinEventHook, event, hwnd, idObject, idChild, dwEventThread, dwmsEventTime) {
   static OBJID_WINDOW := 0, CallBack, prevTime := 0
   (!CallBack && CallBack := Object(A_EventInfo))
   if (idObject != OBJID_WINDOW)
      Return
   if !(event = EVENT_OBJECT_SHOW || event = EVENT_OBJECT_NAMECHANGE)
      Return
   WinGetClass, winClass, ahk_id %hwnd%
   if (winClass != "CabinetWClass")
      Return
   if (A_TickCount - prevTime < 300)
      Return
   prevTime := A_TickCount
   CallBack.(hwnd)
}

GetFolderPath(hWnd := "") {
   (!hWnd && hWnd := WinExist("A"))
   WinGetClass, winClass, ahk_id %hWnd%
   if !(winClass ~="Progman|WorkerW|(Cabinet|Explore)WClass")
      Return
   
   if (winClass ~= "Progman|WorkerW")
      Return A_Desktop
   
   for window in ComObjCreate("Shell.Application").Windows {
      if (hWnd = window.HWND && dirPath := window.Document.Folder.Self.Path)
         break
   }
   Return dirPath
}

class WinEventHook
{
   __New(eventMin, eventMax, hookProc, eventInfo := 0, idProcess := 0, idThread := 0, dwFlags := 0) {
      this.pCallback := RegisterCallback(hookProc, "F",, eventInfo)
      this.hHook := DllCall("SetWinEventHook", "UInt", eventMin, "UInt", eventMax, "Ptr", 0, "Ptr", this.pCallback
                                             , "UInt", idProcess, "UInt", idThread, "UInt", dwFlags, "Ptr")
   }
   __Delete() {
      DllCall("UnhookWinEvent", "Ptr", this.hHook)
      DllCall("GlobalFree", "Ptr", this.pCallback, "Ptr")
   }
}

SelectFolderEx(StartingFolder := "", Prompt := "", OwnerHwnd := 0, OkBtnLabel := "") {
   static OsVersion := DllCall("GetVersion", "UChar")
        , IID_IShellItem := 0
        , InitIID := VarSetCapacity(IID_IShellItem, 16, 0)
                  & DllCall("Ole32.dll\IIDFromString", "WStr", "{43826d1e-e718-42ee-bc55-a1e261c37bfe}", "Ptr", &IID_IShellItem)
        , Show := A_PtrSize * 3
        , SetOptions := A_PtrSize * 9
        , SetFolder := A_PtrSize * 12
        , SetTitle := A_PtrSize * 17
        , SetOkButtonLabel := A_PtrSize * 18
        , GetResult := A_PtrSize * 20
   SelectedFolder := ""
   if (OsVersion < 6) { ; IFileDialog requires Win Vista+, so revert to FileSelectFolder
      FileSelectFolder, SelectedFolder, *%StartingFolder%, 3, %Prompt%
      Return SelectedFolder
   }
   OwnerHwnd := DllCall("IsWindow", "Ptr", OwnerHwnd, "UInt") ? OwnerHwnd : 0
   if !(FileDialog := ComObjCreate("{DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7}", "{42f85136-db7e-439c-85f1-e4075d135fc8}"))
      Return ""
   VTBL := NumGet(FileDialog + 0, "UPtr")
   ; FOS_CREATEPROMPT | FOS_NOCHANGEDIR | FOS_PICKFOLDERS
   DllCall(NumGet(VTBL + SetOptions, "UPtr"), "Ptr", FileDialog, "UInt", 0x00002028, "UInt")
   if (StartingFolder <> "")
      if !DllCall("Shell32.dll\SHCreateItemFromParsingName", "WStr", StartingFolder, "Ptr", 0, "Ptr", &IID_IShellItem, "PtrP", FolderItem)
         DllCall(NumGet(VTBL + SetFolder, "UPtr"), "Ptr", FileDialog, "Ptr", FolderItem, "UInt")
   if (Prompt <> "")
      DllCall(NumGet(VTBL + SetTitle, "UPtr"), "Ptr", FileDialog, "WStr", Prompt, "UInt")
   if (OkBtnLabel <> "")
      DllCall(NumGet(VTBL + SetOkButtonLabel, "UPtr"), "Ptr", FileDialog, "WStr", OkBtnLabel, "UInt")
   if !DllCall(NumGet(VTBL + Show, "UPtr"), "Ptr", FileDialog, "Ptr", OwnerHwnd, "UInt") {
      if !DllCall(NumGet(VTBL + GetResult, "UPtr"), "Ptr", FileDialog, "PtrP", ShellItem, "UInt") {
         GetDisplayName := NumGet(NumGet(ShellItem + 0, "UPtr"), A_PtrSize * 5, "UPtr")
         if !DllCall(GetDisplayName, "Ptr", ShellItem, "UInt", 0x80028000, "PtrP", StrPtr) ; SIGDN_DESKTOPABSOLUTEPARSING
            SelectedFolder := StrGet(StrPtr, "UTF-16"), DllCall("Ole32.dll\CoTaskMemFree", "Ptr", StrPtr)
         ObjRelease(ShellItem)
   }  }
   if (FolderItem)
      ObjRelease(FolderItem)
   ObjRelease(FileDialog)
   Return SelectedFolder
}
This is an impressive piece of code! I know this is the v1.1 forum, but is there any chance we can port this to v2? I tried doing it myself, but, alas, it proved to be difficult (as expected) for a mortal like myself.

For SelectFolderEx(), v2 offers FileSelect("D"), which is nice. However, I just can't wrap my head around the DllCalls and the objects. RegisterCallback is also deprecated, but I can't make the newer CallbackCreate work. It's also my first time seeing CallBack.(hwnd), and from the docs, it should be akin to CallBack[""].hwnd. I could keep on going... Anyway, I would appreciate any help :)

teadrinker
Posts: 4602
Joined: 29 Mar 2015, 09:41
Contact:

Re: Is there an "open folder" event

Post by teadrinker » 12 Dec 2024, 17:02

Baconfry wrote: is there any chance we can port this to v2?
Sure, please create the post in the v2 thread.

Baconfry
Posts: 19
Joined: 07 Jan 2022, 04:07

Re: Is there an "open folder" event

Post by Baconfry » 12 Dec 2024, 22:37

Thank you! Will do :)

Post Reply

Return to “Ask for Help (v1)”