Folder.au3

Last modified:   Friday, 6 March 2009

;*******************************************************************************
;
;   Function List
;         _Fldr_GetLevel()
;         _Fldr_GetParent()
;         _FldrCompression()
;         _FldrCopyMove()
;         _FldrGetDates()
;         _FldrGetSize()
;         _FldrListToArray()
;
;*******************************************************************************

;*******************************************************************************
; Constants for Special Folders in Windows

Global Const $Administrative_Tools = 0x2f
Global Const $All_Users_Application_Data = 0x23
Global Const $All_Users_Desktop = 0x19
Global Const $All_Users_Favorites = 0x19
Global Const $All_Users_Programs = 0x17
Global Const $All_Users_Start_Menu = 0x16
Global Const $All_Users_Startup = 0x18
Global Const $All_Users_Templates = 0x2e
Global Const $Application_Data = 0x1a
Global Const $CD_Burning_Folder = 0x003b
Global Const $Common_Files = 0x2b
Global Const $Control_Panel = 0x3
Global Const $Cookies = 0x21
Global Const $Desktop = 0x10
Global Const $Favorites = 0x6
Global Const $Fonts = 0x14
Global Const $Internet_Explorer = 0x1
Global Const $Local_Settings_Application_Data = 0x1c
Global Const $Local_Settings_History = 0x22
Global Const $Local_Settings_Temporary_Internet_Files = 0x20
Global Const $My_Computer = 0x11
Global Const $My_Documents = 0x5
Global Const $My_Music = 0xd
Global Const $My_Network_Places = 0x12
Global Const $My_Pictures = 0x27
Global Const $My_Recent_Documents = 0x8
Global Const $My_Videos = 0xe
Global Const $NetHood = 0x13
Global Const $Network_Connections = 0x31
Global Const $Printers_and_Faxes = 0x4
Global Const $PrintHood = 0x1b
Global Const $Program_Files = 0x26
Global Const $Programs = 0x2
Global Const $Recycle_Bin = 0xa
Global Const $SendTo = 0x9
Global Const $Start_Menu = 0xb
Global Const $Startup = 0x7
Global Const $System32 = 0x25
Global Const $Templates = 0x15
Global Const $User_Profile = 0x28
Global Const $Windows = 0x24
;*******************************************************************************

;*******************************************************************************
; Example(s)
#cs
    _Special_Folders($My_Network_Places)

    Func _Special_Folders ($Folder)
        $objShell = ObjCreate("Shell.Application")
        $objShell.open($objShell.NameSpace($Folder))
    EndFunc
#ce
;*******************************************************************************
#include-once
;;<<<<<<<<<<<<<<  Functions to assist with folder data management  >>>>>>>>>>>>>>>>>>>>>>>>>>>>

;===============================================================================
; Function Name:    _Fldr_GetLevel()
; Description:      Get the path to the parent of the specified folder
; Syntax:           _Fldr_GetLevel($sPath [, Level])
; Parameter(s):     $sFldr - The folder to start from
;                   $Level - How many levels to go up from $sFldr  Default is 1 which returns the same as
;                            _Fldr_GetParent() below
; Requirements:
; Return Value(s):  Success - Returns the path to the folder without a trailing backslash
;                   Failure Sets @Error
;                       [1 - Recursion level exceeded - Returns a blank string and sets @Error to 1
;                       [2 - $sPath does not exist - Returns a blank string and sets @Error to 2
; Author(s):        George (GEOSoft) Gedye
; Notes:
; Modifications:
; Example(s):     _Fldr_GetLevel("C:\WINDOWS\system32\SoftwareDistribution\Setup", 3) returns "C:\Windows"
;===============================================================================

Func _Fldr_GetLevel($sPath, $Level = 1);;  default $level takes it to the parent
If StringRight($sPath, 1) = "\" Then $sPath = StringTrimRight($sPath, 1)
If NOT FileExists($sPath) Then Return SetError(2, 2, "The starting folder does not exist")
Local $rFldr = StringSplit($sPath, "\"), $I, $fPath = ""
If $Level > Ubound($rFldr) -1 Then Return SetError(1, 1, "Recursion level exceeded");; Returns a blank string and sets @Error to 1
$Level += 1
For $I = 1 To Ubound($rFldr) - $Level
   $fPath &= $rFldr[$I] & "\"
Next
Return StringTrimRight($fPath, 1)
EndFunc    ;<===> _Fldr_GetLevel()

;===============================================================================
; Function Name:    _Fldr_GetParent()
; Description:      Get the path to the parent of the specified folder
; Syntax:           _FldrGetParent([$rFldr])
; Parameter(s):     $rFldr - The folder to query 
; Requirements:
; Return Value(s):  Success - Returns the path to the parent folder without a trailing backslash
;                   Failure Sets @Error
;                             [1 - unable to create the object
;                             [2 - $rFldr does not exist
; Author(s):        George (GEOSoft) Gedye
; Notes:
; Modifications:
;===============================================================================

Func _Fldr_GetParent($sFldr)
   If StringRight($sFldr, 1) = "\" Then $sFldr = StringTrimRight($sFldr, 1)
   Return StringLeft($sFldr, StringInStr($sFldr, "\", 0, -1) -1)
EndFunc    ;<===> _Fldr_GetParent()

;===============================================================================
; Function Name:   _Fldr_IsEmpty()
; Description:     Determine if a folder is empty
; Syntax:          _Fldr_IsEmpty("folder path")
; Parameter(s):    $szRoot - Path to the folder
; Requirement(s):   
; Return Value(s): 1 - the folder is empty
;                  0 - the folder contains files or folders (not empty)
; Author(s):   George (GEOSoft) Gedye
; Modification(s): 
; Note(s):    
; Example(s):   
;===============================================================================

Func _Fldr_IsEmpty($szRoot)
   If StringRight($szRoot, 1) <>"\" THen $szRoot &= "\"
   If FileFindFirstFile($szRoot & "*") = -1 Then Return 1
   Return 0
EndFunc   ;<==> _Fldr_IsEmpty()

;===============================================================================
; Function Name:    _FldrCompression()
; Description:      Compress or decompress a folder.
; Syntax:           _FldrCompression($rFldr [, $action])
; Parameter(s):     $rFldr - The folder to perform the action on.
;                   $action - Action to perform -- 0 = Compress (default), 1 = Decompress
; Requirements:
; Return Value(s):  Success - Compresses or Decompresses the specified folder
;                   Failure Sets @Error
;                      [1 - The current attributes of the folder match the requested action.
;                      [2 - $rFldr does not exist
;                      [3 - Invalid action specified. MUST be 1 or 0
; Author(s):        George (GEOSoft) Gedye
; Notes:
; Modifications:
; Example(s):
;                   $Cpr = _FldrCompression("C:\Test") ;; Compress the folder C:\Test
;                   If @Error Then MsgBox(0, 'Error', $Cpr)
;                   $Cpr = _FldrCompression("C:\Test", 1) ;; Decompress the folder C:\Test
;                   If @Error Then MsgBox(0, 'Error', $Cpr)
;===============================================================================

Func _FldrCompression($rFldr, $action= 0)
   Local $eMsg = 'The folder' & @CRLF & $rFldr & @CRLF & 'is already '
   If NOT FileExists($rFldr) Then Return SetError( 2, 2, 'Unable to locate the folder' & @CRLF & @CRLF & $rFldr)
   If $action = 0 Then
      If StringInStr(FileGetAttrib($rFldr), 'C') Then Return SetError( 1, 1, $eMsg & 'compressed')
   ElseIf $action = 1 Then
      If NOT StringInStr(FileGetAttrib($rFldr), 'C') Then Return SetError( 1, 1, $eMsg & 'uncompressed')
   Else
      Return SetError(3, 3, 'Invalid action')
   EndIf
   If NOT StringInStr($rFldr, '\\') Then $rFldr = StringReplace($rFldr, '\', '\\')
   $rFldr = Chr(39) & $rFldr & Chr(39)
   $objWMIService = ObjGet("winmgmts:" & "{impersonationLevel=impersonate}!\\.\root\cimv2")
   $colFolders = $objWMIService.ExecQuery ("Select * from Win32_Directory where name = " & $rFldr)
   For $objFolder in $colFolders
      If $action = 0 Then
         $errResults = $objFolder.Compress
      Else
         $errResults = $objFolder.UnCompress
      EndIf
   Next
EndFunc   ;<==> _FldrCompression()

;===============================================================================
; Function Name:    _FldrCopyMove()
; Description:      Copy or Move folders with progress dialog
; Syntax:           _FldrCopyMove(Folder to process, Destination folder[, Action])
; Parameter(s):     $rFldr - The full path of the folder to copy or move
;                   $nFldr - The full path of the destination folder
;                   $action - The action to perform 0 = Copy (default) 1 = Move
; Requirements:
; Return Value(s):  Success - Folder is copied / moved
;                   Failure Sets @Error
;                                [1 - unable to create the shell object
;                                [2 - the specified $rFldr was not located (check the path)
;                                [3 - an invalid action was specified
; Author(s):        George (GEOSoft) Gedye
; Notes:            To self --- removed all the dircopy's and used dircreate/filecopy
;                         and over a network it's 800 x's faster for large folder structures
; Modifications:
;===============================================================================

Func _FldrCopyMove($rFldr, $nFldr, $action = 0)
   If NOT FileExists($rFldr) Then Return SetError( 2, 2, 'Unable to locate the folder' & @CRLF & @CRLF & $rFldr)
   If $action <> 0 AND $action <> 1 Then Return SetError(3, 3, 'Invalid action')
   $obj = ObjCreate ("Shell.Application")
   If IsObj($obj) Then
      If NOT FileExists($nFldr) Then DirCreate($nFldr)
      $cFldr = $obj.NameSpace ($nFldr)
      If $action = 0 Then
         $cFldr.CopyHere ($rFldr, "&H0&")
      Else
         $cFldr.MoveHere ($rFldr, "&H0&")
      EndIf
   Else
      Return SetError(1, 1, 'Unable to create the Shell object')
   EndIf
EndFunc    ;<===> _FldrCopyMove()

;===============================================================================
; Function Name:    _FldrGetDates()
; Description:      Returns the Created, LastModified and LastAccessed dates and times of a folder as an array.
; Syntax:           _FldrGetDates([$rFldr [, $Mth_AsText [, $Ext_Date [, $T_Txt ]]]])
; Parameter(s):     $rFldr - The folder to query (default is current dir)
;                   $Mth_AsText - Return the month as text (default) Use 0 to return the numeric date
;                   $Ext_Date - If 0 returns the raw date.
;                               If 1 (default) returns a formatted date string
;                   $T_Txt - If set to 1 (default) and the date = current day then replaces the date with "Today at"
; Requirements:
; Return Value(s):  Success - Returns an Array containing the dates and times of the folder where
;                   array[1] = DateCreated
;                   array[2] = DateLastModified
;                   array[3] = DateLastAccessed
;                   Failure Sets @Error
;                                [1 - unable to create the FileSystem object
;                                [2 - $rFldr does not exist
; Author(s):        George (GEOSoft) Gedye
; Notes:
; Modifications:
;===============================================================================

Func _FldrGetDates($rFldr = '', $Mth_AsText = 1, $Ext_Date = 1, $T_Txt = 1)
   If $rFldr <> '' AND NOT FileExists($rFldr) Then Return SetError( 2, 2, 'Unable to locate the folder' & @CRLF & @CRLF & $rFldr)
   $obj = ObjCreate("Scripting.FileSystemObject")
   If IsObj($obj) Then
      If $rFldr = '' Then $rFldr = @HomeDrive & '\' & @HomePath
      $oFldr = $obj.GetFolder($rFldr)
      Local $Rtn = ''
      With $oFldr
         Dim $F_prop[3] = [.DateCreated,.DateLastModified,.DateLastAccessed]

         For $I = 0 To Ubound($F_Prop) -1
            $Rtn &= _FldrDate($F_Prop[$I], $Mth_AsText, $Ext_Date, $T_Txt) & '|'
         Next

      EndWith
      Return StringSplit(StringTrimRight($Rtn,1), '|')
   Else
      Return SetError(1, 1, 'Unable to create the FileSystem object')
   EndIf
EndFunc    ;<===> _FldrGetDates()

;===============================================================================
; Function Name:    _FldrGetSize()
; Description:      A replacement for the DirGetSize() function that will return the size as bytes, Kbs or Mbs
; Syntax:           _FldrGetSize([$rFldr [,$Set_Ext ]])
; Parameter(s):     $rFldr - The folder to query (default is current dir)
;                   $Set_Ext - If 1 (default) returns the size as shown in the description.
;                              If 0 then returns the same as DirGetSize()
; Requirements:
; Return Value(s):  Success the date as defined by $Set_Ext
;                   Failure Sets @Error
;                              [1 - unable to create the object
;                              [2 - $rFldr does not exist
; Author(s):        George (GEOSoft) Gedye
; Notes:
; Modifications:
;===============================================================================

Func _FldrGetSize($rFldr = '', $Set_Ext = 1)
   If $rFldr <> '' AND NOT FileExists($rFldr) Then Return SetError( 2, 2, 'Unable to locate the folder' & @CRLF & @CRLF & $rFldr)
   $obj = ObjCreate("Scripting.FileSystemObject")
   If IsObj($obj) Then
      If $rFldr = '' Then $rFldr = @HomeDrive & '\' & @HomePath
      $oFldr = $obj.GetFolder($rFldr)
      $F_Size = $oFldr.size
      If $Set_Ext <> 1 Then Return $F_Size
      $Div = 0

      While $F_Size > 1024
         $F_Size = $F_Size / 1024
         $Div += 1
      Wend

      If $Div = 0 Then
         Return $F_Size & ' bytes'
      ElseIf $Div = 1 Then
         Return Round($F_Size, 3) & ' Kb'
      EndIf
      Return Round($F_Size, 2) & ' Mb'
   Else
      Return SetError(1, 1, 'Unable to create the FileSystem object')
   EndIf
EndFunc    ;<===> _FldrGetSize()

;===============================================================================
; Function Name:    _FldrListToArray()
; Description:      Recursivly find the folders in a given path (returns full path for each)
; Syntax:           _FldrListToArray($szRoot, $nFlag = 1 )
; Parameter(s):     $szRoot - The base folder
;                   $sIgnore - Folders to exclude - MUST be pipe (|) separated
;                   $iRecurs - If 1 (default) search is recursive
;                   $iNoRoot - If 0 (default) $szRoot is included in the returned array
;                                    else $szRoot is ignored.
; Requirements:
; Return Value(s):  Success - A 1 based array of the folders with paths
;                   Failure - None
; Author(s):        George (GEOSoft) Gedye
; Notes:
;Example(s):
#cs
    #include <array.au3>
    ;; folders in C:\, ignore Windows and Recycler folders, recursive and don't include the root folder
    $aArray = _FldrListToArray("c:", "windows|recycler", 1, 1)
    _ArrayDisplay($aArray)
#ce
;===============================================================================

Func _FldrListToArray($szRoot, $sIgnore = "", $iRecurs = 1, $iNoRoot = 0 )
   If StringRight($szRoot, 1) <> '\' Then $szRoot &= '\'
   Local $szReturn = '',  $szBuffer = '', $szPathlist = '*', $oRoot = $szRoot & '*', $sChk = $szRoot
      $Hfile = FileFindFirstFile ($szRoot &'*')
      If $Hfile >= 0 Then
         $szBuffer = FileFindNextFile ($Hfile)
         While NOT @Error
            If StringInStr(FileGetAttrib($szRoot & $szBuffer), 'D') Then
               If $sIgnore AND  StringRegExp($szBuffer, "(?i)" & $sIgnore) Then
                  $szBuffer = FileFindNextFile ($Hfile)
                  ContinueLoop
               EndIf
               If StringInStr($szRoot & $szBuffer, $sChk) Then $szPathlist &= $szRoot & $szBuffer & "\*"
            EndIf
            $szBuffer = FileFindNextFile ($Hfile)
         Wend
         FileClose ($Hfile)
      EndIf
      $szReturn = $szPathList

   If $iRecurs = 1 Then
      $szPathList = StringTrimLeft($szPathlist, 1)
      $szRoot = StringLeft($szPathList, StringInStr($szPathlist, '*') -1)
      While 1
         $hFile = FileFindFirstFile ($szRoot & '*')
         If $hFile >= 0 Then
            $szBuffer = FileFindNextFile ($Hfile)
         While NOT @Error
            If StringInStr(FileGetAttrib($szRoot & $szBuffer), 'D') Then
               If NOT $sIgnore Then
                  If StringInStr($szRoot & $szBuffer, $sChk) Then $szPathlist &= $szRoot & $szBuffer & "\*"
                  If StringInStr($szRoot & $szBuffer, $sChk) Then $szReturn &= $szRoot & $szBuffer & "\*"
               Else
                  If NOT StringRegExp($szBuffer, "(?i)" & $sIgnore) Then
                     If StringInStr($szRoot & $szBuffer, $sChk) Then $szPathlist &= $szRoot & $szBuffer & "\*"
                     If StringInStr($szRoot & $szBuffer, $sChk) Then $szReturn &= $szRoot & $szBuffer & "\*"
                  EndIf
               EndIf
            EndIf
            $szBuffer = FileFindNextFile ($Hfile)
         Wend
         FileClose($hFile)
         $szPathList = StringReplace($szPathList, $szRoot, '')
         EndIf
         If $szPathList == '*' Then ExitLoop
         $szPathlist = StringTrimLeft ($szPathlist, 1)
         $szRoot = StringLeft ($szPathlist, StringInStr ($szPathlist, "*") - 1) & "\"
         $szPathlist = StringTrimLeft ($szPathlist, StringInStr ($szPathlist, "*") - 1)
      Wend
   EndIf
   If StringLeft($szReturn, 1) = '*' Then $szReturn = StringTrimLeft($szReturn, 1)
   $szReturn = StringReplace($szReturn, '\\', '\')
   If StringRight($szReturn, 1) = '*' Then $szReturn = StringTrimRight($szReturn,1)
   If NOT $iNoRoot Then $szReturn = $oRoot & $szReturn
   $szReturn = StringSplit($szReturn,'*')
   If $szReturn = '*' or $szReturn = '' Then Return 0
   ; _ArraySort($szReturn) ;; << uncomment and #include <array.au3> to return a sorted array
   Return $szReturn
EndFunc   ;<==> _FldrListToArray()

;;  Private Functions

Func _FldrDate($Dt, $Ext_Date, $Mth_AsText, $T_Txt)
   Local $Tday = 0
   If $Ext_Date = 0 Then Return $Dt
   Local $Disp_Mon = StringSplit('January|February|March|April|May|June|July|August|September|October|November|December', '|')
   Local $y = StringLeft($Dt, 4)
   Local $m = StringMid($Dt,5,2)
   Local $d = StringMid($Dt, 7, 2)
   If $y = @Year AND $m = @Mon AND $d = @Mday Then $Tday = 1
   Local $t = StringMid($Dt, 9)
   $t = StringLeft($t,2) & ':' & StringMid($t, 3,2) & ':' & StringRight($t, 2)
   If StringLeft( $t, 2) < 12 Then
      $t &= ' am'
   Else
      $t = StringLeft($t, 2) - 12 & StringMid($t, 3)
      $t &= ' pm'
   EndIf
   If $Tday = 1 AND $Mth_AsText = 1 AND $T_Txt = 1 Then Return 'Today at ' & $t
   If $Mth_AsText = 1 Then $m = $Disp_Mon[$m]
   Return $m & ' ' & $d & ' ' & $y & ' at ' & $t
EndFunc    ;<===> _FldrDate()