Reopen Last closed window script - what is wrong here?

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
Madma
Posts: 9
Joined: 01 Sep 2018, 13:36

Reopen Last closed window script - what is wrong here?

Post by Madma » 29 Sep 2022, 08:21

Hi everyone!

I'm trying to get this script to work properly but I'm not sure if there's an error in the script or the script is not doing what it is supposed to do.

I found this script online when searching for a way to reopen the last closed window, but if I trigger it, it does not open the last closed window folder but the directory above it. Can someone please help me understand how to fix it or why is this happening?
Unfortunately I don't have any clue about DllCalls so this script looks a bit difficult to decypher.

Thanks a lot for your time and help.
All the best


Code: Select all

#Persistent
SetBatchLines, -1
Process, Priority,, High

WinGet, ListEW, List, ahk_class CabinetWClass
Loop, %ListEW%
{
	ControlGetText, Title%A_Index%, ToolBarWindow322, % "ahk_id " . ListEW%A_Index%
	Title%A_Index% := SubStr(Title%A_Index%, InStr(Title%A_Index%, ":") + 2)
	MsgBox % title%A_Index%
}
SetTimer, Check, 1500
Gui +LastFound
hWnd := WinExist()

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

!e::
If (LastPath = "")
	MsgBox No Explorer Window closed since script has been run.
Else 
	Run, % "explorer /e," LastPath
Return

ShellMessage( wParam,lParam ) {
	global
	If (wParam = 1) ;  HSHELL_WINDOWCREATED := 1
	{
		WinGetClass, Class, ahk_id %lParam%
		If (Class != "CabinetWClass")
			Return
		++ListEW, ListEW%ListEW% := lParam
		ControlGetText, Title%ListEW%, ToolBarWindow322, ahk_id %lParam%
		Title%ListEW% := SubStr(Title%ListEW%, InStr(Title%ListEW%, ":") + 2)
	}
	Else If (wParam = 2)  ;  HSHELL_WINDOWDESTROYED := 2
	{
		Loop, %ListEW%
			If (lParam = ListEW%A_Index%)
				LastPath := Title%A_Index%
	}
}

Check:
Loop, %ListEW%
{
	If (WinActive("ahk_id " . ListEW%A_Index%))
	{
		ControlGetText, Title%A_Index%, ToolBarWindow322, % "ahk_id " . ListEW%A_Index%
		Title%A_Index% := SubStr(Title%A_Index%, InStr(Title%A_Index%, ":") + 2)
	}
}

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

Re: Reopen Last closed window script - what is wrong here?

Post by teadrinker » 29 Sep 2022, 10:21

Try this:

Code: Select all

global ExistingWindows := {}

CollectExistingWindows()
Hook := new ShellHook("ShellProc")
Return

!e::
   if !ExistingWindows.lastClosed
      MsgBox No Explorer Window closed since script has been run.
   else
      OpenShellWindow(ExistingWindows.lastClosed)
Return

OpenShellWindow(folderPath) {
   for window in ComObjCreate("Shell.Application").Windows {
      if (window.Document.Folder.Self.Path = folderPath && found := window.hwnd)
         break
   }
   if found
      WinActivate, % "ahk_id" . found
   else
      Run, % folderPath
}

CollectExistingWindows() {
   for window in ComObjCreate("Shell.Application").Windows
      ExistingWindows[window.hwnd] := window.Document.Folder.Self.Path
}

ShellProc(nCode, wParam) {
   static HSHELL_WINDOWCREATED := 1, HSHELL_WINDOWDESTROYED := 2
   if (nCode = HSHELL_WINDOWCREATED) {
      for window in ComObjCreate("Shell.Application").Windows {
         if (wParam = window.hwnd) {
            ExistingWindows[window.hwnd] := window.Document.Folder.Self.Path
            break
         }
      }
   }
   if (nCode = HSHELL_WINDOWDESTROYED) {
      if ExistingWindows.HasKey(wParam)
         ExistingWindows.lastClosed := ExistingWindows.Delete(wParam)
   }
}

class ShellHook
{
   __New(shellProc) {
      DllCall("RegisterShellHookWindow", "Ptr", A_ScriptHwnd) 
      OnMessage(DllCall("RegisterWindowMessage", "Str", "SHELLHOOK"), shellProc) 
   }
   
   __Delete() {
      DllCall("DeregisterShellHookWindow", "Ptr", A_ScriptHwnd)
   }
}

Madma
Posts: 9
Joined: 01 Sep 2018, 13:36

Re: Reopen Last closed window script - what is wrong here?

Post by Madma » 29 Sep 2022, 10:43

Thanks a lot for your answer.

Unfortunately this gives me the same problem. Maybe it's just me expecting it to do something else.

basically if I open eg: "C:\" then browse into Programs, then xxx, then yyy subfolders... if I close the window then press !e, the directory opened is only "C:\", rather than "C:\Programs\xxx\yyy"...

shouldn't open the last closed directory? or am I wrong? how to add that remaining "...\Programs\xxx\yyy\" part?

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

Re: Reopen Last closed window script - what is wrong here?

Post by teadrinker » 29 Sep 2022, 12:37

Fixed:

Code: Select all

global ExistingWindows := {}

CollectExistingWindows()
Hook := new ShellHook("ShellProc")
Return

!e::
   if !ExistingWindows.lastClosed
      MsgBox No Explorer Window closed since script has been run.
   else
      OpenShellWindow(ExistingWindows.lastClosed)
Return

OpenShellWindow(folderPath) {
   for window in ComObjCreate("Shell.Application").Windows {
      if (window.Document.Folder.Self.Path = folderPath && found := window.hwnd)
         break
   }
   if found
      WinActivate, % "ahk_id" . found
   else
      Run, % folderPath
}

CollectExistingWindows() {
   for window in ComObjCreate("Shell.Application").Windows {
      ExistingWindows[window.hwnd] := {currentPath: window.Document.Folder.Self.Path, window: window}
      ComObjConnect(window, "Shell_")
   }
}

ShellProc(nCode, wParam) {
   static HSHELL_WINDOWCREATED := 1, HSHELL_WINDOWDESTROYED := 2
   if (nCode = HSHELL_WINDOWCREATED) {
      WinGetClass, winClass, ahk_id %wParam%
      if (winClass != "CabinetWClass")
         Return
      
      for window in ComObjCreate("Shell.Application").Windows {
         if (wParam = window.hwnd) {
            ExistingWindows[window.hwnd] := {currentPath: window.Document.Folder.Self.Path, window: window}
            ComObjConnect(window, "Shell_")
            break
         }
      }
   }
   if (nCode = HSHELL_WINDOWDESTROYED && ExistingWindows.HasKey(wParam)) {
      ComObjConnect(ExistingWindows[wParam, "window"])
      ExistingWindows.lastClosed := ExistingWindows.Delete(wParam).currentPath
   }
}

Shell_NavigateComplete2(window, url) {
   ExistingWindows[window.hwnd, "currentPath"] := url
}

class ShellHook
{
   __New(shellProc) {
      DllCall("RegisterShellHookWindow", "Ptr", A_ScriptHwnd) 
      OnMessage(this.msg := DllCall("RegisterWindowMessage", "Str", "SHELLHOOK"), this.shellProc := shellProc) 
   }
   
   __Delete() {
      if IsObject(this.shellProc)
         OnMessage(this.msg, this.shellProc, 0)
      else
         OnMessage(this.msg, "")
      DllCall("DeregisterShellHookWindow", "Ptr", A_ScriptHwnd)
   }
}
Last edited by teadrinker on 29 Sep 2022, 21:52, edited 1 time in total.


Madma
Posts: 9
Joined: 01 Sep 2018, 13:36

Re: Reopen Last closed window script - what is wrong here?

Post by Madma » 29 Sep 2022, 14:35

Daaaamn!! You're awesome!
Thank you so much! It works flawlessly!!

I unfortunately don't understand almost anything from your script, sorry my ignorance. But damn. Great!

Awesome you also completely rewrote it in a completely different way compared to the original. Didn't see it coming...
I don't expect for you to explain it but...
Thanks a lot! Brilliant

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

Re: Reopen Last closed window script - what is wrong here?

Post by teadrinker » 29 Sep 2022, 15:24

Madma wrote: I don't expect for you to explain it
I could explain, but I need to know your level. Do you understand how your version works (or should work), at least approximately?

PaigeDown
Posts: 19
Joined: 24 Dec 2022, 15:26

Re: Reopen Last closed window script - what is wrong here?

Post by PaigeDown » 25 Dec 2022, 14:29

teadrinker wrote:
29 Sep 2022, 13:07
Edited one more time.
this is excellent! is is possible to extend this to reopen a non explorer window as well? so whatever the last <anything> closed was?
merry Christmas!

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

Re: Reopen Last closed window script - what is wrong here?

Post by teadrinker » 25 Dec 2022, 15:26

Merry Christmas!
PaigeDown wrote: so whatever the last <anything> closed was?
I think in general this is not possible. Imagine, the last closed window is some kind of settings window for some application. How can my script know how to open it again?

PaigeDown
Posts: 19
Joined: 24 Dec 2022, 15:26

Re: Reopen Last closed window script - what is wrong here?

Post by PaigeDown » 26 Dec 2022, 02:58

teadrinker wrote:
25 Dec 2022, 15:26
Merry Christmas!
PaigeDown wrote: so whatever the last <anything> closed was?
I think in general this is not possible. Imagine, the last closed window is some kind of settings window for some application. How can my script know how to open it again?
hey, thanks for the response!
i did a lot of googling since this msg, and found a script that does it, but i like your implementation of it better, with a simple hotkey to restore. i don't want to have to click a tray menu. this is what i found, could its implementation be added to yours?

cheers merry christmas

Code: Select all

;GoneIn60s.ahk
; Recover closed applications
;Skrommel @ 2006

#NoEnv
#SingleInstance,Force

OnExit,EXIT

CoordMode,Mouse,Screen
CoordMode,ToolTip,Screen

SysGet,SM_CYCAPTION,4
SysGet,SM_CXBORDER,5
SysGet,SM_CYBORDER,6
SysGet,SM_CXEDGE,45
SysGet,SM_CYEDGE,46
SysGet,SM_CXFIXEDFRAME,7
SysGet,SM_CYFIXEDFRAME,8
SysGet,SM_CXSIZEFRAME,32
SysGet,SM_CYSIZEFRAME,33
SysGet,SM_CXSIZE,30
SysGet,SM_CYSIZE,31

applicationname=GoneIn60s

Gosub,INIREAD

inside=0

Gosub,TRAYMENU
SetTimer,CHECK,1000

Loop
{
  Sleep,100
  MouseGetPos,mx,my,win1
  parent:=DllCall("GetParent","uint",win1)
  If parent>0
    Continue
  WinGetPos,x,y,w,h,ahk_id %win1%
  l:=x+w-SM_CXSIZEFRAME-SM_CXSIZE
  t:=y+SM_CYSIZEFRAME
  r:=x+w-SM_CXSIZEFRAME
  b:=y+SM_CYSIZEFRAME+SM_CYSIZE
  If (mx<l Or mx>r Or my<t Or my>b)
  {
    If inside=1
    {
      ToolTip,
      Hotkey,LButton,CLICK,Off
      inside=0
    }
  }
  Else
  {
    If inside=0
    {
      WinGet,program,ProcessName,ahk_id %win1%
      If program In %ignore%
        Continue 
      WinGetClass,class,ahk_id %win1%
      If class In %nonwindows%
        Continue 
      ToolTip,Gone in %timeout% seconds
      Hotkey,LButton,CLICK,On
      inside=1
    }
  }
}


!F4::
WinGet,win1,Id,A
parent:=DllCall("GetParent",UInt,win1)
If parent>0
  Return
WinGetClass,class,ahk_id %win1%
If class In %nonwindows%
  Return

CLICK:
WinHide,ahk_id %win1%
IfNotInString,closing,%win1%
{
  closing=%closing%%win1%-%A_TickCount%|
  Gosub,TRAYMENU
}
Return


CHECK:
StringSplit,part_,closing,|
Loop,% part_0-1
{
  StringSplit,info_,part_%A_Index%,-
  IfWinExist,ahk_id %info_1%
  {
    left:=Ceil((info_2+timeout*1000-A_TickCount)/1000)
    TrayTip,%applicationname%,Recovered with %left% seconds left!
    StringReplace,closing,closing,%info_1%-%info_2%|
    Gosub,TRAYMENU
  }
  Else
  If (A_TickCount>=info_2+timeout*1000)
  {
    DetectHiddenWindows,On
    If kill=1
    {
      WinGet,pid,Pid,ahk_id %info_1%
      Process,Close,%pid%
    }
    Else
      WinClose,ahk_id %info_1%
    DetectHiddenWindows,Off
    Sleep,1000
    WinShow,ahk_id %info_1%
    StringReplace,closing,closing,%info_1%-%info_2%|
    Gosub,TRAYMENU
  }
 }
Return


RECOVER:
menuitem:=A_ThisMenuItemPos-4
StringSplit,part_,closing,|
StringSplit,info_,part_%menuitem%,-
WinShow,ahk_id %info_1%
Return


RECOVERALL:
StringSplit,part_,closing,|
Loop,% part_0-1
{
  StringSplit,info_,part_%A_Index%,-
  WinShow,ahk_id %info_1%
}
Return


CLOSEALL:
StringSplit,part_,closing,|
Loop,% part_0-1
{
  StringSplit,info_,part_%A_Index%,-
  DetectHiddenWindows,On
  If kill=1
  {
    WinGet,pid,Pid,ahk_id %info_1%
    Process,Close,%pid%
  }
  Else
    WinClose,ahk_id %info_1%
  DetectHiddenWindows,Off
  Sleep,1000
  WinShow,ahk_id %info_1%
  StringReplace,closing,closing,%info_1%-%info_2%|
  Gosub,TRAYMENU
 }
Return



SETTINGS:
ok=0
Gui,Destroy
Gui,Margin,20,10

Gui,Add,GroupBox,xm-10 w300 h50,&Time to wait
Gui,Add,Edit,xm yp+20 w100 vtimeout
Gui,Add,UpDown,x+5,%timeout%
Gui,Add,Text,x+5 yp+2,seconds

Gui,Add,GroupBox,xm-10 y+20 w300 h50,Actions
Gui,Add,CheckBox,xm yp+20 vkill Checked%kill%,&Kill windows   Won't ask to save changed documents!

Gui,Add,GroupBox,xm-10 y+20 w300 h120,&Programs to ignore
Gui,Add,Edit,xm yp+20 r5 w280 vignore,%ignore%
Gui,Add,Text,xm y+5,Example: Notepad.exe,Calc.exe,Pbrush.exe

Gui,Add,GroupBox,xm-10 y+20 w300 h120,Cl&asses to ignore
Gui,Add,Edit,xm yp+20 r5 w280 vsystem,%system%
Gui,Add,Text,xm y+5,Example: Shell_TrayWnd,Progman,#32768

Gui,Add,Button,xm y+20 w75 gSETTINGSOK,&OK
Gui,Add,Button,x+5 w75 gSETTINGSCANCEL,&Cancel

Gui,Show,,%applicationname% Settings

Loop
{
  If ok=1
    Break
  MouseGetPos,x,y,winid,ctrlid
  WinGet,program,ProcessName,ahk_id %winid%
  WinGetClass,class,ahk_id %winid%
  ToolTip,Program: %program%`nClass:      %class%
  Sleep,100
}
ToolTip,
Return


GuiClose:
SETTINGSOK:
ok=1
Gui,Submit
Gosub,INIWRITE
Return


SETTINGSCANCEL:
ok=1
Gui,Destroy
Return


TRAYMENU:
Menu,Tray,NoStandard
Menu,Tray,DeleteAll
Menu,Tray,Add,%applicationname%,RECOVERALL
Menu,Tray,Add
Menu,Tray,Add,&Recover All,RECOVERALL
Menu,Tray,Add
DetectHiddenWindows,On
StringSplit,part_,closing,|
Loop,% part_0-1
{
  StringSplit,info_,part_%A_Index%,-
  WinGetTitle,title,ahk_id %info_1%
  Menu,Tray,Add,&%A_Index% - %title%,RECOVER
}
DetectHiddenWindows,Off
Menu,Tray,Add
Menu,Tray,Add,&Settings...,SETTINGS
Menu,Tray,Add,&About...,ABOUT
Menu,Tray,Add,E&xit,EXIT
Menu,Tray,Default,%applicationname%
Menu,Tray,Tip,%applicationname%
Return


ABOUT:
ok=1
Gui,99:Destroy
Gui,99:Margin,20,20
Gui,99:Add,Picture,xm Icon1,%applicationname%.exe
Gui,99:Font,Bold
Gui,99:Add,Text,x+10 yp+10,%applicationname% v1.4
Gui,99:Font
Gui,99:Add,Text,y+10,Recover closed applications
Gui,99:Add,Text,y+10,- To recover, rightclick the tray icon and choose an application 
Gui,99:Add,Text,y+10,- Doubleclick the tray icon to recover all closed applications
Gui,99:Add,Text,y+10,- If not recovered, it is gone in %timeout% seconds

Gui,99:Add,Picture,xm y+20 Icon5,%applicationname%.exe
Gui,99:Font,Bold
Gui,99:Add,Text,x+10 yp+10,1 Hour Software by Skrommel
Gui,99:Font
Gui,99:Add,Text,y+10,For more tools, information and donations, please visit 
Gui,99:Font,CBlue Underline
Gui,99:Add,Text,y+5 G1HOURSOFTWARE,www.1HourSoftware.com
Gui,99:Font

Gui,99:Add,Picture,xm y+20 Icon7,%applicationname%.exe
Gui,99:Font,Bold
Gui,99:Add,Text,x+10 yp+10,DonationCoder
Gui,99:Font
Gui,99:Add,Text,y+10,Please support the contributors at
Gui,99:Font,CBlue Underline
Gui,99:Add,Text,y+5 GDONATIONCODER,www.DonationCoder.com
Gui,99:Font

Gui,99:Add,Picture,xm y+20 Icon6,%applicationname%.exe
Gui,99:Font,Bold
Gui,99:Add,Text,x+10 yp+10,AutoHotkey
Gui,99:Font
Gui,99:Add,Text,y+10,This tool was made using the powerful
Gui,99:Font,CBlue Underline
Gui,99:Add,Text,y+5 GAUTOHOTKEY,www.AutoHotkey.com
Gui,99:Font

Gui,99:Show,,%applicationname% About
hCurs:=DllCall("LoadCursor","UInt",NULL,"Int",32649,"UInt") ;IDC_HAND
OnMessage(0x200,"WM_MOUSEMOVE") 
Return

1HOURSOFTWARE:
  Run,http://www.1hoursoftware.com,,UseErrorLevel
Return

DONATIONCODER:
  Run,http://www.donationcoder.com,,UseErrorLevel
Return

AUTOHOTKEY:
  Run,http://www.autohotkey.com,,UseErrorLevel
Return

99GuiClose:
  Gui,99:Destroy
  OnMessage(0x200,"")
  DllCall("DestroyCursor","Uint",hCur)
Return

WM_MOUSEMOVE(wParam,lParam)
{
  Global hCurs
  MouseGetPos,,,,ctrl
  If ctrl in Static10,Static14,Static18
    DllCall("SetCursor","UInt",hCurs)
  Return
}
Return


EXIT:
Gosub,CLOSEALL
ExitApp


INIREAD:
IniRead,timeout,%applicationname%.ini,Settings,timeout
If timeout=ERROR
  timeout=60
IniRead,kill,%applicationname%.ini,Settings,kill
If kill=ERROR
  kill=0
IniRead,ignore,%applicationname%.ini,Settings,ignore
If ignore=ERROR
  ignore=Notepad.exe
IniRead,system,%applicationname%.ini,Settings,system
If system=ERROR
  system=Shell_TrayWnd,Progman,#32768,Basebar,DV2ControlHost
StringReplace,ignore,ignore,%A_Space%`,,`,,All
StringReplace,ignore,ignore,`,%A_Space%,`,,All
StringReplace,system,system,%A_Space%`,,`,,All
StringReplace,system,system,`,%A_Space%,`,,All
Return


INIWRITE:
StringReplace,ignore,ignore,%A_Space%`,,`,,All
StringReplace,ignore,ignore,`,%A_Space%,`,,All
StringReplace,system,system,%A_Space%`,,`,,All
StringReplace,system,system,`,%A_Space%,`,,All
IniWrite,%timeout%,%applicationname%.ini,Settings,timeout
IniWrite,%kill%,%applicationname%.ini,Settings,kill
IniWrite,%ignore%,%applicationname%.ini,Settings,ignore
IniWrite,%system%,%applicationname%.ini,Settings,system
Return



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

Re: Reopen Last closed window script - what is wrong here?

Post by teadrinker » 26 Dec 2022, 03:43

PaigeDown wrote: could its implementation be added to yours?
Oh, no, sorry! :)
This script uses a completely different approach. I don't think it makes sense to merge my script with this one.

Post Reply

Return to “Ask for Help (v1)”