Jump to content

Help with DllCall to shell32.dll for SHGetFileInfo


 Share

Recommended Posts

Hi,

Any AutoIt gurus to help out / offer suggestions with problems below? Obviously a code replicating the Windows Explorer functionality.

  • I managed to get the DllCall to shell32.dll for SHGetFileInfo to work, but it does so only in the same folder as the Script or Compiled Binary !
  • In GUIGetMsg() Loop, Is there a better way/place to update on ListView's "Checkbox" click instead of on every $GUI_EVENT_PRIMARYUP ?

    Obviously this does not work when using Spacebar to toggle the listview checkbox.

  • In using FileGetTime(), is there a better way of presenting the Date and Time using the $DTS_SHORTDATEFORMAT and $DTS_TIMEFORMAT constants?
*Edit*: Just found a post by weaponx regarding FileGetTime() formatting here #509802

Appreciate any suggestions for the issues or other ways to optimize the code.

Pointers to a good listview sort (if possible with indicators in column head for sort direction) code would be great too.

#NoTrayIcon
#Region     ____Includes____
#include <GUIConstants.au3>
#include <GuiListView.au3>
#EndRegion ____Includes____

#Region     ____Globals____
Global Const $_Slash = "\"
Global Const $_Pipe = "|"
#EndRegion ____Globals____

#Region ____GUI____
$frmMain = GUICreate("Files ListView", 633, 447, 193, 115)
GUISetStyle(BitOR($WS_MINIMIZEBOX, $WS_MAXIMIZEBOX, $WS_SIZEBOX, $WS_CAPTION, $WS_POPUP, $WS_SYSMENU))
$Btn_Source = GUICtrlCreateButton("Folder:", 8, 8, 73, 25, 0)
GUICtrlSetTip(-1, " Select Source Folder ")
$Txt_Source = GUICtrlCreateInput(@WorkingDir & $_Slash, 88, 8, 537, 21)
$lbl_FileSpec = GUICtrlCreateLabel("File Selection:", 18, 44, 70, 17)
$txt_FileSpec = GUICtrlCreateInput("*.*", 88, 40, 41, 24)
$lbl_LvwFiles = GUICtrlCreateLabel("", 136, 40, 387, 25)
$Btn_Refresh = GUICtrlCreateButton("&Refresh", 529, 40, 97, 25, 0)
$Lvw_Files = GUICtrlCreateListView("File|Date Modified", 8, 72, 617, 361)
_GUICtrlListView_AddColumn($Lvw_Files, "Size", 50, 1)
_GUICtrlListView_AddColumn($Lvw_Files, "Type")
_GUICtrlListView_SetExtendedListViewStyle($Lvw_Files, BitOR($LVS_EX_CHECKBOXES, $LVS_EX_FULLROWSELECT))
#EndRegion ____GUI____

GUISetState(@SW_SHOW)
While 1
    $msg = GUIGetMsg();
    Switch $msg
    Case $GUI_EVENT_CLOSE
             ExitLoop
    Case $Btn_Source
             Btn_Source_Click()
    Case $Btn_Refresh
             Btn_Refresh_Click()
    Case $GUI_EVENT_PRIMARYUP; Is there a better way/place to update on ListView's "Checkbox" click?
             Update_FilesSelected()
  EndSwitch
WEnd

Func Update_FilesSelected()
    $j = _GUICtrlListView_GetItemCount($Lvw_Files)
    $k = 0
    For $i = 0 To $j
        If _GUICtrlListView_GetItemChecked($Lvw_Files, $i) Then $k = $k + 1
  Next
    GUICtrlSetData($lbl_LvwFiles, $k & " of " & $j & " Files Selected")
EndFunc

Func Btn_Source_Click()
  $source = GUICtrlRead($Txt_Source, 1)
  if StringLen($source) < 1 Then $source = @MyDocumentsDir & $_Slash
    $source = FileSelectFolder("Choose Source Folder", "", 1, $source)
    if StringLen($source) > 0 Then GUICtrlSetData($Txt_Source, $source & $_Slash)
EndFunc

Func Btn_Refresh_Click()
Dim $source, $filespec, $filename, $fileattrib, $fileext, $filedate, $filesize
Dim $LvwItem, $psfi, $ret, $filetype
;GUICtrlSetData($Lvw_Files, ""); Gah! Does not work !
  _GUICtrlListView_DeleteAllItems(GUICtrlGetHandle($Lvw_Files))
  Update_FilesSelected()

    $source = GUICtrlRead($Txt_Source, 1)
    $filespec = GUICtrlRead($Txt_FileSpec, 1)
    If StringLen($source) < 1 Then
       MsgBox(0, $_Eh, "Select a Source Folder")
       Return
    EndIf
  If StringRight($source,1) <> $_Slash Then
     $source = $source & $_Slash
     GUICtrlSetData($Txt_Source, $source)
  EndIf
    If StringLen($filespec) < 1 Then
       $filespec = "*.*"
       GUICtrlSetData($Txt_FileSpec, $filespec)
  EndIf

    $search = FileFindFirstFile($source & $filespec)
; Check If The Search Was Successful
    If $search = -1 Then
        MsgBox(0, "Error", "No Files matching " & $filespec & " Found!")
        Return
    EndIf

    While 1
        $filename = FileFindNextFile($search)
        If @error Then ExitLoop
        $fileattrib = FileGetAttrib($source & $filename)
      If NOT StringInStr($fileattrib, "D") Then; Exclude Folders
            $filedate = FileGetTime($source & $filename, 0)
            $ret = FileGetSize($source & $filename)
            If @error Then
               $ret = 0
            Else
                 $ret = $ret  / 1024
            EndIf
            $filesize = StringFormat ("%.1f", $ret)

            $LvwItem = $filename & $_Pipe
            If IsArray($filedate) THen
           $LvwItem = $LvwItem & $filedate[1] & "/" & $filedate[2] & "/" & $filedate[0] & " " & $filedate[3] & ":"  & $filedate[4] & ":" & $filedate[5]
        Else
           $LvwItem = $LvwItem & $filedate
        Endif
          $LvwItem = $LvwItem & $_Pipe
            $LvwItem = $LvwItem & $filesize & " KB " & $_Pipe

          $fileext = ""
          $ret = StringInStr($filename, ".", 1, -1); Search from Right side
          If $ret > 0 Then
             $fileext = StringMid($LvwItem, $ret+1)
          EndIf

            $psfi = DllStructCreate("uint;int;dword;char[260];char[80]")
        $ret = DllCall('shell32.dll', 'int', 'SHGetFileInfo', 'str', $filename, 'uint', 0, 'ptr', DllStructGetPtr($psfi), 'uint', DllStructGetSize($psfi), 'uint', 0x400)
          $filetype = DllStructGetData($psfi,5)
          $psfi = 0; Free the Structure
          If StringLen($filetype) < 1 Then $filetype = $fileext
          If StringLen($filetype) < 1 Then $filetype = "Unknown"
            $LvwItem = $LvwItem & $filetype & $_Pipe

          GuiCtrlCreateListViewItem($LvwItem, $Lvw_Files)
            $ret = _GUICtrlListView_GetItemCount($Lvw_Files)
            _GUICtrlListView_SetItemChecked($Lvw_Files, $ret - 1)
        Endif
    WEnd
; Close the search handle
    FileClose($search)

    Update_FilesSelected()
    ListView_AutoFit()
EndFunc

Func ListView_AutoFit()
Dim $i, $j
    $j = _GUICtrlListView_GetColumnCount ($Lvw_Files)
; Change the column width to fit the item text
    For $i = 0 To $j
        GUICtrlSendMsg($Lvw_Files, $LVM_SETCOLUMNWIDTH, $i, -1)
        GUICtrlSendMsg($Lvw_Files, $LVM_SETCOLUMNWIDTH, $i, -2)
    Next
EndFunc
Edited by DaRam
Link to comment
Share on other sites

1. SHGetFileInfo should receive a proper path. Right now you're only passing a filename, which is why it works for script's directory.

2. Yes. LVN_ITEMCHANGED

"be smart, drink your wine"

Link to comment
Share on other sites

1. SHGetFileInfo should receive a proper path. Right now you're only passing a filename, which is why it works for script's directory.

Awesome catch, thanks Siao - I could kick myself. :D

2. Yes. LVN_ITEMCHANGED

I presume I have to use a GUIRegisterMsg($WM_NOTIFY.... and then trap the Item changed event then.

Any thoughts on #3 presenting the filedatetime array (or string) using $DTS_SHORTDATEFORMAT and $DTS_TIMEFORMAT?

Perusing weaponx's post (I mentioned in the Edit), I did not find the info. I thought I might find on this.

Link to comment
Share on other sites

_DateTimeFormat()

Thanks again.

In case anyone else might be interested, here is the change (just for the date/time in system's regional settings format):

$filedate = FileGetTime($source & $file, 0)
If IsArray($filedate) Then
   $filedate = $filedate[0] & "/" & $filedate[1] & "/" & $filedate[2] & " " & $filedate[3] & ":"  & $filedate[4] & ":" & $filedate[5]
   $filedate = _DateTimeFormat($filedate, 0)
Endif
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...