How to retrieve full path of currently opened folder?

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: How to retrieve full path of currently opened folder?

20 Aug 2020, 06:01

It shows the same size units that are shown in details->size property.
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: How to retrieve full path of currently opened folder?

20 Aug 2020, 11:46

With bytes counting it can be done with UWP.
Very dirty example of getting first subfolders sizes of removable storage.
Too lazy to clean it :)

Code: Select all

CreateClass("Windows.Storage.KnownFolders", IKnownFoldersStatics := "{5A2A7520-4802-452D-9AD9-4351ADA7EC35}", KnownFoldersStatics)
DllCall(NumGet(NumGet(KnownFoldersStatics+0)+11*A_PtrSize), "ptr", KnownFoldersStatics, "ptr*", externalDevices)   ; get_RemovableDevices
DllCall(NumGet(NumGet(externalDevices+0)+14*A_PtrSize), "ptr", externalDevices, "ptr*", StorageFolderReadOnlyList)   ; GetFoldersAsyncOverloadDefaultOptionsStartAndCount
WaitForAsync(StorageFolderReadOnlyList)
DllCall(NumGet(NumGet(StorageFolderReadOnlyList+0)+7*A_PtrSize), "ptr", StorageFolderReadOnlyList, "int*", count)   ; count
loop % count
{
   DllCall(NumGet(NumGet(StorageFolderReadOnlyList+0)+6*A_PtrSize), "ptr", StorageFolderReadOnlyList, "int", A_Index-1, "ptr*", StorageFolder)   ; get_Item
   DllCall(NumGet(NumGet(StorageFolder+0)+14*A_PtrSize), "ptr", StorageFolder, "ptr*", StorageFolderReadOnlyList%A_Index%)   ; GetFoldersAsyncOverloadDefaultOptionsStartAndCount
   WaitForAsync(StorageFolderReadOnlyList%A_Index%)
   DllCall(NumGet(NumGet(StorageFolderReadOnlyList%count%+0)+7*A_PtrSize), "ptr", StorageFolderReadOnlyList%count%, "int*", count1)   ; count
   loop % count1
   {
      DllCall(NumGet(NumGet(StorageFolderReadOnlyList%count%+0)+6*A_PtrSize), "ptr", StorageFolderReadOnlyList%count%, "int", A_Index-1, "ptr*", StorageFolder%count%)   ; get_Item
      StorageItem := ComObjQuery(StorageFolder%count%, IStorageItem := "{4207A996-CA2F-42F7-BDE8-8B10457A7F30}")
      DllCall(NumGet(NumGet(StorageItem+0)+10*A_PtrSize), "ptr", StorageItem, "ptr*", BasicProperties)   ; GetBasicPropertiesAsync
      WaitForAsync(BasicProperties)
      DllCall(NumGet(NumGet(BasicProperties+0)+6*A_PtrSize), "ptr", BasicProperties, "uint64*", size)   ; get_Size
      msgbox % size
   }
}

CreateClass(string, interface, ByRef Class)
{
   CreateHString(string, hString)
   VarSetCapacity(GUID, 16)
   DllCall("ole32\CLSIDFromString", "wstr", interface, "ptr", &GUID)
   result := DllCall("Combase.dll\RoGetActivationFactory", "ptr", hString, "ptr", &GUID, "ptr*", Class, "uint")
   if (result != 0)
   {
      if (result = 0x80004002)
         msgbox No such interface supported
      else if (result = 0x80040154)
         msgbox Class not registered
      else
         msgbox error: %result%
      ExitApp
   }
   DeleteHString(hString)
}

CreateHString(string, ByRef hString)
{
   DllCall("Combase.dll\WindowsCreateString", "wstr", string, "uint", StrLen(string), "ptr*", hString)
}

DeleteHString(hString)
{
   DllCall("Combase.dll\WindowsDeleteString", "ptr", hString)
}

WaitForAsync(ByRef Object)
{
   AsyncInfo := ComObjQuery(Object, IAsyncInfo := "{00000036-0000-0000-C000-000000000046}")
   loop
   {
      DllCall(NumGet(NumGet(AsyncInfo+0)+7*A_PtrSize), "ptr", AsyncInfo, "uint*", status)   ; IAsyncInfo.Status
      if (status != 0)
      {
         if (status != 1)
         {
            DllCall(NumGet(NumGet(AsyncInfo+0)+8*A_PtrSize), "ptr", AsyncInfo, "uint*", ErrorCode)   ; IAsyncInfo.ErrorCode
            msgbox AsyncInfo status error: %ErrorCode%
            ExitApp
         }
         ObjRelease(AsyncInfo)
         break
      }
      sleep 10
   }
   DllCall(NumGet(NumGet(Object+0)+8*A_PtrSize), "ptr", Object, "ptr*", ObjectResult)   ; GetResults
   ObjRelease(Object)
   Object := ObjectResult
}
teadrinker
Posts: 4326
Joined: 29 Mar 2015, 09:41
Contact:

Re: How to retrieve full path of currently opened folder?

20 Aug 2020, 11:50

Considering screenshots above, Sabestian Caine doesn't use Windows 10.
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: How to retrieve full path of currently opened folder?

20 Aug 2020, 11:56

I know, I just write it for fun.
teadrinker
Posts: 4326
Joined: 29 Mar 2015, 09:41
Contact:

Re: How to retrieve full path of currently opened folder?

21 Aug 2020, 09:39

All subfolders with file sizes using winapi (works with removable storage too):

Code: Select all

#NoEnv
SetBatchLines, -1
Return

$F10::
   folderPath := Explorer_GetActiveFolderPath()
   FolderInfo := GetFolderInfo(folderPath)
   MsgBox, % Clipboard := AhkToJSON(FolderInfo, "    ")
   Return

Explorer_GetActiveFolderPath() {
   WinGetClass, winClass, % "ahk_id" . hWnd := WinExist("A")
   if !(winClass ~="Progman|WorkerW|(Cabinet|Explore)WClass")
      Return
   
   shellWindows := ComObjCreate("Shell.Application").Windows
   if (winClass ~= "Progman|WorkerW")  ; IShellWindows::Item:    https://goo.gl/ihW9Gm
                                       ; IShellFolderViewDual:   https://goo.gl/gnntq3
      shellFolderView := shellWindows.Item( ComObject(VT_UI4 := 0x13, SWC_DESKTOP := 0x8) ).Document
   else {
      for window in shellWindows       ; ShellFolderView object: https://goo.gl/MhcinH
         if (hWnd = window.HWND) && (shellFolderView := window.Document)
            break
   }
   Return shellFolderView.Folder.Self.Path
}

GetFolderInfo(folderPath) {
   static Shell := ComObjCreate("Shell.Application")
   Folder := Shell.Namespace(folderPath)
   folderName := Folder.Self.Name
   Info := {}, Obj := Info[folderName] := {}, Obj.folderSize := 0, Obj.items := []
   for Item in Folder.Items {
      if !Item.IsFolder || Item.Type ~= "i)zip|cab"
         Obj.folderSize += Obj.items[Item.Name] := GetFileSize(Item.Path)
      else {
         ChildFolderInfo := %A_ThisFunc%(Item.Path)
         for name in ChildFolderInfo {
            Obj.folderSize += ChildFolderInfo[name].folderSize
            Obj.items[name] := ChildFolderInfo[name]
         }
      }
   }
   Return Info
}

GetFileSize(filePath) {
   static IID_IShellItem2 := "{7e9fb0d3-919f-4307-ab2e-9b1860310c93}"
        , PKEY_Size_GUID  := "{b725f130-47ef-101a-a5f1-02608c9eebac}", PKEY_Size_PID := 12
        , CLSID, PROPERTYKEY, pFnCreateItem
        
   if !CLSID {
      VarSetCapacity(CLSID, 16, 0)
      DllCall("ole32\CLSIDFromString", "WStr", IID_IShellItem2, "Ptr", &CLSID)
      VarSetCapacity(PROPERTYKEY, 20, 0)
      DllCall("ole32\CLSIDFromString", "WStr", PKEY_Size_GUID, "Ptr", &PROPERTYKEY)
      NumPut(PKEY_Size_PID, &PROPERTYKEY + 16, "UInt")
      hLib := DllCall("LoadLibrary", "Str", "Shell32.dll", "Ptr")
      pFnCreateItem := DllCall("GetProcAddress", "Ptr", hLib, "AStr", "SHCreateItemFromParsingName", "Ptr")
   }
   hr := DllCall(pFnCreateItem, "WStr", filePath, "Ptr", 0, "Ptr", &CLSID, "PtrP", pIShellItem2, "UInt")
   if (hr != 0)
      throw "Failed to create IShellItem2 interface from file:`n`n" . filePath . "`n`nError: " . Format("{:#x}", hr)

   ; IShellItem2::GetUInt64
   hr := DllCall(NumGet(NumGet(pIShellItem2 + 0) + A_PtrSize*18), "Ptr", pIShellItem2, "Ptr", &PROPERTYKEY, "UInt64P", fileSize, "UInt")
   if (hr != 0)
      throw "Failed to get size of file:`n`n" . filePath . "`n`nError: " . Format("{:#x}", hr)
   
   ObjRelease(pIShellItem2)
   Return fileSize
}

AhkToJSON(obj, indent := "") {
   static doc := ComObjCreate("htmlfile")
        , _ := doc.write("<meta http-equiv=""X-UA-Compatible"" content=""IE=9"">")
        , JS := doc.parentWindow

   if indent|1 {
      if IsObject( obj ) {
         isArray := true
         for key in obj {
            if IsObject(key)
               throw Exception("Invalid key")
            if !( key = A_Index || isArray := false )
               break
         }
         for k, v in obj
            str .= ( A_Index = 1 ? "" : "," ) . ( isArray ? "" : """" . k . """:" ) . %A_ThisFunc%(v, true)

         Return isArray ? "[" str "]" : "{" str "}"
      }
      else if !(obj*1 = "" || RegExMatch(obj, "\s"))
         Return obj
      
      for k, v in [["\", "\\"], [A_Tab, "\t"], ["""", "\"""], ["/", "\/"], ["`n", "\n"], ["`r", "\r"], [Chr(12), "\f"], [Chr(08), "\b"]]
         obj := StrReplace( obj, v[1], v[2] )

      Return """" obj """"
   }
   sObj := %A_ThisFunc%(obj, true)
   Return JS.eval("JSON.stringify(" . sObj . ",'','" . indent . "')")
}
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: How to retrieve full path of currently opened folder?

21 Aug 2020, 14:33

Your script does not work with my connected phone.
Just shows:

Code: Select all

{
    "": {
        "folderSize": 0,
        "items": []
    }
}
Also it does not work with videos, music, pictures... folders.
Also I get such error :with file=11.6 GB
---------------------------
dx9.ahk
---------------------------
Error: Failed to get size of file:

C:\Users\malcev\Downloads\gena\Once.Upon.a.Time.in.Hollywood.WEB-DL.1080p.Amazon.mkv

Error: 0x80070216

Line#
059: pFnCreateItem := DllCall("GetProcAddress", "Ptr", hLib, "AStr", "SHCreateItemFromParsingName", "Ptr")
060: }
061: hr := DllCall(pFnCreateItem, "WStr", filePath, "Ptr", 0, "Ptr", &CLSID, "PtrP", pIShellItem2, "UInt")
062: if (hr != 0)
063: Throw,"Failed to create IShellItem2 interface from file:

" . filePath . "

Error: " . Format("{:#x}", hr)
066: hr := DllCall(NumGet(NumGet(pIShellItem2 + 0) + A_PtrSize*18), "Ptr", pIShellItem2, "Ptr", &PROPERTYKEY, "UInt64P", fileSize, "UInt")
067: if (hr != 0)
---> 068: Throw,"Failed to get size of file:

" . filePath . "

Error: " . Format("{:#x}", hr)
070: ObjRelease(pIShellItem2)
071: Return,fileSize
072: }
074: {
079: if indent|1
079: {
080: if IsObject( obj )

The current thread will exit.
---------------------------
OK
---------------------------
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: How to retrieve full path of currently opened folder?

23 Aug 2020, 07:17

If You want to get info from removable devices with winapi, You have to use WPD api, I think.
https://docs.microsoft.com/en-us/windows/win32/windows-portable-devices
teadrinker
Posts: 4326
Joined: 29 Mar 2015, 09:41
Contact:

Re: How to retrieve full path of currently opened folder?

23 Aug 2020, 07:32

Thanks, I'll try later.
malcev wrote: Also it does not work with videos, music, pictures... folders.
Do you mean libraries? They are not folders. :)
User avatar
Sabestian Caine
Posts: 528
Joined: 12 Apr 2015, 03:53

Re: How to retrieve full path of currently opened folder?

23 Aug 2020, 08:00

teadrinker wrote:
21 Aug 2020, 09:39
All subfolders with file sizes using winapi (works with removable storage too):

Code: Select all

#NoEnv
SetBatchLines, -1
Return

$F10::
   folderPath := Explorer_GetActiveFolderPath()
   FolderInfo := GetFolderInfo(folderPath)
   MsgBox, % Clipboard := AhkToJSON(FolderInfo, "    ")
   Return

Explorer_GetActiveFolderPath() {
   WinGetClass, winClass, % "ahk_id" . hWnd := WinExist("A")
   if !(winClass ~="Progman|WorkerW|(Cabinet|Explore)WClass")
      Return
   
   shellWindows := ComObjCreate("Shell.Application").Windows
   if (winClass ~= "Progman|WorkerW")  ; IShellWindows::Item:    https://goo.gl/ihW9Gm
                                       ; IShellFolderViewDual:   https://goo.gl/gnntq3
      shellFolderView := shellWindows.Item( ComObject(VT_UI4 := 0x13, SWC_DESKTOP := 0x8) ).Document
   else {
      for window in shellWindows       ; ShellFolderView object: https://goo.gl/MhcinH
         if (hWnd = window.HWND) && (shellFolderView := window.Document)
            break
   }
   Return shellFolderView.Folder.Self.Path
}

GetFolderInfo(folderPath) {
   static Shell := ComObjCreate("Shell.Application")
   Folder := Shell.Namespace(folderPath)
   folderName := Folder.Self.Name
   Info := {}, Obj := Info[folderName] := {}, Obj.folderSize := 0, Obj.items := []
   for Item in Folder.Items {
      if !Item.IsFolder || Item.Type ~= "i)zip|cab"
         Obj.folderSize += Obj.items[Item.Name] := GetFileSize(Item.Path)
      else {
         ChildFolderInfo := %A_ThisFunc%(Item.Path)
         for name in ChildFolderInfo {
            Obj.folderSize += ChildFolderInfo[name].folderSize
            Obj.items[name] := ChildFolderInfo[name]
         }
      }
   }
   Return Info
}

GetFileSize(filePath) {
   static IID_IShellItem2 := "{7e9fb0d3-919f-4307-ab2e-9b1860310c93}"
        , PKEY_Size_GUID  := "{b725f130-47ef-101a-a5f1-02608c9eebac}", PKEY_Size_PID := 12
        , CLSID, PROPERTYKEY, pFnCreateItem
        
   if !CLSID {
      VarSetCapacity(CLSID, 16, 0)
      DllCall("ole32\CLSIDFromString", "WStr", IID_IShellItem2, "Ptr", &CLSID)
      VarSetCapacity(PROPERTYKEY, 20, 0)
      DllCall("ole32\CLSIDFromString", "WStr", PKEY_Size_GUID, "Ptr", &PROPERTYKEY)
      NumPut(PKEY_Size_PID, &PROPERTYKEY + 16, "UInt")
      hLib := DllCall("LoadLibrary", "Str", "Shell32.dll", "Ptr")
      pFnCreateItem := DllCall("GetProcAddress", "Ptr", hLib, "AStr", "SHCreateItemFromParsingName", "Ptr")
   }
   hr := DllCall(pFnCreateItem, "WStr", filePath, "Ptr", 0, "Ptr", &CLSID, "PtrP", pIShellItem2, "UInt")
   if (hr != 0)
      throw "Failed to create IShellItem2 interface from file:`n`n" . filePath . "`n`nError: " . Format("{:#x}", hr)

   ; IShellItem2::GetUInt64
   hr := DllCall(NumGet(NumGet(pIShellItem2 + 0) + A_PtrSize*18), "Ptr", pIShellItem2, "Ptr", &PROPERTYKEY, "UInt64P", fileSize, "UInt")
   if (hr != 0)
      throw "Failed to get size of file:`n`n" . filePath . "`n`nError: " . Format("{:#x}", hr)
   
   ObjRelease(pIShellItem2)
   Return fileSize
}

AhkToJSON(obj, indent := "") {
   static doc := ComObjCreate("htmlfile")
        , _ := doc.write("<meta http-equiv=""X-UA-Compatible"" content=""IE=9"">")
        , JS := doc.parentWindow

   if indent|1 {
      if IsObject( obj ) {
         isArray := true
         for key in obj {
            if IsObject(key)
               throw Exception("Invalid key")
            if !( key = A_Index || isArray := false )
               break
         }
         for k, v in obj
            str .= ( A_Index = 1 ? "" : "," ) . ( isArray ? "" : """" . k . """:" ) . %A_ThisFunc%(v, true)

         Return isArray ? "[" str "]" : "{" str "}"
      }
      else if !(obj*1 = "" || RegExMatch(obj, "\s"))
         Return obj
      
      for k, v in [["\", "\\"], [A_Tab, "\t"], ["""", "\"""], ["/", "\/"], ["`n", "\n"], ["`r", "\r"], [Chr(12), "\f"], [Chr(08), "\b"]]
         obj := StrReplace( obj, v[1], v[2] )

      Return """" obj """"
   }
   sObj := %A_ThisFunc%(obj, true)
   Return JS.eval("JSON.stringify(" . sObj . ",'','" . indent . "')")
}

Thanks dear teadrinker... these codes are not working with removable device... When i attach my mobile with pc and open its removable device folder the run these codes then it takes 3-4 minutes and then it shows this error-
23_08_20 @6_20_11.PNG
23_08_20 @6_20_11.PNG (41.12 KiB) Viewed 3705 times
However when I open any sub folder of removable device and then run these codes then it works and shows the size of subfolder and all its files like this-

23_08_20 @6_26_43.PNG
23_08_20 @6_26_43.PNG (43.24 KiB) Viewed 3705 times

Could you please solve this problem.. Thanks a lot..
I don't normally code as I don't code normally.
User avatar
Sabestian Caine
Posts: 528
Joined: 12 Apr 2015, 03:53

Re: How to retrieve full path of currently opened folder?

23 Aug 2020, 10:29

teadrinker wrote:
23 Aug 2020, 08:09
A weird error. I'll think about it.
Ok sir, Actually your codes are showing the size of sub folders of removable device but they are not showing the size of main folder of removable device itself. Thanks..
I don't normally code as I don't code normally.

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Google [Bot] and 295 guests