Page 1 of 2

Is there an "open folder" event

Posted: 25 Sep 2020, 23:22
by songdg
I want to trigger an event when open a new folder or enter the sub_folder of an existing folder, in my case to read a txt file inside that folder automatically, is that possible or other ways to achieve the same purpose? Currently, I use a hotkey to do that.

Re: Is there an "open folder" event

Posted: 26 Sep 2020, 06:12
by mikeyww
What was your success method?

Re: Is there an "open folder" event

Posted: 26 Sep 2020, 21:41
by songdg
mikeyww wrote:
26 Sep 2020, 06:12
What was your success method?
I used the Explorer_GetActiveFolderPath() method.

Re: Is there an "open folder" event

Posted: 27 Sep 2020, 06:55
by mikeyww
It sounds like you have the folder path. Loop, Files can get you the files in that path.

Re: Is there an "open folder" event  Topic is solved

Posted: 27 Sep 2020, 08:22
by teadrinker
songdg wrote: I want to trigger an event when open a new folder or enter the sub_folder of an existing folder
Something like this:

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.

Re: Is there an "open folder" event

Posted: 27 Sep 2020, 08:35
by mikeyww
Very nice!

Re: Is there an "open folder" event

Posted: 27 Sep 2020, 08:47
by teadrinker
Thanks!

Re: Is there an "open folder" event

Posted: 27 Sep 2020, 09:02
by songdg
teadrinker wrote:
27 Sep 2020, 08:22
songdg wrote: I want to trigger an event when open a new folder or enter the sub_folder of an existing folder
Something like this:

If the Program Files folder or its subfolder is open, a message will appear.
I want to give you :thumbup: ,thank you very much :bravo: !!!

Re: Is there an "open folder" event

Posted: 27 Sep 2020, 09:49
by teadrinker
You are welcome! :)

Re: Is there an "open folder" event

Posted: 26 Feb 2021, 11:38
by Falleau
I tried teadrinker's snippet and it worked very nicely, but only when the folder is opened in file explorer. However, when I opened the folder from the desktop, the hook doesn't seem to trigger. Upon closer inspection, dirPath from GetFolderPath returned empty when any folder from the desktop is opened, causing openedFolderPath to be empty. Is there a way to fix this? Many thanks!

Re: Is there an "open folder" event

Posted: 26 Feb 2021, 12:08
by teadrinker
Can't reproduce the issue. Try running as admin.

Re: Is there an "open folder" event

Posted: 26 Feb 2021, 14:10
by Falleau
I found the cause of the issue. It lies in this block of code:

Code: Select all

getStdOut(vTarget, vSize:="")
{
	Local
	DetectHiddenWindows, On
	vComSpec := A_ComSpec ? A_ComSpec : ComSpec
	Run, % vComSpec,, Hide, vPID
	WinWait, % "ahk_pid " vPID
	DllCall("kernel32\AttachConsole", "UInt",vPID)
	oShell := ComObjCreate("WScript.Shell")
	oExec := oShell.Exec(vTarget)
	vStdOut := ""
	if !(vSize = "")
		VarSetCapacity(vStdOut, vSize)
	while !oExec.StdOut.AtEndOfStream
		vStdOut := oExec.StdOut.ReadAll()
	DllCall("kernel32\FreeConsole")
	Process, Close, % vPID
	return vStdOut
}
...or anything similar in style, this kind of function grabs the output of the command prompt while it's completely hidden from the background. If I try to run that function globally, even once, such as:

Code: Select all

retrieveCommand = cmd.exe /c "powercfg.exe /list"
retrieveSchemes := getStdOut(retrieveCommand)
The folder watcher hook completely goes bonkers. Particularly, the GetFolderPath() function is affected. Do you have ideas why these two seem to clash with each other? Thank you.

Re: Is there an "open folder" event

Posted: 26 Feb 2021, 15:10
by teadrinker
Falleau wrote: Do you have ideas why these two seem to clash with each other?
No idea. But you can use this instead:

Code: Select all

retrieveCommand = powercfg.exe /list
MsgBox, % retrieveSchemes := CmdRet(retrieveCommand)

CmdRet(sCmd, callBackFuncObj := "", encoding := "")
{
   static flags := [HANDLE_FLAG_INHERIT := 0x1, CREATE_NO_WINDOW := 0x8000000], STARTF_USESTDHANDLES := 0x100
        
   (encoding = "" && encoding := "cp" . DllCall("GetOEMCP", "UInt"))
   DllCall("CreatePipe", "PtrP", hPipeRead, "PtrP", hPipeWrite, "Ptr", 0, "UInt", 0)
   DllCall("SetHandleInformation", "Ptr", hPipeWrite, "UInt", flags[1], "UInt", flags[1])
   
   VarSetCapacity(STARTUPINFO , siSize :=    A_PtrSize*4 + 4*8 + A_PtrSize*5, 0)
   NumPut(siSize              , STARTUPINFO)
   NumPut(STARTF_USESTDHANDLES, STARTUPINFO, A_PtrSize*4 + 4*7)
   NumPut(hPipeWrite          , STARTUPINFO, A_PtrSize*4 + 4*8 + A_PtrSize*3)
   NumPut(hPipeWrite          , STARTUPINFO, A_PtrSize*4 + 4*8 + A_PtrSize*4)
   
   VarSetCapacity(PROCESS_INFORMATION, A_PtrSize*2 + 4*2, 0)

   if !DllCall("CreateProcess", "Ptr", 0, "Str", sCmd, "Ptr", 0, "Ptr", 0, "UInt", true, "UInt", flags[2]
                              , "Ptr", 0, "Ptr", 0, "Ptr", &STARTUPINFO, "Ptr", &PROCESS_INFORMATION)
   {
      DllCall("CloseHandle", "Ptr", hPipeRead)
      DllCall("CloseHandle", "Ptr", hPipeWrite)
      throw "CreateProcess is failed"
   }
   DllCall("CloseHandle", "Ptr", hPipeWrite)
   VarSetCapacity(sTemp, 4096), nSize := 0
   while DllCall("ReadFile", "Ptr", hPipeRead, "Ptr", &sTemp, "UInt", 4096, "UIntP", nSize, "UInt", 0) {
      sOutput .= stdOut := StrGet(&sTemp, nSize, encoding)
      ( callBackFuncObj && callBackFuncObj.Call(stdOut) )
   }
   DllCall("CloseHandle", "Ptr", NumGet(PROCESS_INFORMATION))
   DllCall("CloseHandle", "Ptr", NumGet(PROCESS_INFORMATION, A_PtrSize))
   DllCall("CloseHandle", "Ptr", hPipeRead)
   Return sOutput
}

Re: Is there an "open folder" event

Posted: 26 Feb 2021, 23:08
by Falleau
Awesome, that approach does not conflict with the hook at all. Thank you so much! :D

Re: Is there an "open folder" event

Posted: 27 Feb 2021, 01:11
by superpeter
That is so awesome, thanks teadrinker! I can keep a log of when each subfolder was opened in the main folder.

Just wondering, is it possible to similarly check if a file (say, a text file or any kind of file) is opened in a certain folder? Thx

Re: Is there an "open folder" event

Posted: 27 Feb 2021, 07:44
by teadrinker
superpeter wrote: if a file (say, a text file or any kind of file) is opened in a certain folder?
What do you mean by this? A file from a certain folder is open in any application, or an opened folder contains a certain file?

Re: Is there an "open folder" event

Posted: 27 Feb 2021, 12:14
by superpeter
Sorry, I meant if "A file from a certain folder is opened." For example, if "somefile.txt" (from a certain folder) is opened, a Msgbox would pop up. Or if "anyfile.*" (any type of file) is opened from a certain folder.

For "if a folder contains a certain file," I think I can use If FileExist. :)

Re: Is there an "open folder" event

Posted: 27 Feb 2021, 12:47
by teadrinker
It very depends on application which open a file. I don't know any reliable way to find out what the file is open with notepad.

Re: Is there an "open folder" event

Posted: 27 Feb 2021, 12:59
by superpeter
I tested with the following code and it seems to work!

Code: Select all

settimer, check, 1000

var := "test copy"
check:
loop
{
IfWinExist, %var% - Notepad
 msgbox, The file %var% has been opened
}
return 

Re: Is there an "open folder" event

Posted: 27 Feb 2021, 13:08
by teadrinker
But where is a folder path there?