Page 3 of 4

Re: 4 options to change the current folder in Windows Explor

Posted: 07 Feb 2014, 12:42
by fischgeek
Works great on 8.1. No modifications.

Re: 4 options to change the current folder in Windows Explor

Posted: 07 Feb 2014, 18:55
by JnLlnd
Azevedo wrote:Hi.
It works fine on a regular windows explorer window but it won't work on Open/Save dialogs.
Any help?

Thanks
The Shell.Application COM object is only opening or controling Explorr windows. For dialog boxes, you have to send commands to dialog box control and Send some keys.

See this script and search for NavigateDialog(strPath, strWinId, strClass) close to the end of the script.

Here is an abstract of the code (this will not work by itself but you have the ingredients):

Code: Select all

;------------------------------------------------------------
NavigateDialog(strPath, strWinId, strClass)
;------------------------------------------------------------
/*
Excerpt from RMApp_Explorer_Navigate(FullPath, hwnd="") by Learning One
http://ahkscript.org/boards/viewtopic.php?f=5&t=526&start=20#p4673
*/
{
	if (strClass = "#32770")
		if ControlIsVisible("ahk_id " . strWinId, "Edit1")
			strControl := "Edit1"
			; in standard dialog windows, "Edit1" control is the right choice
		Else if ControlIsVisible("ahk_id " . strWinId, "Edit2")
			strControl := "Edit2"
			; but sometimes in MS office, if condition above fails, "Edit2" control is the right choice 
		Else ; if above fails - just return and do nothing.
		{
			if (blnDiagMode)
				Diag("NavigateDialog", "Error: #32770 Edit1 and Edit2 controls not visible")
			return
		}
	Else if InStr(strClass, "bosa_sdm_") ; for some MS office dialog windows, which are not #32770 class
		if ControlIsVisible("ahk_id " . strWinId, "Edit1")
			strControl := "Edit1"
			; if "Edit1" control exists, it is the right choice
		Else if ControlIsVisible("ahk_id " . strWinId, "RichEdit20W2")
			strControl := "RichEdit20W2"
			; some MS office dialogs don't have "Edit1" control, but they have "RichEdit20W2" control, which is then the right choice.
		Else ; if above fails, just return and do nothing.
		{
			if (blnDiagMode)
				Diag("NavigateDialog", "Error: bosa_sdm Edit1 and RichEdit20W2 controls not visible")
			return
		}
	Else ; in all other cases, open a new Explorer and return from this function
	{
		ComObjCreate("Shell.Application").Explore(strPath)
		; http://msdn.microsoft.com/en-us/library/windows/desktop/bb774073%28v=vs.85%29.aspx
		if (blnDiagMode)
			Diag("NavigateDialog", "Not #32770 or bosa_sdm: open New Explorer")
		return
	}

	if (blnDiagMode)
	{
		Diag("NavigateDialogControl", strControl)
		Diag("NavigateDialogPath", strPath)
	}
			
	;===In this part (if we reached it), we'll send strPath to control and restore control's initial text after navigating to specified folder===
	ControlGetText, strPrevControlText, %strControl%, ahk_id %strWinId% ; we'll get and store control's initial text first
	
	ControlSetTextR(strControl, strPath, "ahk_id " . strWinId) ; set control's text to strPath
	ControlSetFocusR(strControl, "ahk_id " . strWinId) ; focus control
	if (WinExist("A") <> strWinId) ; in case that some window just popped out, and initialy active window lost focus
		WinActivate, ahk_id %strWinId% ; we'll activate initialy active window
	
	;=== Avoid accidental hotkey & hotstring triggereing while doing SendInput - can be done simply by #UseHook, but do it if user doesn't have #UseHook in the script ===
	If (A_IsSuspended)
		blnWasSuspended := True
	if (!blnWasSuspended)
		Suspend, On
	SendInput, {End}{Space}{Backspace}{Enter} ; silly but necessary part - go to end of control, send dummy space, delete it, and then send enter
	if (!blnWasSuspended)
		Suspend, Off

	Sleep, 70 ; give some time to control after sending {Enter} to it
	ControlGetText, strControlTextAfterNavigation, %strControl%, ahk_id %strWinId% ; sometimes controls automatically restore their initial text
	if (strControlTextAfterNavigation <> strPrevControlText) ; if not
		ControlSetTextR(strControl, strPrevControlText, "ahk_id " . strWinId) ; we'll set control's text to its initial text
	
	if (WinExist("A") <> strWinId) ; sometimes initialy active window loses focus, so we'll activate it again
		WinActivate, ahk_id %strWinId%

	if (blnDiagMode)
		Diag("NavigateDialog", "Finished")
}


;------------------------------------------------------------
ControlIsVisible(strWinTitle, strControlClass)
/*
Adapted from ControlIsVisible(WinTitle,ControlClass) by Learning One
http://ahkscript.org/boards/viewtopic.php?f=5&t=526&start=20#p4673
*/
;------------------------------------------------------------
{ ; used in Navigator
	ControlGet, blnIsControlVisible, Visible, , %strControlClass%, %strWinTitle%

	return blnIsControlVisible
}
;------------------------------------------------------------


;------------------------------------------------------------
ControlSetFocusR(strControl, strWinTitle = "", intTries = 3)
/*
Adapted from RMApp_ControlSetFocusR(Control, WinTitle="", Tries=3) by Learning One
http://ahkscript.org/boards/viewtopic.php?f=5&t=526&start=20#p4673
*/
;------------------------------------------------------------
{ ; used in Navigator. More reliable ControlSetFocus
	Loop, %intTries%
	{
		ControlFocus, %strControl%, %strWinTitle% ; focus control
		Sleep, % (50 * intTries) ; JL added "* intTries"
		ControlGetFocus, strFocusedControl, %strWinTitle% ; check
		if (strFocusedControl = strControl) ; if OK
		{
			if (blnDiagMode)
				Diag("ControlSetFocusR Tries", A_Index)
			return True
		}
	}
}
;------------------------------------------------------------


;------------------------------------------------------------
ControlSetTextR(strControl, strNewText = "", strWinTitle = "", intTries = 3)
/*
Adapted from from RMApp_ControlSetTextR(Control, NewText="", WinTitle="", Tries=3) by Learning One
http://ahkscript.org/boards/viewtopic.php?f=5&t=526&start=20#p4673
*/
;------------------------------------------------------------
{ ; used in Navigator. More reliable ControlSetText
	Loop, %intTries%
	{
		ControlSetText, %strControl%, %strNewText%, %strWinTitle% ; set
		Sleep, % (50 * intTries) ; JL added "* intTries"
		ControlGetText, strCurControlText, %strControl%, %strWinTitle% ; check
		if (strCurControlText = strNewText) ; if OK
		{
			if (blnDiagMode)
				Diag("ControlSetTextR Tries", A_Index)
			return True
		}
	}
}
;------------------------------------------------------------


See also this thread http://ahkscript.org/boards/viewtopic.p ... t=20#p4673

Good luck!

Re: 4 options to change the current folder in Windows Explor

Posted: 07 Feb 2014, 19:57
by Azevedo
The Shell.Application COM object is only opening or controling Explorr windows. For dialog boxes, you have to send commands to dialog box control and Send some keys.

See this script and search for NavigateDialog(strPath, strWinId, strClass) close to the end of the script.

Here is an abstract of the code (this will not work by itself but you have the ingredients):
Oh I see... well ok, I'll do with the send commands then!

Thanks a lot!

Re: 4 options to change the current folder in Windows Explor

Posted: 09 Feb 2014, 10:54
by JnLlnd
Just to make my comment more clear, you can use command like ControlGetText and ControlSetText to save and change the current dialog box folder. The Send key itself is used only to press "Enter". This could be relatively simple. But the longer approach described by Learning One in http://ahkscript.org/boards/viewtopic.p ... t=20#p4673 is much safer.

Of course, if you are doing something for yourself (I mean, you don't plan to distribute your code to other users), you could work this out using only Send and Sleep commands.

Re: 4 options to change the current folder in Windows Explor

Posted: 09 Feb 2014, 13:56
by Azevedo
Yes thanks,

Although I'm building it to myself I do want to be reliable and steady.
So I'm using ControlGetText and ControlSetText. I really do the trick!

Now the problem is with old Open/Save dialog boxes (which have simple combo box to navigate). It won't allow directly changing to a folder that is not in that combo box.

Navigate Shell command not working when the path includes ha

Posted: 04 Apr 2014, 11:57
by JnLlnd
Hello!

I'm having problem using the Navigate Shell command when the path include an # sign (search keywords: hashtag, number sign or pound).

I posted the question on StackOverflow:
http://stackoverflow.com/questions/2286 ... es-an-hash

You could reply here or on StackOverflow.

Thanks!

Re: 4 options to change the current folder in Windows Explor

Posted: 23 Apr 2014, 16:53
by JnLlnd
Unfortunately, there does not seem to be a solution to this:

Code: Select all

For pExp in ComObjCreate("Shell.Application").Windows
    if (pExp.hwnd = strWinId)
        try pExp.Navigate(myPath)
This will fail if myPath includes a hash (# as in C:\C#Projects).

The workaround would be to rely on the "second best" approach as identified by the tests in this thread: Explorer_F4Esc. For example (when Explorer is the active window):

Code: Select all

Send, {F4}{Esc}
Sleep, 500 ; long delay for safety
Send, %strFolder%{Enter}

Re: 4 options to change the current folder in Windows Explor

Posted: 23 Apr 2014, 19:14
by JnLlnd
Trying this with a folder name including # did not work! (EDIT: See foot note)

This works:

Code: Select all

run, Explorer.exe
Sleep, 500
Send, {F4}{Esc}
Sleep, 500
Send, c:\delete_me{Enter}
But this does not work: (EDIT: See foot note)

Code: Select all

run, Explorer.exe
Sleep, 500
Send, {F4}{Esc}
Sleep, 500
Send, c:\delete#me{Enter}
The only difference is the _ replaced by # ! It looks like Windows Explorer really have problem with hash in folder names.

Finally, the only way I found to make this work is:

Code: Select all

run, Explorer.exe
Sleep, 500 ; long delay for safety
strFolder := A_ScriptDir
Send, {F4}{Esc}
Sleep, 500 ; long delay for safety
ControlSetText, Edit1, C:\delete#me, A
ControlSend, Edit1, {Enter}, A
I could not give the rational behind this...

EDIT (2014-09-06): Send, c:\delete#me does not work only because # is a AHK special character when used with Send. The command works if you add the {Raw} option: Send, {Raw}c:\delete#me. See comments from Lexikos belo for more about this.

Re: 4 options to change the current folder in Windows Explor

Posted: 05 Sep 2014, 05:39
by lexikos
JnLlnd, I came across your posts while searching for something else, and thought I'd look into your issue. However, window.Navigate("C:\C#Projects") works just fine for me on Windows 7. It also works with "file:///C:/C#Projects". Your Send code fails because # is the modifier symbol for the Win key. You can use {#} or SendRaw c:\delete#me`n (not {Enter}) instead.

Code: Select all

; Test script: navigate the "Computer" window to a path containing #.
FileCreateDir C:\C#Projects
for window in ComObjCreate("Shell.Application").Windows
try
    if window.LocationName = "Computer"
        window.Navigate("C:\C#Projects")

Re: 4 options to change the current folder in Windows Explor

Posted: 05 Sep 2014, 07:23
by JnLlnd
lexikos wrote:Your Send code fails because # is the modifier symbol for the Win key. You can use {#} or SendRaw c:\delete#me`n (not {Enter}) instead.
Thanks for jumping in Lekikos. Yes, I realized that later in my AHK learning curve :-) . Just forgot to update this thread about it.
lexikos wrote:However, window.Navigate("C:\C#Projects") works just fine for me on Windows 7.
You script also worked for me (after I adapted window.LocationName = "Computer" to my environment. But could you try the following and tell me if Alt-2 is running well for you? For me, it still produced an error. Would it be related to # being a special AHK char?

Code: Select all

; 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%
run, Explorer.exe
return

!1::
!2::
strWinId := WinExist("A")
TrayTip, %myPath1%, %strWinId%
For pExp in ComObjCreate("Shell.Application").Windows
    if (pExp.hwnd = strWinId)
        try pExp.Navigate(A_ThisHotkey = "!1" ? "C:\delete_me\" : "C:\delete#me\")
return

Re: 4 options to change the current folder in Windows Explor

Posted: 06 Sep 2014, 18:47
by lexikos
Apparently it only works if there is no slash after the hash. (Edit: Reading your Stack Overflow post, I see you already figured that out.)
Would it be related to # being a special AHK char?
# is special only for Send and hotkeys. No character in a quoted literal string has special meaning, except ` and ".

When a message box from "Windows Explorer" appears saying that it cannot find "file:///C:/delete#me/", that clearly shows that Windows Explorer is showing the error message, not AutoHotkey, and that Windows Explorer received the proper file path, since it is shown in the error message. One can therefore conclude that the problem lies with Windows Explorer.

Re: 4 options to change the current folder in Windows Explor

Posted: 06 Sep 2014, 19:56
by lexikos
So, one limited workaround is to open a base folder and navigate to each sub folder. For example (call this instead of pExp.Navigate()):

Code: Select all

Navigate(Exp, Path)
{
    if !RegExMatch(Path, "^.*#[^\\]*(?=\\|$)", safe_path)
        safe_path := Path
    Exp.Navigate(safe_path)
    rem_path := SubStr(Path, StrLen(safe_path) + 2)  ; Could be "", which is okay
    Loop, Parse, rem_path, \
    {
        while Exp.ReadyState != 4
            Sleep 10
        item := Exp.Document.Folder.Items.Item(A_LoopField)
        if !item || !item.IsFolder
            throw Exception("Folder not found", -1, A_LoopField)
        item.InvokeVerbEx("open")
    }
}
Unfortunately, this won't work as intended if the user has Explorer set to open each folder in a separate window. For that case, you could Run %Path% and close the old window:

Code: Select all

Navigate(Exp, Path)
{
    if RegExMatch(Path, "#.*\\")
    {
        ; Workaround required
        WinGetPos x, y, w, h
        WinClose
        Run %Path%
        WinWait %Path% ahk_exe explorer.exe
        WinMove,,, x, y, w, h
    }
    else
        Exp.Navigate(Path)
}
This would need adjustment for systems without the "Display the full path in the title bar" option enabled.

Although Run %Path% should be reliable, it discards the (back/forward) history. Assuming you already have an Explorer window in the foreground that you want to open the folder in, this approach seems to be fairly reliable:

Code: Select all

Navigate(Exp, Path)
{
    if RegExMatch(Path, "#.*\\")
        SendInput {F4}{Esc}{Raw}%Path%`n
    else
        Exp.Navigate(Path)
}

Re: 4 options to change the current folder in Windows Explor

Posted: 06 Sep 2014, 22:47
by JnLlnd
Hum... Interesting. So much work for something that should just be working in the first time... I suppose this is not the first time you have to work that hard around a Windows bug :-)

I adapted my code to use SendInput command with {Raw} option instead of the ControlSetText approach that is now irrelevant. I also use your regex instead of a simple InStr. This will limit the use of the workaround to the cases where there is a \ after the #.

Being on StackOverflow, I would definitively + your answer :-)

Re: 4 options to change the current folder in Windows Explorer

Posted: 27 Dec 2016, 00:32
by jeeswg
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!

Code: Select all

if vDir contains #
Loop, %vDir%, 2, 0 ;(0/1/2=files/both/folders, 0/1=recurse no/yes)
vDir := A_LoopFileShortPath

Re: 4 options to change the current folder in Windows Explorer

Posted: 27 Dec 2016, 13:44
by jeeswg
OK, unfortunately still a problem if the folder has a # in the first 6 characters of any of the subfolder names. Is it possible to assign a special folder ID to the folder with the hash, and then put that into Navigate()?

e.g. shell:Desktop

[EDIT:]
Or perhaps IShellBrowser::BrowseObject with a PIDL?

Re: 4 options to change the current folder in Windows Explorer

Posted: 30 Dec 2016, 00:58
by jeeswg
you can navigate from folder 1 to 2 by creating and invoking a lnk file inside folder 1,
if you can't create a lnk in the protected/special folder,
you could navigate to a go-between folder and create the lnk there,
I don't know of a way to check whether the current folder is protected/special or not,
so I could just always use the go-between folder

anyway you've got me hooked on this problem,
I posted some code at the Stack Overflow link

anyway this Navigate instruction, they really made a hash of it

Re: 4 options to change the current folder in Windows Explorer

Posted: 13 Jun 2017, 15:54
by jeeswg
I have what looks to be a working solution for this, which I've also posted here:

windows - Navigate Shell command not working when the path includes an hash - Stack Overflow
https://stackoverflow.com/questions/228 ... es-an-hash

Code: Select all

;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") ;cDims
			NumPut(1, SAFEARRAY, 4, "UInt") ;cbElements
			NumPut(vPIDL, SAFEARRAY, A_PtrSize=8?16:12, "Ptr") ;pvData
			NumPut(DllCall("shell32\ILGetSize", Ptr,vPIDL, UInt), SAFEARRAY, A_PtrSize=8?24:16, "Int") ;rgsabound[1]
			oWin.Navigate2(ComObject(0x2011,&SAFEARRAY))
			DllCall("shell32\ILFree", Ptr,vPIDL)
		}
		break
	}
return

Re: 4 options to change the current folder in Windows Explorer

Posted: 13 Jun 2017, 16:00
by qwerty12
Interesting... Thanks, jeeswg

Re: 4 options to change the current folder in Windows Explorer

Posted: 25 Jul 2017, 08:52
by JnLlnd
Thanks, jeeswg. Sorry, I have not see it before. It works well. Could you explain what shell32\SHParseDisplayName and the following NumPut are doing?

Re: 4 options to change the current folder in Windows Explorer

Posted: 25 Jul 2017, 15:44
by jeeswg
[SHParseDisplayName gets the PIDL for the file:]
SHParseDisplayName function (Windows)
https://msdn.microsoft.com/en-us/librar ... s.85).aspx

[PIDLs:]
Introduction to the Shell Namespace (Windows)
https://msdn.microsoft.com/en-us/librar ... s.85).aspx

[This link suggests that Navigate2 expects a SAFEARRAY:]
Explorer Windows Manipulations - Page 5 - Scripts and Functions - AutoHotkey Community
https://autohotkey.com/board/topic/1903 ... ntry297581

[Navigate2 expects a SAFEARRAY, so we prepare the SAFEARRAY struct:]
SAFEARRAY structure (Automation)
https://msdn.microsoft.com/en-us/librar ... s.85).aspx

Yeah, it's crazy when it just works. Been a long time, this problem. Cheers.