I would like testing and feedback (I'm hoping this is the correct place for this mods please move/delete as appropriate)
As anyone who alters environment variables frequently knows Visual studio doesn't pick them up automatically.
I found exiting and restarting all instances of explorer.exe gets Visual Studio picking up the latest set of environment variables without a restart.
Unfortunately this means you lose all your open windows.
I have written an AutoHotKey (www.AutoHotKey.com) script to get around this.
; Array must be initialised
Full_Path := Object()
; First Array dimension must be setup
Full_Path[j] := A_LoopField
; Generate a list of HWND's for explorer windows
WinGet, id, list, ahk_class CabinetWClass
; iterate over all HWND's filling in our Full_Path array
Loop, %id%
{
; store hwnd in this_id for current loop
this_id := id%A_Index%
; Get the window information for this_id
WinGetText, pathToStore, ahk_id %this_id%
; strips the address out of the text storing in ActiveAddress
StringSplit, ActiveAddress, pathToStore, `n
; Turn's Path Into Variable
pathToStore = %ActiveAddress1%
; Remove's The Beginning "Address:" Phrase
pathToStore := RegExReplace(pathToStore, "^Address: ", "")
; Remove's Carriage Returns Incase it Exist in pathToStore
StringReplace, pathToStore, pathToStore, `r, , all
; Store the result in the Full_Path array
ifExist, %pathToStore%
Full_Path%A_Index% := pathToStore
}
; We can now kill all instances of explorer.exe at command prompt
Loop, %id%
{
; Store hwnd in id array
this_id := id%A_Index%
; get process id to kill from stored hwnd
WinGet, pidVal, PID, ahk_id %this_id%
; kill the explorer process
Run, taskkill /f /pid %pidVal%
}
; kill explorer shell
RunWait, taskkill /f /im explorer.exe
; restart explorer shell
Run, explorer
; open all windows we had open previously
Loop, %id%
{
; store actual path to open in local variable path To Open
pathToOpen := Full_Path%A_Index%
; Run explorer providing the correct path to open
Run, explorer %pathToOpen%
}
Return
Any advice or improvements you can make would be greatly appreciated.
Hopefully it will be of use to someone else.
Another approach:
; Get fullpath of all opened explorer windows:
If WinExist("ahk_class CabinetWClass") ; explorer
{
list := ""
; https://autohotkey.com/boards/viewtopic.php?p=28751#p28751
for window in ComObjCreate("Shell.Application").Windows
{
explorer_path := ""
try explorer_path := window.Document.Folder.Self.Path
list .= explorer_path ? explorer_path "`n" : ""
}
list := trim(list, "`n")
; MsgBox, "%list%"
}
; We can now restart the Explorer.exe Process:
RunWait, %comspec% /c taskkill /f /im explorer.exe ,,hide
Process, WaitClose, explorer.exe
Run, explorer.exe
; open all explorer windows we had open previously:
If (list != "")
{
Process, wait, explorer.exe
Loop, parse, list, `n
Run %A_LoopField%
}
Related
I created folder shortcuts for my taskbar and I would like them to stop launching a new explorer every time
So I decided to create a batch script, howover I can not get the kids from explorer.exe
#echo off
pushd
tasklist /nh /fi "imagename eq explorer.exe C:\Users\danil\Desktop\ISO" | find /i "explorer.exe C:\Users\danil\Desktop\ISO" > nul ||(start explorer.exe C:\Users\danil\Desktop\ISO)
The issue with your attempt is that tasklist will list only one instance of explorer.exe but not the titles of each window openned.
With some edits over this I've created listWindows.bat - it will list all visible windows names and their coresponding executable. So you can try this:
call listWindows.bat|findstr /i /b /e "explorer::Downloads" >nul 2>nul || (
start "" explorer.exe "C:\Users\%username%\Downloads"
)
To check the windows you need to start you can just try this:
call listWindows.bat|findstr /i /b "explorer::"
You cannot check the opening folders by checking the command line options, because the arguments stay the same across the whole lifetime of the process even after you changed to some other folders in that window. You need to use scriptable shell objects to get the current address.
Here's a PowerShell script to open a folder if it's not already opened in explorer
$folder = 'C:\Users\danil\Desktop\ISO'
$folderOpened = $false
foreach ($w in (New-Object -ComObject Shell.Application).Windows()) {
if ($w.LocationURL -ieq ([uri]$folder).AbsoluteUri) {
$folderOpened = $true; break
}
}
if (-not $folderOpened) { Invoke-Item $folder } # or start $folder
Below is an equivalent hybrid batch-jscript snippet
#if (#CodeSection == #Batch) #then
#echo off
cscript //e:jscript //nologo "%~f0" %*
exit /b
#end
// JScript Section
var objShell = new ActiveXObject("shell.application");
var objShellWindows;
objShellWindows = objShell.Windows();
if (objShellWindows != null)
{
// the folder you want to open
var folder = "file:///C:/Users/danil/Desktop/ISO";
var folderOpened = 0;
for (var objEnum = new Enumerator(objShellWindows);
!objEnum.atEnd(); objEnum.moveNext())
{
if (folder == objEnum.item().LocationUrl)
{
folderOpened = 1;
break;
}
}
if (!folderOpened) // open the folder if it's not already opened
objShell.Explore(folder); // or objshell.Open(folder)
}
Each explorer window is represented by an InternetExplorer object that can be retrieved from the Shell.Windows() collection. You need to use a file URI scheme instead of a normal Windows path, but it works. Of course you can even further change it to switch to the folder window if it's being opened. You can also use VBS or any other languages that support scriptable shell objects
Update:
You can avoid the file URI scheme by changing objEnum.item().LocationUrl to objEnum.item().Document.Folder.Self.Path
In the PowerShell version above it means changing
if ($w.LocationURL -ieq ([uri]$folder).AbsoluteUri) {
to
if ($w.Document.Folder.Self.Path -ieq $folder) {
I need to open a file in special program. For example, I need to open *.docx file if office word.
I have figured out how to run office
Example()
Func Example()
; Run Notepad with the window maximized.
Local $iPID = Run("C:\Program Files (x86)\Microsoft Office\Office15\WINWORD.EXE", "", #SW_SHOWMAXIMIZED)
; Wait 10 seconds for the Notepad window to appear.
WinWait("[CLASS:winword]", "", 5)
; Wait for 2 seconds.
Sleep(2000)
; Close the Notepad process using the PID returned by Run.
ProcessClose($iPID)
EndFunc ;==>
How to open the file?
For Word documents, just pass the name of the document as a command line argument
Example()
Func Example()
; Run Notepad with the window maximized.
Local $iPID = Run("C:\Program Files (x86)\Microsoft Office\Office15\WINWORD.EXE" & " " & "path_to_document", "", #SW_SHOWMAXIMIZED)
; Wait 10 seconds for the Notepad window to appear.
WinWait("[CLASS:winword]", "", 5)
; Wait for 2 seconds.
Sleep(2000)
; Close the Notepad process using the PID returned by Run.
ProcessClose($iPID)
EndFunc ;==>
Or use ShellExecute()
I'm having problem using the Navigate Shell command when the path include an # sign.
; this will create 2 folders at the root of your C: drive
myPath1 := "C:\delete_me\"
myPath2 := "C:\delete#me\"
if !FileExist(myPath1)
FileCreateDir, %myPath1%
if !FileExist(myPath2)
FileCreateDir, %myPath2%
; make an Explorer active and press Alt-1 and Alt-2
return
!1::
strWinId := WinExist("A")
TrayTip, %myPath1%, %strWinId%
For pExp in ComObjCreate("Shell.Application").Windows
if (pExp.hwnd = strWinId)
try pExp.Navigate(myPath1)
return
!2::
strWinId := WinExist("A")
TrayTip, %myPath2%, %strWinId%
For pExp in ComObjCreate("Shell.Application").Windows
if (pExp.hwnd = strWinId)
try pExp.Navigate(myPath2)
return
Alt-1 works well. But, with Alt-2, the Navigate command returns "file:///C:/delete#me/ » not found.".
If there is no "/" after the "#" (eg myPath := "C:\delete#me"), it works. But this cannot be a solution because the destination path can be deeper in a subfolder (eg. "C:\delete#me\xyz").
I tried to encode the "#", replacing it with "%23", without success. Found nothing on the web or MSDN about that. Any idea?
[keywords: haskmark, hashtag, number sign or pound]
I have what looks to be a working solution for this, which I've also posted here:
4 options to change the current folder in Windows Explorer - Page 3 - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=526&p=153676#p153676
;links:
;Explorer Windows Manipulations - Page 5 - Scripts and Functions - AutoHotkey Community
;https://autohotkey.com/board/topic/19039-explorer-windows-manipulations/page-5#entry297581
;Navigate2 Method (IWebBrowser2)
;https://msdn.microsoft.com/en-us/library/aa752134(v=vs.85).aspx
;4 options to change the current folder in Windows Explorer - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=5&t=526
;windows - Navigate Shell command not working when the path includes an hash - Stack Overflow
;https://stackoverflow.com/questions/22868546/navigate-shell-command-not-working-when-the-path-includes-an-hash
;an AutoHotkey v1.1 script
;note: will create folder: %A_Desktop%\abc#def\abc#def
;q:: ;explorer - navigate to folder (tested on Windows 7)
WinGet, hWnd, ID, A
WinGetClass, vWinClass, % "ahk_id " hWnd
if !(vWinClass = "CabinetWClass") && !(vWinClass = "ExploreWClass")
return
vDir = %A_Desktop%\abc#def\abc#def
;vDir = %A_Desktop%\abc def\abc def
if !FileExist(vDir)
FileCreateDir, % vDir
DllCall("shell32\SHParseDisplayName", WStr,vDir, Ptr,0, PtrP,vPIDL, UInt,0, Ptr,0)
for oWin in ComObjCreate("Shell.Application").Windows
if (oWin.HWND = hWnd)
{
if !InStr(vDir, "#")
oWin.Navigate(vDir)
else
{
VarSetCapacity(SAFEARRAY, A_PtrSize=8?32:24, 0)
NumPut(1, SAFEARRAY, 0, "UShort")
NumPut(1, SAFEARRAY, 4, "UShort")
NumPut(vPIDL, SAFEARRAY, A_PtrSize=8?16:12, "Ptr")
NumPut(DllCall("shell32\ILGetSize", Ptr,vPIDL, UInt), SAFEARRAY, A_PtrSize=8?24:16, "Int")
oWin.Navigate2(ComObject(0x2011,&SAFEARRAY))
DllCall("shell32\ILFree", Ptr,vPIDL)
}
break
}
return
If you want to open a new window, there's no need for COM or unreliable workarounds: just run the folder.
Run C:\delete#me
If you want to open the path in an existing window which is already active, the simplest and most effective workaround is this:
SendInput {F4}{Esc}{Raw}C:\delete#me`n
So in the context of your script, you could use the following function to work around the # when it is present:
Navigate(pExp, myPath2)
;...
Navigate(Exp, Path)
{
if RegExMatch(Path, "#.*\\")
SendInput {F4}{Esc}{Raw}%Path%`n
else
Exp.Navigate(Path)
}
Unfortunately, there does not seem to be a solution to this. Shell.Application Navigate command fails if the path includes a hash (# as in C:\C#Projects).
Using AutoHotkey, the workaround would be to rely on the "second best" approach as identified by the tests in this thread: http://ahkscript.org/boards/viewtopic.php?f=5&t=526.
run, Explorer.exe
Sleep, 500
strFolder := A_ScriptDir
Send, {F4}{Esc}
Sleep, 500
ControlSetText, Edit1, C:\delete#me, A
ControlSend, Edit1, {Enter}, A
When I saw that Navigate couldn't handle hash, I was shocked,
but sure enough I replicated the error.
I thought I'd try the short form path just in case. It works!
if vDir contains #
Loop, %vDir%, 2, 0 ;(0/1/2=files/both/folders, 0/1=recurse no/yes)
vDir := A_LoopFileShortPath
The following approach doesn't require a visible address bar, or SendInput,
also the previous navigation history is maintained.
In the worst-case scenario of a hash in the short-form path of the dir above the target dir,
a go-between folder is used which is navigated to.
A link is created there, invoked, and deleted.
Below, the workaround code is indented, to separate it from the standard code.
A hotkey of ctrl+q, when an Explorer window is active, launches the script.
-
^q:: ;explorer - navigate to directory (use go-between dir if short-form path of dir above target contains #)
WinGet, hWnd, ID, A
WinGetClass, vWinClass, ahk_id %hWnd%
if vWinClass not in CabinetWClass,ExploreWClass
Return
vDir2 = %A_Desktop%\Go-Between ;go-between dir
vDir3 = C:\delete#me ;target dir
if (SubStr(vDir3, 1-1) = "\")
vDir3 := SubStr(vDir3, 1, -1)
if !InStr(FileExist(vDir3), "D")
Return
vPathLnk := ""
if vDir3 contains #
Loop, %vDir3%, 2, 0 ;(0/1/2=files/both/folders, 0/1=recurse no/yes)
vDir3 := A_LoopFileShortPath
;vDir4 is the short-form path of the dir above the target
;paths of problem target dirs are of the form: *#*\*
;where there is at least one hash with a backslash to its right
SplitPath, vDir3, , vDir4
if vDir4 contains #
{
if !InStr(FileExist(vDir2), "D")
FileCreateDir, %vDir2%
if !InStr(FileExist(vDir2), "D")
{
MsgBox error`, go-between dir not found:`r`n%vDir2%
Return
}
vNameLnk = Go-Between.lnk
vPathLnk = %vDir2%\%vNameLnk%
FileCreateShortcut, %vDir3%, %vPathLnk%
}
for oWin in ComObjCreate("Shell.Application").Windows
if (hWnd = oWin.Hwnd)
{
vDir1 := oWin.Document.Folder.Self.Path
if (vDir1 = vDir3)
break
if vDir3 contains #
{
if !(vDir1 = vDir2)
oWin.Navigate(vDir2)
while !(oWin.ReadyState = 4)
Sleep 10
oItem := oWin.Document.Folder.Items.Item(vNameLnk)
oItem.InvokeVerbEx("open")
break
}
oWin.Navigate(vDir3)
break
}
oWin := ""
if !(vPathLnk = "")
FileRecycle, %vPathLnk% ;send to recycle bin
;if !(vPathLnk = "")
;FileDelete, %vPathLnk% ;delete
Return
I've collected a script from the AutoHotKey forum which lets me open a command prompt at the location I'm open in windows explorer. If the current window is not a explorer window then the prompt opens at the location where the script is present. I would like to change this behavior and make it open from C:\ if the current window is not a explorer window. I've tried to edit the script but its not working as desired.
#ifwinactive, ahk_class CabinetWClass
ControlGetText, address , edit1, ahk_class CabinetWClass
if (address <> "") {
Run, cmd.exe, %address%
}
else {
Run, cmd.exe, "C:"
}
ExitApp
#ifwinactive
The command to run cmd.exe in the c:\ path is
run, cmd.exe, c:\
A full script that would run the cmd window every time would look like this
SetTitleMatchMode, 2
ifwinactive, ahk_class CabinetWClass
ControlGetText, address , edit1, ahk_class CabinetWClass
else
address =
; Exclude specific windows
ifwinactive, My Computer
address =
ifwinactive, My Documents
address =
if (address <> "")
Run, cmd.exe, %address%
else
Run, cmd.exe, C:\
ExitApp
I realize this is an old question, but I was looking into this myself and have a better solution.
Windows has two in-built ways to start cmd at the path of a current explorer window. Shift+RightClick and then click Open Command Window Here (or press w). You can also press alt+d, type cmd, and press enter. So...
LWin & Return::
if WinActive("ahk_class CabinetWClass")
or WinActive("ahk_class ExploreWClass")
{
Send {Shift Down}{AppsKey}{Shift Up}
Sleep 10
Send w{enter}
}
else
{
run, cmd, C:\
}
return
No magically grabbing the address directly from explorer! :)
Couldn't get other answers to work (it has been a few years since they've been written).
I ended up writing this script:
#o::
Send {Alt down}D{Alt up}cmd{enter}
return
Here's a pretty sophisticated script from the AHK forums:
#NoEnv
#SingleInstance Force
#NoTrayIcon
SendMode Input
SetWorkingDir %A_ScriptDir%
SetTitleMatchMode RegEx
#IfWinActive ahk_class ExploreWClass|CabinetWClass|Progman
#c::
WinGetClass WinClass
If ( WinClass = "Progman" )
{
Run %ComSpec% /K cd /D "C:\"
Return
}
If ( InStr( "WIN_7,WIN_VISTA" , A_OSVersion ) )
{
ControlGetText, Path, ToolbarWindow322
RegExMatch(Path, ":\s*(.*)", Path)
Path := Path1
}
Else
{
; Windows XP doesn't know the Edit1 control exists if
; the Address Bar is hidden, so check if it exists and temporarly
; show the Address bar if needed. Temporarly showing the Address bar
; will register the Edit1 control, which contains the path.
ControlGetPos Edit1Pos , , , , Edit1
If ( !Edit1Pos )
{
PostMessage 0x111 , 41477 , 0 , , A ; Show Address Bar
Sleep 100
PostMessage 0x111 , 41477 , 0 , , A ; Hide Address Bar
}
ControlGetText Path , Edit1
}
If ( InStr( Path , ":" ) )
; If( InStr( Path , ":" ) && FileExist(Path) )
Run %ComSpec% /K cd /D "%Path%"
Else
Run %ComSpec% /K cd /D "C:\"
Return
I tweaked the WIN_7 part a little, so that the code is independent of the unreliable Edit1 control, which doesn't always expose the current explorer location or an incorrect one. If ( InStr( Path , ":" ) ) makes sure that there's no custom path like Computer on Windows 7 or My Computer on Windows XP. I also added an alternative condition that additionally checks for the path to exist, if you want to hedge your bets.
Keep it simple. Unless of course you need complexity.
!f1::
run, C:\Windows\System32\cmd.exe
return
!f1 means Alt+F1. For my personal preference. Change it to whatever you like.
Another solution hacked together from here. Works for me on Windows 10, but I admit it's total copy-pasta. Posting in the hopes of saving someone else's eyes from the horror of AHK scripting.
;; Open terminal in current Explorer window folder
#If WinActive("ahk_class CabinetWClass") ; explorer
F4::
WinGetTitle, ActiveTitle, A
If InStr(ActiveTitle, "\") ; If the full path is displayed in the title bar (Folder Options)
Fullpath := ActiveTitle
else
If InStr(ActiveTitle, ":") ; If the title displayed is something like "DriveName (C:)"
{
Fullpath := SubStr(ActiveTitle, -2)
Fullpath := SubStr(Fullpath, 1, -1)
}
else ; If the full path is NOT displayed in the title bar
; https://autohotkey.com/boards/viewtopic.php?p=28751#p28751
for window in ComObjCreate("Shell.Application").Windows
{
try Fullpath := window.Document.Folder.Self.Path
SplitPath, Fullpath, title
If (title = ActiveTitle)
break
}
Run, cmd.exe, %Fullpath%
return
#If
I have a batch script I want to run with hotkeys, and this script is supposed to make some actions in the active window (for example, creating a particular set of folders, or lowercase all names of the files inside the folder). So the script needs to refer to the active window when it's called.
I have tried to leave the "Start in" field of the alias empty, but echoing %cd% always print "C:\Windows\System32" instead of the current active window.
You can lookup which process got the window in foreground using pinvoke of user32.dll.
I've used this trick for system.window.forms.sendkeys method in a script:
Add-Type #"
using System;
using System.Runtime.InteropServices;
public class Tricks {
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
}
"#
$a = [tricks]::GetForegroundWindow()
get-process | ? { $_.mainwindowhandle -eq $a } # in my case:
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
161 7 13984 15820 91 9,75 7720 Console
For anyone looking for a non-Powershell solution, here's a batch script that uses cscript to invoke a block of JScript. The JScript creates a new child process, gets its PID, then walks up the ParentProcessID line of ancestors until it gets to explorer.exe, then returns the PID of the direct child. It ought to return the correct PID for the console window in which the script runs, even if there are multiple instances of cmd.exe or cscript.exe running.
What can I say? I was feeling creative today.
#if (#a==#b) #end /* JScript multiline comment
:: begin batch portion
#echo off
setlocal
for /f "delims=" %%I in ('cscript /nologo /e:Jscript "%~f0"') do (
echo PID of this console window is %%I
)
goto :EOF
:: end batch portion / begin JScript */
var oShell = WSH.CreateObject('wscript.shell'),
johnConnor = oShell.Exec('%comspec% /k #echo;');
// returns PID of the direct child of explorer.exe
function getTopPID(PID, child) {
var proc = GetObject("winmgmts:Win32_Process=" + PID);
// uncomment the following line to watch the script walk up the ancestor tree
// WSH.Echo(proc.name + ' has a PID of ' + PID);
return (proc.name == 'explorer.exe') ? child : getTopPID(proc.ParentProcessID, PID);
}
var PID = getTopPID(johnConnor.ProcessID);
johnConnor.Terminate();
// send the console window to the back for a second, then refocus, just to show off
oShell.SendKeys('%{ESC}');
WSH.Sleep(1000);
oShell.AppActivate(PID);
// output PID of console window
WSH.Echo(PID);