Jump to content

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

Get paths of selected items in an explorer window


  • Please log in to reply
38 replies to this topic
Rapte_Of_Suzaku
  • Members
  • 901 posts
  • Last active: Jul 08 2011 02:12 PM
  • Joined: 29 Feb 2008
Library for getting info from a specific explorer window (if window handle not specified, the currently active window will be used). Requires AHK_L or similar. Works with the desktop. Does not currently work with save dialogs and such.


Explorer_GetSelected(hwnd="") - paths of target window's selected items
Explorer_GetAll(hwnd="") - paths of all items in the target window's folder
Explorer_GetPath(hwnd="") - path of target window's folder

example:
F1::
	path := Explorer_GetPath()
	all := Explorer_GetAll()
	sel := Explorer_GetSelected()
	MsgBox % path
	MsgBox % all
	MsgBox % sel
return
The Library:
/*
	Library for getting info from a specific explorer window (if window handle not specified, the currently active
	window will be used).  Requires AHK_L or similar.  Works with the desktop.  Does not currently work with save
	dialogs and such.
	
	
	Explorer_GetSelected(hwnd="")   - paths of target window's selected items
	Explorer_GetAll(hwnd="")        - paths of all items in the target window's folder
	Explorer_GetPath(hwnd="")       - path of target window's folder
	
	example:
		F1::
			path := Explorer_GetPath()
			all := Explorer_GetAll()
			sel := Explorer_GetSelected()
			MsgBox % path
			MsgBox % all
			MsgBox % sel
		return
	
	Joshua A. Kinnison
	2011-04-27, 16:12
*/

Explorer_GetPath(hwnd="")
{
	if !(window := Explorer_GetWindow(hwnd))
		return ErrorLevel := "ERROR"
	if (window="desktop")
		return A_Desktop
	path := window.LocationURL
	path := RegExReplace(path, "ftp://.*@","ftp://")
	StringReplace, path, path, file:///
	StringReplace, path, path, /, \, All 
	
	; thanks to polyethene
	Loop
		If RegExMatch(path, "i)(?<=%)[\da-f]{1,2}", hex)
			StringReplace, path, path, `%%hex%, % Chr("0x" . hex), All
		Else Break
	return path
}
Explorer_GetAll(hwnd="")
{
	return Explorer_Get(hwnd)
}
Explorer_GetSelected(hwnd="")
{
	return Explorer_Get(hwnd,true)
}

Explorer_GetWindow(hwnd="")
{
	; thanks to jethrow for some pointers here
    WinGet, process, processName, % "ahk_id" hwnd := hwnd? hwnd:WinExist("A")
    WinGetClass class, ahk_id %hwnd%
	
	if (process!="explorer.exe")
		return
	if (class ~= "(Cabinet|Explore)WClass")
	{
		for window in ComObjCreate("Shell.Application").Windows
			if (window.hwnd==hwnd)
				return window
	}
	else if (class ~= "Progman|WorkerW") 
		return "desktop" ; desktop found
}
Explorer_Get(hwnd="",selection=false)
{
	if !(window := Explorer_GetWindow(hwnd))
		return ErrorLevel := "ERROR"
	if (window="desktop")
	{
		ControlGet, hwWindow, HWND,, SysListView321, ahk_class Progman
		if !hwWindow ; #D mode
			ControlGet, hwWindow, HWND,, SysListView321, A
		ControlGet, files, List, % ( selection ? "Selected":"") "Col1",,ahk_id %hwWindow%
		base := SubStr(A_Desktop,0,1)=="\" ? SubStr(A_Desktop,1,-1) : A_Desktop
		Loop, Parse, files, `n, `r
		{
			path := base "\" A_LoopField
			IfExist %path% ; ignore special icons like Computer (at least for now)
				ret .= path "`n"
		}
	}
	else
	{
		if selection
			collection := window.document.SelectedItems
		else
			collection := window.document.Folder.Items
		for item in collection
			ret .= item.path "`n"
	}
	return Trim(ret,"`n")
}

updated version: 2010-12-04, 14:39
fixed bug with ftp paths (2011-04-27, 16:12)

Learning one
  • Members
  • 1483 posts
  • Last active: Jan 02 2016 02:30 PM
  • Joined: 04 Apr 2009
Useful, reliable, easy to use. Thanks.

fragman
  • Members
  • 1591 posts
  • Last active: Nov 12 2012 08:51 PM
  • Joined: 13 Oct 2009
I'm using some similar functions right now. If you intend to keep up with this, I suggest adding functions to select items and set the folder, navigate back/forward/up, refresh the view, start a rename...basically all useful functions that the automation interfaces of Explorer implement. If you want you can look at the source of my program 7plus (see Navigate.ahk) for some ideas, it's not very clean code there though :(

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

target := window, break

You may as well do this:
target := window, this_is_a_variable_and_referencing_it_here_has_no_effect
You can't put a command inside an expression. I'd suggest doing this instead:
for window in ComObjCreate("Shell.Application").Windows
         if (window.hwnd==hwnd)
            return window
Btw, instead of
else
      return ; nothing found
}
you can write
}
to the same effect. That's more a matter of personal taste, though.

I suggest adding [...] basically all useful functions that the automation interfaces of Explorer implement.

Why not just use the automation interfaces of Explorer directly?

Rapte_Of_Suzaku
  • Members
  • 901 posts
  • Last active: Jul 08 2011 02:12 PM
  • Joined: 29 Feb 2008
Thanks for pointing out my ",break" blunder. I've surely done that elsewhere (time to search my library).

As for keeping up with this, I'm more interested in the file/folder manipulation aspects (see my FileContainer). With regards to 7plus, definitely feel free to make use of FileContainer! (see Explorer Selection Hotkeys for how to use it simply)

fragman
  • Members
  • 1591 posts
  • Last active: Nov 12 2012 08:51 PM
  • Joined: 13 Oct 2009

I suggest adding [...] basically all useful functions that the automation interfaces of Explorer implement.

Why not just use the automation interfaces of Explorer directly?


Because I would assume that many users aren't familiar with COM and would rather like to use a library written in AHK.

Rapte_Of_Suzaku: I've considered it, but haven't needed it so far.

pajenn
  • Members
  • 391 posts
  • Last active: Feb 06 2015 07:57 AM
  • Joined: 07 Feb 2009
Interesting and very useful script. I've worked on something similar based off Sean's ShellFolder.ahk and ShellDesktop.ahk functions which require his COM library (and maybe ACC too). My scripts basically just parsed the output using regex and accounted for some exceptions.

The desktop was always the problem and I notice similar problems with this script to what I faced:

1. It uses A_Desktop variable for desktop, which leaves out desktop items that are in other desktop directories. For example, if I select a file on my desktop (Win XP) that's actually in C:\Documents and Settings\All Users\Desktop, the script returns an empty hit.

2. It appears that 'show file extensions' needs to be turned on, including for shortcuts (i.e. on XP, HKEY_CLASSES_ROOT\lnkfile\NeverShowExt needs to be deleted (+reboot) if it exists).

3. Special CLSID folders such as My Computer and Recycle Bin are not retrieved. You could make exceptions for them that return ::{20d04fe0-3aea-1069-a2d8-08002b30309d} and
::{645ff040-5081-101b-9f08-00aa002f954e} as their paths, respectively. (That works, for example, if the user is retrieving the path to run it).

Hardware: fast laptop with SSD
Software: Win 7 Home Premium 64-bit, android for phone and tablet


jack_steel
  • Members
  • 2 posts
  • Last active: Jan 18 2011 04:59 PM
  • Joined: 18 Jan 2011
I get the error

The following variable name contains an illegal character: "window.LocationURL"

when using Explorer_GetPath in Windows 7. Any ideas?

fragman
  • Members
  • 1591 posts
  • Last active: Nov 12 2012 08:51 PM
  • Joined: 13 Oct 2009
You should use Autohotkey_L.

jack_steel
  • Members
  • 2 posts
  • Last active: Jan 18 2011 04:59 PM
  • Joined: 18 Jan 2011
Oh... I've never heard about it :shock:
Will have a look at the website to understand the difference...

stevel
  • Members
  • 133 posts
  • Last active: Nov 15 2013 12:32 AM
  • Joined: 12 Oct 2010
For those using AHK basic, there is a very simple technique I have been using for a long time now. I use it so frequently that I assigned it a hotkey. It is simply copying any selected file, group of files, or folder in Explorer or any other file manager (it also works in save dialog boxes) and then setting a variable to clipboard contents. You may have to use a clipwait to make sure the copy has occurred. Example:
clipboardSaved := clipboard

clipboard =

WinActivate,, FolderView

Send ^c

clipwait

contents = %clipboard%

clipboard := clipboardSaved

clipboardSaved =


20110123
  • Guests
  • Last active:
  • Joined: --

For those using AHK basic, there is a very simple technique I have been using for a long time now. I use it so frequently that I assigned it a hotkey. It is simply copying any selected file, group of files, or folder in Explorer or any other file manager (it also works in save dialog boxes) and then setting a variable to clipboard contents. You may have to use a clipwait to make sure the copy has occurred. Example:

clipboardSaved := clipboard
clipboard =
WinActive,, FolderView
Send ^c
clipwait
contents = %clipboard%
clipboard := clipboardSaved
clipboardSaved =


That won't work as copying a file copies the whole file, not it's name (unless you double clicked to edit the name already). Also "WinActive" should be "WinActivate". Why not use

ControlGet, selectedFiles, List, selected, SysListView321, A

You can still clipboard = %selectedFiles% if you need to. Use parsing loops to get individual filenames.

To get the whole paths add the filenames onto the result of either of these:

ControlGetText, ExplorePath, Edit1, A
ControlGetText, ExplorePath, ToolbarWindow323, A


stevel
  • Members
  • 133 posts
  • Last active: Nov 15 2013 12:32 AM
  • Joined: 12 Oct 2010
Actually, it works perfectly.

I have been using it now for several years now -- and even assigned it a hotkey since I use it so much. Yes, the file is 'copied' (really just a reference to the file), however since you are only extracting the text path when you use '%clipboard%' that is all you get.

As for copying a list of file names, I left out the simple use of parsing or even StringSplit because I thought that technique was obvious. Try it out, you will see what I mean.

Also, using the alternative code presented above, adds unreliability to the technique. First, there is an explorer option to not show the full path that may have been set. Second, the technique works in every file manager I have tried it in, including 'Everything' (I use it in Everything, Q-Dir, and Explorer). There is no need to try to locate a path separately -- an item that might not be available.

tomoe_uehara
  • Members
  • 2166 posts
  • Last active: Jun 11 2015 05:33 PM
  • Joined: 05 Sep 2009

Requires AHK_L or similar.

Request: A script like this for AHK Basic :O

a4u
  • Guests
  • Last active:
  • Joined: --
:!: NOTE - in this code, the RED line is causing explorer.exe to crash if running 32-bit AHK on a 64-bit system.

Request: A script like this for AHK Basic :O

I'd request folks update to AHK_L ;), but here's a Basic version (requires COM Standard Library):
Explorer_GetPath(hwnd="")
{
   Com_Init()
   if !(window := Explorer_GetWindow(hwnd))
      return, ErrorLevel := "ERROR", Com_Term()
   if (window="desktop")
      return, A_Desktop, Com_Term()
   path := Com_Invoke(window, "LocationURL")
   Com_Release(window), Com_Term()
   path := SubStr(path,InStr(path,"///")+3)
   StringReplace, path, path, /, \, All 
   
   ; thanks to polyethene
   Loop
      If RegExMatch(path, "i)(?<=%)[\da-f]{1,2}", hex)
         StringReplace, path, path, `%%hex%, % Chr("0x" . hex), All
      Else Break
   return path
}
Explorer_GetAll(hwnd="")
{
   Com_Init()
   return, Explorer_Get(hwnd), Com_Term()
}
Explorer_GetSelected(hwnd="")
{
   Com_Init()
   return, Explorer_Get(hwnd,true), Com_Term()
}

Explorer_GetWindow(hwnd="")
{
   ; thanks to jethrow for some pointers here
   WinGet, process, processName, % "ahk_id" hwnd := hwnd ? hwnd:WinExist("A")
   WinGetClass class, ahk_id %hwnd%
   
   if (process!="explorer.exe")
      return
   if RegExMatch(class, "(Cabinet|Explore)WClass")
   {
      shell := Com_CreateObject("Shell.Application")
      windows := Com_Invoke(shell, "Windows")
      Com_Release(shell)
      Loop, % Com_Invoke(windows,"Count") {
         window := Com_Invoke(windows, "item", A_Index-1)
         if (Com_Invoke(window, "hwnd")==hwnd)
            return, window, Com_Release(windows)
         Com_Release(window)
      }
      Com_Release(windows), Com_Release(window)
   }
   else if RegExMatch(class, "Progman|WorkerW") 
      return "desktop" ; desktop found
}
Explorer_Get(hwnd="",selection=false)
{
   if !(window := Explorer_GetWindow(hwnd))
      return ErrorLevel := "ERROR"
   if (window="desktop")
   {
      ControlGet, hwWindow, HWND,, SysListView321, ahk_class Progman
      if !hwWindow ; #D mode
         ControlGet, hwWindow, HWND,, SysListView321, A
      [color=red]ControlGet, files, List, % ( selection ? "Selected":"") "Col1",,ahk_id %hwWindow%[/color]
      base := SubStr(A_Desktop,0,1)=="" ? SubStr(A_Desktop,1,-1) : A_Desktop
      Loop, Parse, files, `n, `r
      {
         path := base "" A_LoopField
         IfExist %path% ; ignore special icons like Computer (at least for now)
            ret .= path "`n"
      }
   }
   else
   {
		if selection
			collection := Com_Invoke(window, "document.SelectedItems")
		else
			collection := Com_Invoke(window, "document.Folder.Items")
		Com_Release(window)
		Loop, % Com_Invoke(collection, "Count")
			ret .= Com_Invoke(collection, "item[" A_Index-1 "].path") "`n"
		Com_Release(collection)
   }
   return, SubStr(ret,1,-1)
}