AutoFan Posted April 20, 2020 Posted April 20, 2020 (edited) Hi, FileOpenDialog failed to work if number of selected files is bigger than 450 (approximately). Is there a workaround ? Thanks Edited April 20, 2020 by AutoFan
Musashi Posted April 20, 2020 Posted April 20, 2020 1 hour ago, AutoFan said: FileOpenDialog failed to work if number of selected files is bigger than 450 (approximately). It seems, that the length of the result string from FileOpenDialog is limited to 65,535 characters (16-bit unsigned integer / word). The number of selected files does not matter. Example -> select 4677 files (StringLen = 65.523) ==> OK ; select 4678 files ==> not OK #include <MsgBoxConstants.au3> ; just to create xxx testfiles (run once) : Local $hFileOpen, $sFileSuffix For $i = 1 To 10000 $sFileSuffix = StringFormat("%05i", $i) $hFileOpen = FileOpen(@ScriptDir & "\testfiles\file" & $sFileSuffix & ".txt", 10) FileWrite($hFileOpen, "File " & $sFileSuffix) FileClose($hFileOpen) Next Example() ; from AutoIt-Help (modified) Func Example() Local Const $sMessage = "Hold down Ctrl or Shift to choose multiple files." Local $iError ; Display an open dialog to select a list of file(s). Local $sFileOpenDialog = FileOpenDialog($sMessage, @ScriptDir & "\testfiles", "All (*.*)", 15) $iError = @error ConsoleWrite("! Error = " & $iError & " StringLen = " & StringLen($sFileOpenDialog) & @CRLF) If $iError Then ; Display the error message. MsgBox($MB_SYSTEMMODAL, "", "No file(s) were selected.") ; Change the working directory (@WorkingDir) back to the location of the script directory as FileOpenDialog sets it to the last accessed folder. FileChangeDir(@ScriptDir) Else ; Change the working directory (@WorkingDir) back to the location of the script directory as FileOpenDialog sets it to the last accessed folder. FileChangeDir(@ScriptDir) ; Replace instances of "|" with @CRLF in the string returned by FileOpenDialog. $sFileOpenDialog = StringReplace($sFileOpenDialog, "|", @CRLF) ; Display the list of selected files. ConsoleWrite("You chose the following files:" & @CRLF & $sFileOpenDialog) EndIf EndFunc ;==>Example AutoFan 1 "In the beginning the Universe was created. This has made a lot of people very angry and been widely regarded as a bad move."
AutoFan Posted April 21, 2020 Author Posted April 21, 2020 (edited) Thanks for pointing out. 21 hours ago, Musashi said: 21 hours ago, Musashi said: It seems, that the length of the result string from FileOpenDialog is limited to 65,535 characters (16-bit unsigned integer / word). The number of selected files does not matter. Example -> select 4677 files (StringLen = 65.523) ==> OK ; select 4678 files ==> not OK #include <MsgBoxConstants.au3> ; just to create xxx testfiles (run once) : Local $hFileOpen, $sFileSuffix For $i = 1 To 10000 $sFileSuffix = StringFormat("%05i", $i) $hFileOpen = FileOpen(@ScriptDir & "\testfiles\file" & $sFileSuffix & ".txt", 10) FileWrite($hFileOpen, "File " & $sFileSuffix) FileClose($hFileOpen) Next Example() ; from AutoIt-Help (modified) Func Example() Local Const $sMessage = "Hold down Ctrl or Shift to choose multiple files." Local $iError ; Display an open dialog to select a list of file(s). Local $sFileOpenDialog = FileOpenDialog($sMessage, @ScriptDir & "\testfiles", "All (*.*)", 15) $iError = @error ConsoleWrite("! Error = " & $iError & " StringLen = " & StringLen($sFileOpenDialog) & @CRLF) If $iError Then ; Display the error message. MsgBox($MB_SYSTEMMODAL, "", "No file(s) were selected.") ; Change the working directory (@WorkingDir) back to the location of the script directory as FileOpenDialog sets it to the last accessed folder. FileChangeDir(@ScriptDir) Else ; Change the working directory (@WorkingDir) back to the location of the script directory as FileOpenDialog sets it to the last accessed folder. FileChangeDir(@ScriptDir) ; Replace instances of "|" with @CRLF in the string returned by FileOpenDialog. $sFileOpenDialog = StringReplace($sFileOpenDialog, "|", @CRLF) ; Display the list of selected files. ConsoleWrite("You chose the following files:" & @CRLF & $sFileOpenDialog) EndIf EndFunc ;==>Example Edited April 21, 2020 by AutoFan
KaFu Posted April 22, 2020 Posted April 22, 2020 Here's a customized version I use in SMF. Return buffer size is defined in row containing Local $iFileBufferSize = 32768 * 10 expandcollapse popup#include <Array.au3> #include <WindowsConstants.au3> #include <WinAPIDlg.au3> Global $f_CDN__FileDialogsEx_Start = 1 $sFile = _FileOpenDialog_Ex("SMF _FileOpenDialog_Ex", @ScriptDir, "All (*.*)", 1 + 2, "", 0, 1) $aFiles = StringSplit($sFile, "|") _ArrayDisplay($aFiles) Func _FileOpenDialog_Ex($sTitle, $sInitDir, $sFilter, $iOptions = 0, $sDefaultName = "", $hWnd = 0, $iType = 0) #cs https://groups.google.com/forum/?hl=en&fromgroups=#!topic/microsoft.public.vc.mfc/HafQr4gIRY0 The problem is that GetOpenFileName changes the current directory to the last browsed one. The current directory and any of its parents cannot be deleted. #ce If Not $sInitDir Then If Not FileExists("\\?\" & $sInitDir) Then $sInitDir = "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" ; CLSID for "My Computer" EndIf Local $sWorkingDir = @WorkingDir If $iType = 1 Then $f_CDN__FileDialogsEx_Start = 1 Local $sFilename = _FileOpenDialogEx($sTitle, $sInitDir, $sFilter, BitOR($OFN_ENABLESIZING, $OFN_ALLOWMULTISELECT), $sDefaultName, $hWnd) Else Local $sFilename = FileOpenDialog($sTitle, $sInitDir, $sFilter, $iOptions, $sDefaultName, $hWnd) EndIf Local $iError = @error FileChangeDir($sWorkingDir) Return SetError($iError, 0, $sFilename) EndFunc ;==>_FileOpenDialog_Ex Func _FileOpenDialogEx($sTitle = "", $sInitDir = "", $sFilter = "All Files (*.*)", $iOptions = 0, $sDefaultName = "", $hParent = 0, $hTemplate = 0, $sTemplateName = "") Local $sRet = _GetOpenSaveFileName('GetOpenFileNameW', $hTemplate, $sTemplateName, $hParent, $sTitle, $sInitDir, $sFilter, $iOptions, $sDefaultName) If @error Then SetError(@error) Return $sRet EndFunc ;==>_FileOpenDialogEx Func _GetOpenSaveFileName($sFunction, $hTemplate, $sTemplateName, $hParent, $sTitle, $sInitDir, $sFilter, $iOptions, $sDefaultName) Local $taFilters, $tFile, $_OFN_HookProc = 0, $iFlagsEx = 0, $iFlagsForced = BitOR($OFN_EXPLORER, $OFN_HIDEREADONLY, $OFN_NODEREFERENCELINKS) $iOptions = BitOR($iFlagsForced, $iOptions) If BitAND($iOptions, $OFN_EX_NOPLACESBAR) Then $iOptions = BitXOR($iOptions, $OFN_EX_NOPLACESBAR) $iFlagsEx = $OFN_EX_NOPLACESBAR EndIf Local $tagBuffer = "wchar[4096]", $iBufferSize = 4095 Local $aFilters = StringSplit($sFilter, "|"), $saFilters = "", $tagFilters = "", $aFiltSplit, $i For $i = 1 To $aFilters[0] $aFiltSplit = StringRegExp($aFilters[$i], "(?U)\A\h*(.+)\h*\((.*)\)", 1) $saFilters &= $aFilters[$i] & Chr(0) & $aFiltSplit[1] & Chr(0) Next $tagFilters = "wchar[" & StringLen($saFilters) + 3 & "]" $taFilters = DllStructCreate($tagFilters) DllStructSetData($taFilters, 1, $saFilters) Local $iFileBufferSize = 32768 * 10 Local $tagFileBuffer = "wchar[" & $iFileBufferSize & "]" $tFile = DllStructCreate($tagFileBuffer) ; Win2000/XP: should be 32k for ansi, unlimited for unicode If $sDefaultName <> "" Then DllStructSetData($tFile, 1, $sDefaultName) Local $tOFN = DllStructCreate('dword lStructSize;hwnd hwndOwner;hwnd hInstance;' & _ 'ptr lpstrFilter;ptr lpstrCustomFilter;dword nMaxCustFilter;dword nFilterIndex;' & _ 'ptr lpstrFile;dword nMaxFile;ptr lpstrFileTitle;dword nMaxFileTitle;ptr lpstrInitialDir;ptr lpstrTitle;' & _ 'dword Flags;short nFileOffset;short nFileExtension;ptr lpstrDefExt;dword lCustData;ptr lpfnHook;ptr lpTemplateName;' & _ 'dword Reserved[2];dword FlagsEx') DllStructSetData($tOFN, 'lStructSize', DllStructGetSize($tOFN)) If IsHWnd($hParent) Then DllStructSetData($tOFN, 'hwndOwner', $hParent) DllStructSetData($tOFN, 'lpstrFilter', DllStructGetPtr($taFilters)) DllStructSetData($tOFN, 'nFilterIndex', 1) DllStructSetData($tOFN, 'lpstrFile', DllStructGetPtr($tFile)) DllStructSetData($tOFN, 'nMaxFile', $iFileBufferSize) DllStructSetData($tOFN, 'FlagsEx', $iFlagsEx) If $hTemplate <> 0 Then If $sTemplateName <> "" Then $iOptions = BitOR($iOptions, $OFN_ENABLETEMPLATE) DllStructSetData($tOFN, 'hInstance', $hTemplate) Local $tTemplateName = DllStructCreate($tagBuffer) ; 'char[256]') DllStructSetData($tTemplateName, 1, $sTemplateName) DllStructSetData($tOFN, 'lpTemplateName', DllStructGetPtr($tTemplateName)) Else $iOptions = BitOR($iOptions, $OFN_ENABLETEMPLATEHANDLE) DllStructSetData($tOFN, 'hInstance', $hTemplate) EndIf EndIf $iOptions = BitOR($iOptions, $OFN_ENABLEHOOK, $OFN_ENABLEINCLUDENOTIFY) $_OFN_HookProc = DllCallbackRegister("_OFN_HookProc", "int", "hwnd;uint;wparam;lparam") DllStructSetData($tOFN, 'lpfnHook', DllCallbackGetPtr($_OFN_HookProc)) If $sTitle <> "" Then Local $tTitle = DllStructCreate($tagBuffer) DllStructSetData($tTitle, 1, String($sTitle)) DllStructSetData($tOFN, "lpstrTitle", DllStructGetPtr($tTitle)) EndIf If $sInitDir <> "" Then Local $tInitDir = DllStructCreate($tagBuffer) DllStructSetData($tInitDir, 1, String($sInitDir)) DllStructSetData($tOFN, "lpstrInitialDir", DllStructGetPtr($tInitDir)) EndIf DllStructSetData($tOFN, 'Flags', $iOptions) Local $aRet = DllCall('comdlg32.dll', 'int', $sFunction, 'ptr', DllStructGetPtr($tOFN)) Local $iError = @error If $_OFN_HookProc <> 0 Then DllCallbackFree($_OFN_HookProc) If $iError Then Return SetError(2, $iError, "") ElseIf $aRet[0] Then Local $iChar = 1 While $iChar < $iFileBufferSize + 1 If DllStructGetData($tFile, 1, $iChar) = "" Then If DllStructGetData($tFile, 1, $iChar + 1) = "" Then ExitLoop DllStructSetData($tFile, 1, "|", $iChar) EndIf $iChar += 1 WEnd Return SetError(0, 0, DllStructGetData($tFile, 1)) Else Return SetError(1, 0, "") EndIf EndFunc ;==>_GetOpenSaveFileName Volatile Func _OFN_HookProc($hWnd, $Msg, $wParam, $lParam) Switch $Msg Case $WM_NOTIFY Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR $tNMHDR = DllStructCreate("hwnd hWndFrom;int idFrom;int code", $lParam) $hWndFrom = DllStructGetData($tNMHDR, "hWndFrom") $iIDFrom = DllStructGetData($tNMHDR, "idFrom") $iCode = DllStructGetData($tNMHDR, "code") Switch $iCode Case $CDN_FOLDERCHANGE If $f_CDN__FileDialogsEx_Start Then ; if executing first time Local $aRet = DllCall('user32.dll', 'hwnd', 'FindWindowEx', 'hwnd', $hWndFrom, 'hwnd', 0, 'str', "SHELLDLL_DefView", 'str', "") If $aRet[0] = 0 Then ConsoleWrite("_OFN_HookProc" & @TAB & "_FindWindowEx Error" & @CRLF) Else DllCall('user32.dll', 'int', 'SendMessage', 'hwnd', $aRet[0], 'uint', $WM_COMMAND, 'wparam', 0x702c, 'lparam', 0) ; $ODM_VIEW_DETAIL EndIf WinMove($hWndFrom, "", @DesktopWidth / 2 - 650 / 2, @DesktopHeight / 2 - 600 / 2, 650, 600) $f_CDN__FileDialogsEx_Start = 0 ; to make sure these tweaks happens only once. EndIf EndSwitch Case Else EndSwitch Return 0 EndFunc ;==>_OFN_HookProc Musashi and AutoFan 2 OS: Win10-22H2 - 64bit - German, AutoIt Version: 3.3.16.1, AutoIt Editor: SciTE, Website: https://funk.eu AMT - Auto-Movie-Thumbnailer (2024-Oct-13) BIC - Batch-Image-Cropper (2023-Apr-01) COP - Color Picker (2009-May-21) DCS - Dynamic Cursor Selector (2024-Oct-13) HMW - Hide my Windows (2024-Oct-19) HRC - HotKey Resolution Changer (2012-May-16) ICU - Icon Configuration Utility (2018-Sep-16) SMF - Search my Files (2025-May-18) - THE file info and duplicates search tool SSD - Set Sound Device (2017-Sep-16)
AutoFan Posted April 23, 2020 Author Posted April 23, 2020 13 hours ago, KaFu said: Here's a customized version I use in SMF. Return buffer size is defined in row containing Local $iFileBufferSize = 32768 * 10 expandcollapse popup#include <Array.au3> #include <WindowsConstants.au3> #include <WinAPIDlg.au3> Global $f_CDN__FileDialogsEx_Start = 1 $sFile = _FileOpenDialog_Ex("SMF _FileOpenDialog_Ex", @ScriptDir, "All (*.*)", 1 + 2, "", 0, 1) $aFiles = StringSplit($sFile, "|") _ArrayDisplay($aFiles) Func _FileOpenDialog_Ex($sTitle, $sInitDir, $sFilter, $iOptions = 0, $sDefaultName = "", $hWnd = 0, $iType = 0) #cs https://groups.google.com/forum/?hl=en&fromgroups=#!topic/microsoft.public.vc.mfc/HafQr4gIRY0 The problem is that GetOpenFileName changes the current directory to the last browsed one. The current directory and any of its parents cannot be deleted. #ce If Not $sInitDir Then If Not FileExists("\\?\" & $sInitDir) Then $sInitDir = "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" ; CLSID for "My Computer" EndIf Local $sWorkingDir = @WorkingDir If $iType = 1 Then $f_CDN__FileDialogsEx_Start = 1 Local $sFilename = _FileOpenDialogEx($sTitle, $sInitDir, $sFilter, BitOR($OFN_ENABLESIZING, $OFN_ALLOWMULTISELECT), $sDefaultName, $hWnd) Else Local $sFilename = FileOpenDialog($sTitle, $sInitDir, $sFilter, $iOptions, $sDefaultName, $hWnd) EndIf Local $iError = @error FileChangeDir($sWorkingDir) Return SetError($iError, 0, $sFilename) EndFunc ;==>_FileOpenDialog_Ex Func _FileOpenDialogEx($sTitle = "", $sInitDir = "", $sFilter = "All Files (*.*)", $iOptions = 0, $sDefaultName = "", $hParent = 0, $hTemplate = 0, $sTemplateName = "") Local $sRet = _GetOpenSaveFileName('GetOpenFileNameW', $hTemplate, $sTemplateName, $hParent, $sTitle, $sInitDir, $sFilter, $iOptions, $sDefaultName) If @error Then SetError(@error) Return $sRet EndFunc ;==>_FileOpenDialogEx Func _GetOpenSaveFileName($sFunction, $hTemplate, $sTemplateName, $hParent, $sTitle, $sInitDir, $sFilter, $iOptions, $sDefaultName) Local $taFilters, $tFile, $_OFN_HookProc = 0, $iFlagsEx = 0, $iFlagsForced = BitOR($OFN_EXPLORER, $OFN_HIDEREADONLY, $OFN_NODEREFERENCELINKS) $iOptions = BitOR($iFlagsForced, $iOptions) If BitAND($iOptions, $OFN_EX_NOPLACESBAR) Then $iOptions = BitXOR($iOptions, $OFN_EX_NOPLACESBAR) $iFlagsEx = $OFN_EX_NOPLACESBAR EndIf Local $tagBuffer = "wchar[4096]", $iBufferSize = 4095 Local $aFilters = StringSplit($sFilter, "|"), $saFilters = "", $tagFilters = "", $aFiltSplit, $i For $i = 1 To $aFilters[0] $aFiltSplit = StringRegExp($aFilters[$i], "(?U)\A\h*(.+)\h*\((.*)\)", 1) $saFilters &= $aFilters[$i] & Chr(0) & $aFiltSplit[1] & Chr(0) Next $tagFilters = "wchar[" & StringLen($saFilters) + 3 & "]" $taFilters = DllStructCreate($tagFilters) DllStructSetData($taFilters, 1, $saFilters) Local $iFileBufferSize = 32768 * 10 Local $tagFileBuffer = "wchar[" & $iFileBufferSize & "]" $tFile = DllStructCreate($tagFileBuffer) ; Win2000/XP: should be 32k for ansi, unlimited for unicode If $sDefaultName <> "" Then DllStructSetData($tFile, 1, $sDefaultName) Local $tOFN = DllStructCreate('dword lStructSize;hwnd hwndOwner;hwnd hInstance;' & _ 'ptr lpstrFilter;ptr lpstrCustomFilter;dword nMaxCustFilter;dword nFilterIndex;' & _ 'ptr lpstrFile;dword nMaxFile;ptr lpstrFileTitle;dword nMaxFileTitle;ptr lpstrInitialDir;ptr lpstrTitle;' & _ 'dword Flags;short nFileOffset;short nFileExtension;ptr lpstrDefExt;dword lCustData;ptr lpfnHook;ptr lpTemplateName;' & _ 'dword Reserved[2];dword FlagsEx') DllStructSetData($tOFN, 'lStructSize', DllStructGetSize($tOFN)) If IsHWnd($hParent) Then DllStructSetData($tOFN, 'hwndOwner', $hParent) DllStructSetData($tOFN, 'lpstrFilter', DllStructGetPtr($taFilters)) DllStructSetData($tOFN, 'nFilterIndex', 1) DllStructSetData($tOFN, 'lpstrFile', DllStructGetPtr($tFile)) DllStructSetData($tOFN, 'nMaxFile', $iFileBufferSize) DllStructSetData($tOFN, 'FlagsEx', $iFlagsEx) If $hTemplate <> 0 Then If $sTemplateName <> "" Then $iOptions = BitOR($iOptions, $OFN_ENABLETEMPLATE) DllStructSetData($tOFN, 'hInstance', $hTemplate) Local $tTemplateName = DllStructCreate($tagBuffer) ; 'char[256]') DllStructSetData($tTemplateName, 1, $sTemplateName) DllStructSetData($tOFN, 'lpTemplateName', DllStructGetPtr($tTemplateName)) Else $iOptions = BitOR($iOptions, $OFN_ENABLETEMPLATEHANDLE) DllStructSetData($tOFN, 'hInstance', $hTemplate) EndIf EndIf $iOptions = BitOR($iOptions, $OFN_ENABLEHOOK, $OFN_ENABLEINCLUDENOTIFY) $_OFN_HookProc = DllCallbackRegister("_OFN_HookProc", "int", "hwnd;uint;wparam;lparam") DllStructSetData($tOFN, 'lpfnHook', DllCallbackGetPtr($_OFN_HookProc)) If $sTitle <> "" Then Local $tTitle = DllStructCreate($tagBuffer) DllStructSetData($tTitle, 1, String($sTitle)) DllStructSetData($tOFN, "lpstrTitle", DllStructGetPtr($tTitle)) EndIf If $sInitDir <> "" Then Local $tInitDir = DllStructCreate($tagBuffer) DllStructSetData($tInitDir, 1, String($sInitDir)) DllStructSetData($tOFN, "lpstrInitialDir", DllStructGetPtr($tInitDir)) EndIf DllStructSetData($tOFN, 'Flags', $iOptions) Local $aRet = DllCall('comdlg32.dll', 'int', $sFunction, 'ptr', DllStructGetPtr($tOFN)) Local $iError = @error If $_OFN_HookProc <> 0 Then DllCallbackFree($_OFN_HookProc) If $iError Then Return SetError(2, $iError, "") ElseIf $aRet[0] Then Local $iChar = 1 While $iChar < $iFileBufferSize + 1 If DllStructGetData($tFile, 1, $iChar) = "" Then If DllStructGetData($tFile, 1, $iChar + 1) = "" Then ExitLoop DllStructSetData($tFile, 1, "|", $iChar) EndIf $iChar += 1 WEnd Return SetError(0, 0, DllStructGetData($tFile, 1)) Else Return SetError(1, 0, "") EndIf EndFunc ;==>_GetOpenSaveFileName Volatile Func _OFN_HookProc($hWnd, $Msg, $wParam, $lParam) Switch $Msg Case $WM_NOTIFY Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR $tNMHDR = DllStructCreate("hwnd hWndFrom;int idFrom;int code", $lParam) $hWndFrom = DllStructGetData($tNMHDR, "hWndFrom") $iIDFrom = DllStructGetData($tNMHDR, "idFrom") $iCode = DllStructGetData($tNMHDR, "code") Switch $iCode Case $CDN_FOLDERCHANGE If $f_CDN__FileDialogsEx_Start Then ; if executing first time Local $aRet = DllCall('user32.dll', 'hwnd', 'FindWindowEx', 'hwnd', $hWndFrom, 'hwnd', 0, 'str', "SHELLDLL_DefView", 'str', "") If $aRet[0] = 0 Then ConsoleWrite("_OFN_HookProc" & @TAB & "_FindWindowEx Error" & @CRLF) Else DllCall('user32.dll', 'int', 'SendMessage', 'hwnd', $aRet[0], 'uint', $WM_COMMAND, 'wparam', 0x702c, 'lparam', 0) ; $ODM_VIEW_DETAIL EndIf WinMove($hWndFrom, "", @DesktopWidth / 2 - 650 / 2, @DesktopHeight / 2 - 600 / 2, 650, 600) $f_CDN__FileDialogsEx_Start = 0 ; to make sure these tweaks happens only once. EndIf EndSwitch Case Else EndSwitch Return 0 EndFunc ;==>_OFN_HookProc Wow, worked flawlessly ! Thanks a lot !
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now