Jump to content



Photo

Windows Explorer current folder


  • Please log in to reply
50 replies to this topic

#1 WideBoyDixon

WideBoyDixon

    Code Monkey

  • Active Members
  • PipPipPipPipPipPip
  • 381 posts

Posted 18 February 2009 - 12:22 AM

I needed to be able to retrieve the folder currently being explored by an instance of Windows Explorer. To that end, I had to write a function to do this which I've copied out below. Feel free to re-use this if you find it useful.

AutoIt         
#include-once ; ================================================================================================== ; <_GetWindowsExplorerPath.au3> ; ; Functions: ;   _GetWindowsExplorerPath() ;   _GetWindowsExplorerPaths() ; ; Author: WideBoyDixon ; ================================================================================================== ; ================================================================================================== ; Func _GetWindowsExplorerPath($hWnd) ; ; Function to get the path currently being explored by a Windows Explorer window ; ; $hWnd = Handle to the Windows Explorer window ; ; Returns: ;   Success: String - Path being explored by this window ;   Failure: "" empty string, with @error set: ;      @error = 1 = This is not a valid explorer window ;      @error = 2 = DLL call error, use _WinAPI_GetLastError() ; ; Author: WideBoyDixon ; ================================================================================================== Func _GetWindowsExplorerPath($hWnd)     Local $pv, $pidl, $return = "", $ret, $hMem, $pid, $folderPath = DllStructCreate("char[260]"), $className     Local $bPIDL = False     Local Const $CWM_GETPATH = 0x400 + 12;     ; Check the classname of the window first     $className = DllCall("user32.dll", "int", "GetClassName", "hwnd", $hWnd, "str", "", "int", 4096)     If @error Then Return SetError(2, 0, "")     If ($className[2] <> "ExploreWClass" And $className[2] <> "CabinetWClass") Then Return SetError(1, 0, "")         ; Retrieve the process ID for our process     $pid = DllCall("kernel32.dll", "int", "GetCurrentProcessId")     If @error Then Return SetError(2, 0, "")     ; Send the CWM_GETPATH message to the window     $hMem = DllCall("user32.dll", "lparam", "SendMessage", "hwnd", $hWnd, "int", $CWM_GETPATH, "wparam", $pid[0], "lparam", 0)     If @error Then Return SetError(2, 0, "")     If $hMem[0] = 0 Then Return SetError(1, 0, "")         ; Lock the shared memory     $pv = DllCall("shell32.dll", "ptr", "SHLockShared", "uint", $hMem[0], "uint", $pid[0])     If @error Then Return SetError(2, 0, "")     If $pv[0] Then         $pidl = DllCall("shell32.dll", "ptr", "ILClone", "uint", $pv[0]) ; Clone the PIDL         If @error Then Return SetError(2, 0, "")         $bPIDL = True         DllCall("shell32.dll", "int", "SHUnlockShared", "uint", $pv) ; Unlock the shared memory     EndIf     DllCall("shell32.dll", "int", "SHFreeShared", "uint", $hMem, "uint", $pid) ; Free the shared memory         If $bPIDL Then         ; Retrieve the path from the PIDL         $ret = DllCall("shell32.dll", "int", "SHGetPathFromIDList", "ptr", $pidl[0], "ptr", DllStructGetPtr($folderPath))         If (@error = 0) And ($ret[0] <> 0) Then $return = DllStructGetData($folderPath, 1) ; Retrieve the value         DllCall("shell32.dll", "none", "ILFree", "ptr", $pidl[0]) ; Free up the PIDL that we cloned         Return SetError(0, 0, $return) ; Success     EndIf         Return SetError(2, 0, "") ; Failed a WinAPI call EndFunc ; ================================================================================================== ; Func _GetWindowsExplorerPaths() ; ; Function to get a list of all paths currently being explored by a Windows Explorer window ; ; Returns: ;   Array ;       [0][0] - Number of items in the Array ;       [$i][0] - Window handle of the explorer window ;       [$i][1] - Folder being explored by this window ; ; Author: WideBoyDixon ; ================================================================================================== Func _GetWindowsExplorerPaths()     Local $nCount = 0 ; The number of explorer windows we found     Local $aPaths[1][2] ; Our return array     Local $aWindows = WinList() ; Look at all the windows we can find     Local $nI, $folderPath ; Loop variable and folder path string     ; Loop through all windows     For $nI = 1 To $aWindows[0][0]         ; Try to get the folder path for this window         $folderPath = _GetWindowsExplorerPath($aWindows[$nI][1])         If @error = 0 Then             ; Found the path ... store it             $nCount += 1 ; Increment the number of windows we've found             ReDim $aPaths[$nCount + 1][2] ; Make room for this one in the array             $aPaths[$nCount][0] = $aWindows[$nI][1] ; Store the window handle             $aPaths[$nCount][1] = $folderPath ; Store the path that's being explored             $aPaths[0][0] = $nCount ; Update the number of items in the array         EndIf     Next     Return $aPaths EndFunc


Regards,

WBD

Edited by WideBoyDixon, 18 February 2009 - 12:23 AM.








#2 KaFu

KaFu

    Hey, it's just me, KhaFoo...

  • MVPs
  • 3,166 posts

Posted 18 February 2009 - 07:39 AM

Nice example, will sure come handy at some point :).

$var = WinList("[CLASS:ExploreWClass;]") for $i = 1 to $var[0][0]     ConsoleWrite(_GetWindowsExplorerPath($var[$i][1]) & @crlf) Next


Cheers

#3 dmob

dmob

    Prodigy

  • Active Members
  • PipPipPip
  • 191 posts

Posted 18 February 2009 - 09:17 AM

Would this work for a FileOpen Dialog? If not, can it be adapted?

I thought I might be able to use something like this to tackle a
problem I have, how to detect uploads from Firefox.

#4 WideBoyDixon

WideBoyDixon

    Code Monkey

  • Active Members
  • PipPipPipPipPipPip
  • 381 posts

Posted 18 February 2009 - 12:04 PM

Would this work for a FileOpen Dialog? If not, can it be adapted?

Unfortunately, "No" and "No". In order to get the current folder in a FileOpen dialog you need to delve in to the depths of IShellBrowser and other shell interfaces and I'm not sure AutoIt can do that without creating an external DLL. The basics are:

[1] Use SendMessage to the dialog using WM_GETISHELLBROWSER (=WM_USER + 7) to get a pointer to an IShellBrowser
[2] Use the QueryActiveShellView method of IShellBrowser to get the active shell view which is a pointer to an IShellView
[3] Use the QueryInterface method of the IShellView to get a handle to a folder view IFolderView
[4] Use the GetFolder method of the IFolderView to get a handle to IPersistFolder2
[5] Call GetCurFolder on the IPersistFolder2 to get a PIDL for the current folder
[6] Call SHGetPathFromIDList to get the path from the PIDL
[7] Call CoTaskMemFree to free up the PIDL

The C++ code would look something like this:

Plain Text         
bool ShellViewGetCurrentFolder(HWND hwnd, LPTSTR path) {     path[0] = 0;     IShellBrowser *psb = (IShellBrowser*) ::SendMessage( hwnd, WM_GETISHELLBROWSER, 0, 0 );     if (!psb)         return false;             CComPtr<IShellView> psv;     if (FAILED(psb->QueryActiveShellView(&psv)))         return false;             CComPtr<IFolderView> pfv;     if (FAILED(psv->QueryInterface(IID_IFolderView, (void**)&pfv)))         return false;               CComPtr<IPersistFolder2> ppf2;     if (FAILED(pfv->GetFolder(IID_IPersistFolder2, (void**)&ppf2)))         return false;             LPITEMIDLIST pidlFolder;     if (SUCCEEDED(ppf2->GetCurFolder(&pidlFolder)))     {         bool res = false;         if (::SHGetPathFromIDList(pidlFolder, path))             res = true;         ::CoTaskMemFree(pidlFolder);         return res;     }         return false; }

Hope this helps.

WBD

#5 dmob

dmob

    Prodigy

  • Active Members
  • PipPipPip
  • 191 posts

Posted 19 February 2009 - 08:20 AM

Thank you for your reply... too complicated for a noob like me.

#6 BrettF

BrettF

    My Drunk Monkey Guerilla is gonna getcha!

  • MVPs
  • 7,662 posts

Posted 19 February 2009 - 08:36 AM

Very nice!

@Kafu- you example didn't seem to work for me?

I can see this comming in useful with an up and comming project...

Just some issues at the moment.

Using this code:
$aWindow = _GetWindowsExplorerPaths() For $i = 1 To $aWindow[0][0]     MsgBox(0, $i, "HWND = " & $aWindow[$i][0] & @CRLF & _             "Folder = " & $aWindow[$i][1]) Next


With 2 explorer windows open (one is My Computer and the other is D:\My Documents), it doesn't display anything as the folder for My Computer. Any idea why?

Cheers,

Brett

#7 KaFu

KaFu

    Hey, it's just me, KhaFoo...

  • MVPs
  • 3,166 posts

Posted 19 February 2009 - 09:16 AM

@Kafu- you example didn't seem to work for me?


Strange, just rechecked posted code and it works for me (this is even another machine then i wrote the example on), writes info to console as intended.

Just realized what you mentioned, if the "file focus" of an explorer is set on "My Computer" it doesn't return anything. But that's okay, because "My Computer" isn't a location in the file-system :).

#8 BrettF

BrettF

    My Drunk Monkey Guerilla is gonna getcha!

  • MVPs
  • 7,662 posts

Posted 19 February 2009 - 09:21 AM

Strange.. This works for me... :)

$var = WinList("[CLASS:CabinetWClass;]") for $i = 1 to $var[0][0]     MsgBox (0, "", _GetWindowsExplorerPath($var[$i][1])) Next


#9 Digisoul

Digisoul

    Universalist

  • Active Members
  • PipPipPipPipPipPip
  • 312 posts

Posted 19 February 2009 - 07:28 PM

I needed to be able to retrieve the folder currently being explored by an instance of Windows Explorer. To that end, I had to write a function to do this which I've copied out below. Feel free to re-use this if you find it useful.

AutoIt         
#include-once ; ================================================================================================== ; <_GetWindowsExplorerPath.au3> ; ; Functions: ;   _GetWindowsExplorerPath() ;   _GetWindowsExplorerPaths() ; ; Author: WideBoyDixon ; ================================================================================================== ; ================================================================================================== ; Func _GetWindowsExplorerPath($hWnd) ; ; Function to get the path currently being explored by a Windows Explorer window ; ; $hWnd = Handle to the Windows Explorer window ; ; Returns: ;   Success: String - Path being explored by this window ;   Failure: "" empty string, with @error set: ;      @error = 1 = This is not a valid explorer window ;      @error = 2 = DLL call error, use _WinAPI_GetLastError() ; ; Author: WideBoyDixon ; ================================================================================================== Func _GetWindowsExplorerPath($hWnd)     Local $pv, $pidl, $return = "", $ret, $hMem, $pid, $folderPath = DllStructCreate("char[260]"), $className     Local $bPIDL = False     Local Const $CWM_GETPATH = 0x400 + 12;     ; Check the classname of the window first     $className = DllCall("user32.dll", "int", "GetClassName", "hwnd", $hWnd, "str", "", "int", 4096)     If @error Then Return SetError(2, 0, "")     If ($className[2] <> "ExploreWClass" And $className[2] <> "CabinetWClass") Then Return SetError(1, 0, "")         ; Retrieve the process ID for our process     $pid = DllCall("kernel32.dll", "int", "GetCurrentProcessId")     If @error Then Return SetError(2, 0, "")     ; Send the CWM_GETPATH message to the window     $hMem = DllCall("user32.dll", "lparam", "SendMessage", "hwnd", $hWnd, "int", $CWM_GETPATH, "wparam", $pid[0], "lparam", 0)     If @error Then Return SetError(2, 0, "")     If $hMem[0] = 0 Then Return SetError(1, 0, "")         ; Lock the shared memory     $pv = DllCall("shell32.dll", "ptr", "SHLockShared", "uint", $hMem[0], "uint", $pid[0])     If @error Then Return SetError(2, 0, "")     If $pv[0] Then         $pidl = DllCall("shell32.dll", "ptr", "ILClone", "uint", $pv[0]) ; Clone the PIDL         If @error Then Return SetError(2, 0, "")         $bPIDL = True         DllCall("shell32.dll", "int", "SHUnlockShared", "uint", $pv) ; Unlock the shared memory     EndIf     DllCall("shell32.dll", "int", "SHFreeShared", "uint", $hMem, "uint", $pid) ; Free the shared memory         If $bPIDL Then         ; Retrieve the path from the PIDL         $ret = DllCall("shell32.dll", "int", "SHGetPathFromIDList", "ptr", $pidl[0], "ptr", DllStructGetPtr($folderPath))         If (@error = 0) And ($ret[0] <> 0) Then $return = DllStructGetData($folderPath, 1) ; Retrieve the value         DllCall("shell32.dll", "none", "ILFree", "ptr", $pidl[0]) ; Free up the PIDL that we cloned         Return SetError(0, 0, $return) ; Success     EndIf         Return SetError(2, 0, "") ; Failed a WinAPI call EndFunc ; ================================================================================================== ; Func _GetWindowsExplorerPaths() ; ; Function to get a list of all paths currently being explored by a Windows Explorer window ; ; Returns: ;   Array ;       [0][0] - Number of items in the Array ;       [$i][0] - Window handle of the explorer window ;       [$i][1] - Folder being explored by this window ; ; Author: WideBoyDixon ; ================================================================================================== Func _GetWindowsExplorerPaths()     Local $nCount = 0 ; The number of explorer windows we found     Local $aPaths[1][2] ; Our return array     Local $aWindows = WinList() ; Look at all the windows we can find     Local $nI, $folderPath ; Loop variable and folder path string     ; Loop through all windows     For $nI = 1 To $aWindows[0][0]         ; Try to get the folder path for this window         $folderPath = _GetWindowsExplorerPath($aWindows[$nI][1])         If @error = 0 Then             ; Found the path ... store it             $nCount += 1 ; Increment the number of windows we've found             ReDim $aPaths[$nCount + 1][2] ; Make room for this one in the array             $aPaths[$nCount][0] = $aWindows[$nI][1] ; Store the window handle             $aPaths[$nCount][1] = $folderPath ; Store the path that's being explored             $aPaths[0][0] = $nCount ; Update the number of items in the array         EndIf     Next     Return $aPaths EndFunc

Regards,

WBD

Thats really awesome script. i want to know 1 more thing, isn't it possible to get the currently selected file in explorer?
73 108 111 118 101 65 117 116 111 105 116 Posted Image

#10 WideBoyDixon

WideBoyDixon

    Code Monkey

  • Active Members
  • PipPipPipPipPipPip
  • 381 posts

Posted 19 February 2009 - 09:49 PM

Thats really awesome script. i want to know 1 more thing, isn't it possible to get the currently selected file in explorer?


Technically it's possible but of course there might be more than one selected file (or there might be zero). Again you'd have to delve deep in to the Shell32.dll functions and I think the one you'd need is SHShellFolderView_Message along with SFVM_GETSELECTEDOBJECTS

I'm not sure quite how to program an array of PIDLs in AutoIt so I'm going to shy away from this one for now.

WBD

#11 wraithdu

wraithdu

    I am less fun than a twisted ankle.

  • MVPs
  • 2,137 posts

Posted 20 February 2009 - 04:32 AM

@Digisoul

Explorer is just a listview control. Look at the _GuiCtrlListView_*** functions to do what you need.

#12 Digisoul

Digisoul

    Universalist

  • Active Members
  • PipPipPipPipPipPip
  • 312 posts

Posted 20 February 2009 - 09:26 AM

@Digisoul

Explorer is just a listview control. Look at the _GuiCtrlListView_*** functions to do what you need.


Ya i know but it never work well,

main problems

1. you have to find the file with,
2. if the file has same name & but different extensions, you cant decide it correctly.
73 108 111 118 101 65 117 116 111 105 116 Posted Image

#13 picea892

picea892

    Universalist

  • Active Members
  • PipPipPipPipPipPip
  • 689 posts

Posted 26 February 2009 - 05:28 PM

Hi
Maybe I'm missing something, but I think there is an easier way to get this information. I use this method to get the current folder and selected file. Once obtained, this information is used to edit the file differently based on the type. Hope the below is clear. It is a function of a much larger script.

HotKeySet("^q", "quickview")
func quickview()
if WinActive("[CLASS:ExploreWClass]","") Then
$sSelected_Path = ControlGetText("[CLASS:ExploreWClass]", "", "Edit1")
$CLVItem = ControlListView("[CLASS:ExploreWClass]", "", "[CLASS:SysListView32; INSTANCE:1]", "GetSelected")
$Item = ControlListView("[CLASS:ExploreWClass]", "", "[CLASS:SysListView32; INSTANCE:1]", "GetText", $CLVItem)
$Item2=StringRight($Item,3)
if $Item2="au3" Then
ShellExecute("F:\applications\autoit\install\SciTe\SciTE.exe", $sSelected_Path & "\" & $Item)
ElseIf $Item2="vbs" or $Item2="hta" or $Item2="bat" Then
ShellExecute("C:\Mshell\programs\notepad2.exe", $sSelected_Path & "\" & $Item)
EndIf
ElseIf WinActive("[CLASS:CabinetWClass]","") Then
$sSelected_Path = ControlGetText("[CLASS:CabinetWClass]", "", "Edit1")
$CLVItem = ControlListView("[CLASS:CabinetWClass]", "", "[CLASS:SysListView32; INSTANCE:1]", "GetSelected")
$Item = ControlListView("[CLASS:CabinetWClass]", "", "[CLASS:SysListView32; INSTANCE:1]", "GetText", $CLVItem)
$Item2=StringRight($Item,3)
if $Item2="au3" Then
ShellExecute("F:\applications\autoit\install\SciTe\SciTE.exe", $sSelected_Path & "\" & $Item)
ElseIf $Item2="vbs" or $Item2="hta" or $Item2="bat" Then
ShellExecute("C:\Mshell\programs\notepad2.exe", $sSelected_Path & "\" & $Item)
EndIf
else
SEND("!q")
EndIf
EndFunc

#14 WideBoyDixon

WideBoyDixon

    Code Monkey

  • Active Members
  • PipPipPipPipPipPip
  • 381 posts

Posted 26 February 2009 - 10:39 PM

It doesn't work if you have the address bar hidden. That's the kicker.

WBD

#15 TheSaint

TheSaint

    *** Knight Templar ***

  • MVPs
  • 4,022 posts

Posted 27 February 2009 - 06:58 PM

It doesn't work if you have the address bar hidden. That's the kicker.

WBD

An issue I had to try and deal with in my New Folders and Context Options programs.

Make sure brain is in gear before opening mouth! Ignoring those who try to divert conversation with irrelevancies. If I put effort into communication, I expect you to read properly & fully, or just not comment. If I'm intent on insulting you or being rude, I will be obvious, not ambiguous about it. I'm only big and bad, to those who have an over-active imagination. I may have the Artistic Liesense to disagree with you. TheSaint's Toolbox


#16 wraithdu

wraithdu

    I am less fun than a twisted ankle.

  • MVPs
  • 2,137 posts

Posted 27 February 2009 - 07:15 PM

@TheSaint
What was your solution? Especially since this topic's method doesn't work in Vista, SendMessage() returns 0.

#17 TheSaint

TheSaint

    *** Knight Templar ***

  • MVPs
  • 4,022 posts

Posted 27 February 2009 - 07:54 PM

@TheSaint
What was your solution? Especially since this topic's method doesn't work in Vista, SendMessage() returns 0.

Someone just had to ask that ... now I have to go and work out what I did ... I had to say something didn't I ... and I'm not even 100% sure I did solve it? I remember my Open Projects program also giving me some grief, because the Drive windows opened by TrueCrypt didn't always display a drive letter in the address bar ... but I do remember solving that somehow. Have you or anyone else tried my New Folders program in Vista ... especially without the address bar being active ... I don't have easy access to Vista at this point?

Make sure brain is in gear before opening mouth! Ignoring those who try to divert conversation with irrelevancies. If I put effort into communication, I expect you to read properly & fully, or just not comment. If I'm intent on insulting you or being rude, I will be obvious, not ambiguous about it. I'm only big and bad, to those who have an over-active imagination. I may have the Artistic Liesense to disagree with you. TheSaint's Toolbox


#18 WideBoyDixon

WideBoyDixon

    Code Monkey

  • Active Members
  • PipPipPipPipPipPip
  • 381 posts

Posted 27 February 2009 - 11:43 PM

In the Hot Folders script I dealt with this using the following:

; Force address bar to be visible so that we can get the handle to the edit control _SendMessage($hwndActive, $WM_COMMAND, 41477, 0)


Perhaps that would work for you too?

WBD

Edited by WideBoyDixon, 27 February 2009 - 11:44 PM.


#19 cvocvo

cvocvo

    Seeker

  • Active Members
  • 43 posts

Posted 19 July 2010 - 02:21 AM

Has anyone succeeded in getting this script to work in Windows Vista or 7? I don't understand why it wouldn't work in 7 -- the class for an explorer window is still CabinetWClass.

Any suggestions that might help get this working?

#20 KaFu

KaFu

    Hey, it's just me, KhaFoo...

  • MVPs
  • 3,166 posts

Posted 19 July 2010 - 06:09 AM

This works for me on Win7...
MsgBox(0, "", _GetWindowsExplorerPath("[CLASS:CabinetWClass]")) Func _GetWindowsExplorerPath($hWnd)     If @OSVersion = "WIN_7" Then Return WinGetTitle($hWnd,"") EndFunc   ;==>_GetWindowsExplorerPath

Just add the line If @OSVersion... below the Return SetError(1, 0, "") line of the original function.




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users