Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Get the current path of a Window Explorer


  • Please log in to reply
21 replies to this topic
PhiLho
  • Moderators
  • 6850 posts
  • Last active: Jan 02 2012 10:09 PM
  • Joined: 27 Dec 2005
It may look as old news, since there is a "classical" way to get this path, a method I used in my programs: get the path from the address bar.
WinGetClass explorerClass, A
ControlGetText currentPath, Edit1, ahk_class %explorerClass%
But Tekl pointed out some limitations of this method and gave a link to an article explaining how to use unofficial WinAPI functions to get this information.

Warning: This doesn't work on Windows 2000! That's the problem with unofficial API functions, Microsoft doesn't document them (by definition) and doesn't need to support them. It may fail on Windows Vista as well...

Anyway, I translated the given code sample to DllCalls, and here is the result:
GetWindowsExplorerPath(_hWnd)
{
	local pid, hMem, pv, pidl, pidl?, explorerPath

	If (A_OSType = "WIN32_NT")
	{
		pid := DllCall("GetCurrentProcessId")
		SendMessage 0x400 + 12	; CWM_GETPATH = WM_USER + 12
				, pid, 0, , ahk_id %_hWnd%
		hMem := ErrorLevel
		if (hMem != 0)
		{
			pv := DllCall("Shell32\SHLockShared"
				, "UInt", hMem, "UInt", pid)
			if (pv != 0)
			{
				pidl := DllCall("Shell32\ILClone", "UInt", pv)
				DllCall("Shell32\SHUnlockShared", "UInt", pv)
			}
			DllCall("Shell32\SHFreeShared"
				, "UInt", hMem, "UInt", pid)
		}
	}
	Else	; Win9x
	{
		SendMessage 0x400 + 12	; CWM_GETPATH = WM_USER + 12
				, 0, 0, , ahk_id %_hWnd%
		pidl? := ErrorLevel
		if (pidl? != 0)
		{
			pidl := DllCall("Shell32\ILClone", "UInt", pidl?)
			DllCall("Shell32\ILGlobalFree", "UInt", pidl?)
		}
	}
	VarSetCapacity(explorerPath, 512, 0)
	DllCall("Shell32\SHGetPathFromIDList"
		, "UInt", pidl, "Str", explorerPath)
	Return explorerPath
}

;-- Example of use

hWnd := WinExist("A")
WinGetClass wClass, ahk_id %hWnd%
If (wClass != "ExploreWClass" and wClass != "CabinetWClass")
	MsgBox Use this only with a Windows Explorer window!
Else
	MsgBox % GetWindowsExplorerPath(hWnd)
I have not yet tested on Win9x.
Posted Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")

Tekl
  • Members
  • 814 posts
  • Last active: May 03 2009 03:28 PM
  • Joined: 24 Sep 2004
Thanks PhiLho,

that's great. I'll make more depper test it in the next days.
Tekl

Tekl
  • Members
  • 814 posts
  • Last active: May 03 2009 03:28 PM
  • Joined: 24 Sep 2004
Btw. does it also work with SetPath?
Tekl

PhiLho
  • Moderators
  • 6850 posts
  • Last active: Jan 02 2012 10:09 PM
  • Joined: 27 Dec 2005
Argh, I was waiting for this question...
I started to code it (it can be useful, eg. when you create a new folder), then dropped it (nobody asked for it).
One reason for dropping it is the method to transform a path to a LPCITEMIDLIST, using SHParseDisplayName. The path must be a wide string (ie. Unicode), which isn't easy to get with AHK. I can make a crude mock wide string (alternating Ascii codes with zeroes), but I was lazy to do it... :-)
Posted Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")

robiandi
  • Guests
  • Last active:
  • Joined: --
But in Win2000 the above function is equivalent to
msgbox %path%


PhiLho
  • Moderators
  • 6850 posts
  • Last active: Jan 02 2012 10:09 PM
  • Joined: 27 Dec 2005
Which "above function"?
Did you tested your code? On XP, and probably on Win9x, this displays the PATH environment variable, which is the list of directories where to search the executable to run (or the DLL to load) when you type its name on the command line.
Posted Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")

Tekl
  • Members
  • 814 posts
  • Last active: May 03 2009 03:28 PM
  • Joined: 24 Sep 2004
Hi PhiLho,

isn't there an ANSI-equivalent of that function? Does it only support utf-16 or also utf-8? But I think you know, that AHK has Transform, Unicode.
Tekl

robiandi
  • Guests
  • Last active:
  • Joined: --
@PhiLho: The "above function" ist GetWindowsExplorerPath(_hWnd)
Your script in the posting of Mon Jun 05, 2006 4:42 pm
returns in my situation (Win2000) only the PATH environment variable (for every active window)
and not the path of the active Windows explorer window

Tekl
  • Members
  • 814 posts
  • Last active: May 03 2009 03:28 PM
  • Joined: 24 Sep 2004
Hi,

maybe it helps using #NoEnv in the script-header.
Tekl

robiandi
  • Guests
  • Last active:
  • Joined: --
@Tekl:

maybe it helps using #NoEnv in the script-header.

I tried ist. In this case the result of GetWindowsExplorerPath(_hWnd) is empty.
(Win2000)

PhiLho
  • Moderators
  • 6850 posts
  • Last active: Jan 02 2012 10:09 PM
  • Joined: 27 Dec 2005
@robiandi: OK, I think I understand. I changed the path variable to explorerPath, to avoid potential collision.
If it doesn't work in Win2k, this may be because it uses unofficial WinAPI functions, ie. functions found in system DLLs but not documented by Microsoft, ie. for internal use only. Since they are not official, MS is free to change or remove them whenever they feel like it... Perhaps one of them (or all) is absent in Win2k, or perhaps the CWM_GETPATH isn't supported.
You can add: el = %el% %ErrorLevel% after each DllCall and display el at the end, to see if there is any -4 value.
Posted Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")

robiandi
  • Guests
  • Last active:
  • Joined: --
@PhiLho: I added el = %el% %ErrorLevel% after each DllCall and got: 0 -4 -4 -4 -4 0

I think this means: "firemission over"

PhiLho
  • Moderators
  • 6850 posts
  • Last active: Jan 02 2012 10:09 PM
  • Joined: 27 Dec 2005
Aw, too bad! That's the problem with unofficial API.
Thank you for testing. Can you be so kind to test the Win9x part, please? I doubt it works, since Win2k has probably protected memory like NT, but who know?
Otherwise, one should add a test to exclude WIN_2000 (and WIN_2003?) from this code and rely on the Edit1 method.
Posted Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")

robiandi
  • Guests
  • Last active:
  • Joined: --
I tested the Win9x part and got: 0

but the function returns an empty string.

PhiLho
  • Moderators
  • 6850 posts
  • Last active: Jan 02 2012 10:09 PM
  • Joined: 27 Dec 2005
That's logical, perhaps the message isn't supported, and anyway, if memory is protected, AHK cannot read it (or we may need to use ReadProcessMemory as shimanov shown, but I don't master this technique).
Thanks for reporting.
Posted Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")