Jump to content

File Open/Save Dialogs customization


Siao
 Share

Recommended Posts

Started this as solution to this request.

There are already some of these GetOpenFileName/GetSaveFileName API wrappers around, for example, in this topic, and I've just noticed that they are even included in post v.3.2.10.0 beta.

However, all of them are chopped down versions that don't support Unicode (which is pretty sad) and don't use any of the advanced features.

Here are the funcs I wrote,

_FileOpenDialogEx()

_FileSaveDialogEx()

Not totally fool-proof, but usable:

_FileDialogsEx.au3

(when using latest betas instead of v.3.2.10 there will be a bunch of "previously declared" errors for OFN_* constants, so in that case comment them out.)

And a couple of examples how to use it.

;   _FileDialogsEx.au3 example #1:
;   create big resizeable file open dialog, defaulting to thumbnails view
;   demonstrates how to set size/position of dialog window, how to set default view mode for listview.

#include <WindowsConstants.au3>
#include <WinAPI.au3>
#include "_FileDialogsEx.au3"

Global $f_CDN_Start = 1

$Return = _FileOpenDialogEx("Open picture", @WindowsDir & "\Web\Wallpaper", "All Files (*.*)", BitOR($OFN_ENABLESIZING,$OFN_ALLOWMULTISELECT), "", 0, "_OFN_HookProc")
If @error Then 
    ConsoleWrite('No file selected.' & @CRLF)
Else
    ConsoleWrite($Return & @CRLF)
EndIf

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_INITDONE
                Case $CDN_FOLDERCHANGE
                    If $f_CDN_Start Then;if executing first time
                        Local $hODLV = _FindWindowEx($hWndFrom, 0, "SHELLDLL_DefView", "")
                        If $hODLV <> 0 Then
                            DllCall('user32.dll','int','SendMessage','hwnd',$hODLV,'uint',$WM_COMMAND,'wparam',$ODM_VIEW_THUMBS,'lparam',0)
                        EndIf
                        WinMove($hWndFrom, "", 0,0, 800,600, 0)
                        $f_CDN_Start = 0;to make sure these tweaks happens only once.
                    EndIf
                Case $CDN_SELCHANGE
                Case $CDN_FILEOK
            EndSwitch
        Case Else
    EndSwitch
EndFunc
Func _FindWindowEx($hWndParent,$hWndChildAfter,$sClassName,$sWinTitle="")
    Local $aRet = DllCall('user32.dll','hwnd','FindWindowEx', 'hwnd', $hWndParent,'hwnd',$hWndChildAfter,'str',$sClassName,'str',$sWinTitle)
    If $aRet[0] = 0 Then ConsoleWrite('_FindWindowEx() Error : ' & _WinAPI_GetLastErrorMessage())
    Return $aRet[0]
EndFunc

Exit

;   _FileDialogsEx.au3 example #2:
;   simple text encoding converter.
;   demonstrates how to change text of dialog controls and the usage of custom templates.

#include <WindowsConstants.au3>
#include <WinAPI.au3>
#include "_FileDialogsEx.au3"

Global Const $CBN_SELCHANGE = 1
Global $sEncoding

$Input = _FileOpenDialogEx("Select text file to convert", @MyDocumentsDir, "Text Files (*.txt)|All Files (*.*)", BitOR($OFN_FILEMUSTEXIST,$OFN_PATHMUSTEXIST,$OFN_EX_NOPLACESBAR,$OFN_DONTADDTORECENT), "", 0, "_FileOpen_HookProc")
If @error Then 
    MsgBox(0,'Error','No file selected.' & @CRLF)
Else
    ConsoleWrite($Input & @CRLF)
    $sText = FileRead($Input)
    If Not @error Then
;here we use Notepad's dialog resource for our "Encoding" template
        $hNotepad = _WinAPI_LoadLibrary(@WindowsDir & "\notepad.exe")
        $Output = _FileSaveDialogEx("", @MyDocumentsDir, "Text Files (*.txt)", BitOR($OFN_OVERWRITEPROMPT,$OFN_PATHMUSTEXIST,$OFN_DONTADDTORECENT), "", 0, "_FileSave_HookProc", $hNotepad, 'NPENCODINGDIALOG')
        _WinAPI_FreeLibrary($hNotepad)
        Switch $sEncoding
            Case "Unicode"
                $iMode = 34
            Case "Unicode big endian"
                $iMode = 66
            Case "UTF-8"
                $iMode = 130
            Case Else;ANSI
                $iMode = 2
        EndSwitch
        $hFile = FileOpen($Output,$iMode)
        FileWrite($hFile, $sText)
        FileClose($hFile)
    EndIf
EndIf

Func _FileOpen_HookProc($hWnd, $Msg, $wParam, $lParam)
    Switch $Msg
        Case $WM_INITDIALOG
            Local $hDlg = _WinAPI_GetParent($hWnd), $lParamType = "str"
            If @Unicode Then $lParamType = "w" & $lParamType
            _SendMessage($hDlg, $CDM_SETCONTROLTEXT, $stc3, "File name:", 0, "int", $lParamType)
            _SendMessage($hDlg, $CDM_SETCONTROLTEXT, $stc2, "File type:", 0, "int", $lParamType)
        Case Else
    EndSwitch
EndFunc
Func _FileSave_HookProc($hWnd, $Msg, $wParam, $lParam)
    Switch $Msg
        Case $WM_INITDIALOG
            Local $hDlg = _WinAPI_GetParent($hWnd), $lParamType = "str"
            If @Unicode Then $lParamType = "w" & $lParamType
            _SendMessage($hDlg, $CDM_SETCONTROLTEXT, $stc3, "File name:", 0, "int", $lParamType)
            _SendMessage($hDlg, $CDM_SETCONTROLTEXT, $stc2, "File type:", 0, "int", $lParamType)
            ControlCommand($hWnd, "", '[CLASS:ComboBox;Instance:1]', "AddString", 'ANSI')
            ControlCommand($hWnd, "", '[CLASS:ComboBox;Instance:1]', "AddString", 'Unicode')
            ControlCommand($hWnd, "", '[CLASS:ComboBox;Instance:1]', "AddString", 'Unicode big endian')
            ControlCommand($hWnd, "", '[CLASS:ComboBox;Instance:1]', "AddString", 'UTF-8')
            ControlCommand($hWnd, "", '[CLASS:ComboBox;Instance:1]', "SelectString", 'ANSI')
        Case $WM_COMMAND
            Local $hComboEnc = ControlGetHandle($hWnd, "", '[CLASS:ComboBox;Instance:1]'), $iCode = BitShift($wParam, 16)
            If $lParam = $hComboEnc And $iCode = $CBN_SELCHANGE Then
                $sEncoding = ControlCommand($hWnd, "", '[CLASS:ComboBox;Instance:1]', "GetCurrentSelection", "")
            EndIf
        Case Else
    EndSwitch
EndFunc

Exit
Edited by Siao

"be smart, drink your wine"

Link to comment
Share on other sites

"Doesn't run" is a bit of an overstatement. I warned about this in my first post (1st sentence right below the attached file). And it's a simple matter of opening _FileDialogsEx.au3 in Scite, selecting all $OFN_* constants with mouse and block-commenting (Ctrl+Q) them. I think that shouldn't be too complicated for someone who's been around this long? :)

Edited by Siao

"be smart, drink your wine"

Link to comment
Share on other sites

Hi,

there is also this : @AutoItUnicode

Update the first post an many more people will use your script.

Mega

Edited by Xenobiologist

Scripts & functions Organize Includes Let Scite organize the include files

Yahtzee The game "Yahtzee" (Kniffel, DiceLion)

LoginWrapper Secure scripts by adding a query (authentication)

_RunOnlyOnThis UDF Make sure that a script can only be executed on ... (Windows / HD / ...)

Internet-Café Server/Client Application Open CD, Start Browser, Lock remote client, etc.

MultipleFuncsWithOneHotkey Start different funcs by hitting one hotkey different times

Link to comment
Share on other sites

there is also this : @AutoItUnicode

Update the first post an many more people will use your script.

Those many people who don't understand the concept of beta and can't handle the nuisance it sometimes brings, shouldn't be running beta in first place.

Currently the official version still is v.3.2.10.0 and that's what I'm willing to support. What I'm not willing to do is to keep the track of whatever new constants are included or whatever function/macro names change in each beta version for whatever reasons, and to provide separate files for each version. That would only add to confusion.

"be smart, drink your wine"

Link to comment
Share on other sites

  • 1 month later...

I am using your code.

I get the following error:

>Running:(3.2.10.0):C:\Program Files\AutoIt3\autoit3.exe "C:\autoit\scripts\Working Copy of Wireshark Extractor.au3"

C:\Program Files\AutoIt3\Include\_FileDialogsEx.au3 (215) : ==> Badly formatted "Func" statement.:

$_OFN_HookProc = DllCallbackRegister($sHookProc, "int", "hwnd;uint;wparam;lparam")

????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????4

->07:32:33 AutoIT3.exe ended.rc:1

>Exit code: 1 Time: 5.834

Could you please help me correct or understand the error?

Thanx alot!

Excerpt from my code:

#include <WindowsConstants.au3>

#include <WinAPI.au3>

#include <GuiTreeView.au3>

#include <String.au3>

#include <_FileDialogsEx.au3>

Global $f_CDN_Start = 1

$Return = _FileOpenDialogEx("Select Capture File:", $capture_src, "All Files (*.*)", BitOR($OFN_ENABLESIZING,$OFN_ALLOWMULTISELECT), "", 0, "_OFN_HookProc")

If @error Then

ConsoleWrite('No file selected.' & @CRLF)

Else

ConsoleWrite($Return & @CRLF)

EndIf

Link to comment
Share on other sites

$Return = _FileOpenDialogEx("Select Capture File:", $capture_src, "All Files (*.*)", BitOR($OFN_ENABLESIZING,$OFN_ALLOWMULTISELECT), "", 0, "_OFN_HookProc")

If you specify a callback function, it would make sense to actually have that function somewhere in your script...

Edited by Siao

"be smart, drink your wine"

Link to comment
Share on other sites

  • 3 weeks later...

Apperently I can't change the position '0,0' in this line from the first script.

WinMove($hWndFrom, "", 0,0, 800,600, 0)

I using v.3.2.10.0. What am I doing wrong?

I'm getting:

!>12:44:16 AutoIT3.exe ended.rc:-1073741676

[Edit: Without the last '0' it works fine]

Edited by Tin2tin
Link to comment
Share on other sites

  • 4 weeks later...

Why is this unable to search the root directory? "C:" and "C:\" send the cpu into overdrive and then craps out the script. "C:\" works with the regular opendialog function. Is there a workaround?

Post example. Edited by Siao

"be smart, drink your wine"

Link to comment
Share on other sites

I don't know how or why, but all of a sudden I'm not getting the cpu overloads anymore. I'll watch it for now, and if it comes back I'll post...but there would be no need for me to post an example because it was happening with the provided script example. One more question Siao, is it possible to style the opendialog? I started another post if it is possible and you know how. http://www.autoitscript.com/forum/index.php?showtopic=69809

Thanks.

Link to comment
Share on other sites

  • 1 month later...

I've upgraded to 3.2.12.0 and taken these dublicate functions out:

;~ Global Const $OFN_ALLOWMULTISELECT = 0x200
;~ Global Const $OFN_CREATEPROMPT = 0x2000
;~ Global Const $OFN_DONTADDTORECENT = 0x2000000
;~ Global Const $OFN_ENABLEHOOK = 0x20
;~ Global Const $OFN_ENABLEINCLUDENOTIFY = 0x400000
;~ Global Const $OFN_ENABLESIZING = 0x800000
;~ Global Const $OFN_ENABLETEMPLATE = 0x40
;~ Global Const $OFN_ENABLETEMPLATEHANDLE = 0x80
;~ Global Const $OFN_EXPLORER = 0x80000
;~ Global Const $OFN_EXTENSIONDIFFERENT = 0x400
;~ Global Const $OFN_EX_NOPLACESBAR = 0x1
;~ Global Const $OFN_FILEMUSTEXIST = 0x1000
;~ Global Const $OFN_FORCESHOWHIDDEN = 0x10000000
;~ Global Const $OFN_HIDEREADONLY = 0x4
;~ Global Const $OFN_LONGNAMES = 0x200000
;~ Global Const $OFN_NOCHANGEDIR = 0x8
;~ Global Const $OFN_NODEREFERENCELINKS = 0x100000
;~ Global Const $OFN_NOLONGNAMES = 0x40000
;~ Global Const $OFN_NONETWORKBUTTON = 0x20000
;~ Global Const $OFN_NOREADONLYRETURN = 0x8000
;~ Global Const $OFN_NOTESTFILECREATE = 0x10000
;~ Global Const $OFN_NOVALIDATE = 0x100
;~ Global Const $OFN_OVERWRITEPROMPT = 0x2
;~ Global Const $OFN_PATHMUSTEXIST = 0x800
;~ Global Const $OFN_READONLY = 0x1
;~ Global Const $OFN_SHAREWARN = 0
;~ Global Const $OFN_SHOWHELP = 0x10

However I still get an error:

ERROR: undefined macro. Local $taFilters, $tFile, $_OFN_HookProc = 0, $fUnicode = @Unicode,

What is the definition af this macro?

Link to comment
Share on other sites

From AutoIt helpfile, v3.2.12.0 changelog:

Changed: @Unicode renamed in @AutoItUnicode. @Unicode is an alias for now. It will be removed > 3.2.14.0

"be smart, drink your wine"

Link to comment
Share on other sites

  • 8 months later...

though old, i want to reactivate this thread.

what a great UDF !!!

the hook also enables e.g. to reposition every messagebox !

i have an advanced question: (maybe siao is around):

i would like to use the hook to obtain the currently selected item and its full path (in a filesave/fileopen dialog). in msdn i found the specaial constants CDM_GETFILEPATH and CDM_GETFOLDERPATH, but i do not succeed in using them.

but i found some examples from delphi, vb and c++. maybe anyone can make it work in autoit:

' here is the code if just one file is selected and for multiple file selection I'll add code later

sbuff = String$(2 * MAX_LEN + 2, 0)

strlen = apiSendMessage(hWndParent, CDM_GETFILEPATH, 2 * MAX_LEN, ByVal sbuff)

If strlen > 0 Then

sbuff = Left$(sbuff, strlen - 1)

Form_frmIntro.lsItemToAddToProject.RowSource = _

Form_frmIntro.lsItemToAddToProject.RowSource + _

sbuff + ";"

End If

blnRetVal = True

Call apiSetWindowLong(hwnd, DWL_MSGRESULT, 1)

UINT CALLBACK Dialog_HookProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam)

{

switch (Msg) {

case WM_NOTIFY : {

if (((OFNOTIFY*)lParam)->hdr.code == CDN_SELCHANGE) {

char FileName[MAX_PATH];

SendMessage(GetParent(Wnd), CDM_GETFILEPATH, sizeof(FileName), Integer(&FileName));

Dialog_PreviewFile(FileName, Wnd);

return true;}

case WM_COMMAND :{

UpdateWindow(Wnd);

return true;}}

return false;

}

Case WM_NOTIFY

CopyMemory tNMH, ByVal lParam, Len(tNMH)

Select Case tNMH.Code

' Auswahl gewechselt

Case CDN_SELCHANGE

s = GetDlgPath(CDM_GETFILEPATH, hWndDlg)

If PathIsDirectory(s) = False And _

CBool(PathFileExists(s)) Then _

RaiseEvent FileChanged(s)

' Ordner hat sich geändert

Case CDN_FOLDERCHANGE

RaiseEvent FolderChanged(GetDlgPath(CDM_GETFOLDERPATH, _

hWndDlg))

' OK geklickt

Case CDN_FILEOK

RaiseEvent PressedOKButton

'Case CDN_HELP

' RaiseEvent PressedHelpButton

' Es gibt keinen Help-Button...!?

Case CDN_TYPECHANGE

' Datei-Typ-Liste hat gewechselt

End Select

' Das wars...!

Case WM_DESTROY

If Not m_cControl Is Nothing Then

' Das Control wieder auf den Platz zurücksetzen

SetParent m_cControl.hWnd, OldhWnd

m_cControl.Visible = False

End If

RaiseEvent DialogClosed

End Select

End Sub

' Hilfsfunktion zur Bestimmung der Funktions-Adresse

Private Function addr(ByVal a As Long) As Long

addr = a

End Function

' Fragt den aktuellen Datei- oder Ordner-Pfad ab

' (je nach Konstante)

Private Function GetDlgPath(ByVal lConst As Long, hWndDlg As Long) As String

Dim sBuf As String

Dim lPos As Long

Dim hWnd As Long

hWnd = GetParent(hWndDlg)

sBuf = String(MAX_PATH, 0)

SendMessageString hWnd, lConst, MAX_PATH, sBuf

lPos = InStr(1, sBuf, vbNullChar)

If lPos > 0 Then

GetDlgPath = Left(sBuf, lPos - 1)

Else

GetDlgPath = sBuf

End If

End Function

some sources:

here

here

here

here

thank you very much in advance !!!!

please help !!

j.

Edited by jennico
Spoiler

I actively support Wikileaks | Freedom for Julian Assange ! | Defend freedom of speech ! | Fight censorship ! | I will not silence.OixB7.jpgDon't forget this IP: 213.251.145.96

 

Link to comment
Share on other sites

okay, i worked out a different method. working fine:

try it out !

btw: the GuiListView.au3 lacks a satisfying GetCursorSelect function, so i made one

GetSelectionFromDialogWindow_UDF.au3

;----------------------------------------------------------------------------
; Function:     GetSelectionFromDialogWindow($DialogWindowTitle = "[CLASS:#32770]", $SpecialFolderSwitch = True, $MultiSelectionSwitch = True)
; Description:  Retrieves full path of selected item in a standard GetFile dialog box.
; Parameters:   $DialogWindowTitle : Title of Dialog Window (Default = "[CLASS:#32770]"
;               $SpecialFolderSwitch : Switch = True (Default) for not return special folder items. (if False no support for full path.)
;               $MultiSelectionSwitch : Switch = True (Default) for not return muliple selections. (if False only the highest selected will be returned.)
; Remarks:      works for external standard dialog boxes.
;               in order to make it work with internal dialogs, use it inside the hook procedure (see above).
;               @Extended returns the current file selection (0 based, -1 = no selection)
; Author:       copyright by jennico 2009
;----------------------------------------------------------------------------

#include-once
#include <GuiListView.au3>

;Global Const $CB_ERR = -1
;Global Const $CB_GETCOUNT = 0x146
If Not IsDeclared("CB_GETCURSEL") Then Global Const $CB_GETCURSEL = 0x147
If Not IsDeclared("CB_GETLBTEXT") Then Global Const $CB_GETLBTEXT = 0x148

Global Const $arDrives = DriveGetDrive("ALL")


;------------comment out for use as UDF and pass dialog title (if available)
$timer = TimerInit();
MsgBox(0, Round(TimerDiff($timer) / 1000, 5), GetSelectionFromDialogWindow() & _
        "     " & @CRLF & @CRLF & "      =>  (Selected Item # : " & @extended & ")     ")
;------------comment out for use as UDF


Func GetSelectionFromDialogWindow($DialogWindowTitle = "[CLASS:#32770]", $SpecialFolderSwitch = True, $MultiSelectionSwitch = True)
    Local $hwnd = WinGetHandle($DialogWindowTitle);pass window title
    Local $path, $selected = -1
    Local $hlistview = ControlGetHandle($hwnd, "", "SysListView321")
    Local $hcombobox = ControlGetHandle($hwnd, "", "ComboBox1")
    Local $ret = DllCall("user32.dll", "int", "SendMessage", "hwnd", $hcombobox, "int", $CB_GETCURSEL, "int", 0, "int", 0)
    For $i = 0 To $ret[0]
        $p = DllStructCreate("char[260]")
        DllCall("user32.dll", "int", "SendMessage", "hwnd", $hcombobox, "int", $CB_GETLBTEXT, "int", $i, "ptr", DllStructGetPtr($p))
        $folder = DllStructGetData($p, 1)
        $path &= "\" & $folder
        If StringInStr($folder, ":") = 0 Then ContinueLoop
        For $j = 1 To $arDrives[0]
            If StringInStr($folder, $arDrives[$j]) Then
                $path = StringUpper($arDrives[$j])
                ExitLoop
            EndIf
        Next
    Next
    If $SpecialFolderSwitch And StringInStr($path, ":") = 0 Then $path = "";filter for special folders
    If $path Then
        $selected = _GUICtrlListView_GetCursorSelect($hlistview, $MultiSelectionSwitch)
        $path &= "\" & _GUICtrlListView_GetItemText ($hlistview, $selected)
    EndIf
    Return SetExtended($selected, $path)
EndFunc   ;==>GetSelectionFromDialogWindow

Func _GUICtrlListView_GetCursorSelect($hwnd, $imode)
    Local $ret = -1, $iCount = DllCall("user32.dll", "lparam", "SendMessage", "hwnd", $hwnd, "int", $LVM_GETITEMCOUNT, "wparam", 0, "lparam", 0)
    For $i = 0 To $iCount[0] - 1
        $state = DllCall("user32.dll", "lparam", "SendMessage", "hwnd", $hwnd, "int", $LVM_GETITEMSTATE, "wparam", $i, "lparam", $LVIS_SELECTED)
        If $state[0] Then
            If $imode And $ret > -1 Then Return -1;filter for multiselection
            $ret = $i
        EndIf
    Next
    Return $ret
EndFunc   ;==>GUICtrlListView_GetSelected

have fun !

j.

Edit: forgot to mention: you need an open FileSave / FileOpen Window when trying it out !

Edit: header changed.

Edited by jennico
Spoiler

I actively support Wikileaks | Freedom for Julian Assange ! | Defend freedom of speech ! | Fight censorship ! | I will not silence.OixB7.jpgDon't forget this IP: 213.251.145.96

 

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...