|  Browse For File | 
 
| Author: | 
Message: | 
 
Volv 
Skinning Contest Winner 
     
  
  
 
Posts: 1233 Reputation: 31 
36 /   /   
Joined: Oct 2004 
 | 
| 
O.P.  Browse For File
 Heya, 
How would I go about making a 'Browse for file' dialog which allows the user to navigate to a file of their choice on their PC and returns the path to the file. 
 
Thanks in advance 
- Volv 
 |   
 | 
 
| 06-24-2006 02:04 AM | 
 | 
 
  | 
 
matty 
Scripting Guru 
     
  
 
Posts: 8327 Reputation: 109 
40 /   /   
Joined: Dec 2002
 
Status: Away
 
 | 
 RE: Browse For File
This is taken from Choli's Translator, give all credits too him. 
js code:     var OFN_ENABLESIZING = 0x800000; 
    var OFN_EXPLORER = 0x80000; 
    var OFN_FILEMUSTEXIST = 0x1000; 
    var OFN_HIDEREADONLY = 0x4; 
    var OFN_LONGNAMES = 0x200000; 
    var OFN_PATHMUSTEXIST = 0x800; 
     
function OnEvent_Initialize(MessengerStart) 
{ 
    var OpenFileName = Interop.Allocate(88); 
    var filter; 
    var s_filter; 
    var file; 
    var s_file; 
    var title; 
    var s_title; 
    var ret; 
    var tdata; 
 
     with (OpenFileName) { 
        WriteDWORD(0, Size); // lStructSize 
        WriteDWORD(4, 0); // hwndOwner 
        WriteDWORD(8, 0); // hInstance 
        filter = "Translation files (Lng_*.ini)|Lng_*.ini|All files (*.*)|*.*||"; 
        s_filter = Interop.Allocate(2 * (filter.length + 1)); 
        WriteMultiStringW(s_filter, filter); 
        WriteDWORD(12, s_filter.DataPtr); // lpstrFilter 
        WriteDWORD(16, 0); // lpstrCustomFilter 
        WriteDWORD(20, 0); // nMaxCustomFilter 
        WriteDWORD(24, 1); // nFilterIndex 
        file = "Lng_*.ini" + Space(256); 
        s_file = Interop.Allocate(2 * (file.length + 1)); 
        s_file.WriteString(0, file); 
        WriteDWORD(28, s_file.DataPtr); // lpstrFile 
        WriteDWORD(32, file.length); // nMaxFile 
        WriteDWORD(36, 0); // lpstrFileTitle 
        WriteDWORD(40, 0); // nMaxFileTitle 
        WriteDWORD(44, 0); // lpstrInitialDir 
        title = "Select original file"; 
        s_title = Interop.Allocate(2 * (title.length + 1)); 
        s_title.WriteString(0, title); 
        WriteDWORD(48, s_title.DataPtr); // lpstrTitle 
        WriteDWORD(52, OFN_ENABLESIZING | OFN_EXPLORER | OFN_HIDEREADONLY | OFN_LONGNAMES | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST); // flags 
        WriteWORD(56, 0); // nFileOffset 
        WriteWORD(58, 0); // nFileExtension 
        WriteDWORD(60, 0); // lpstrDefExt 
        WriteDWORD(64, 0); // lCustData 
        WriteDWORD(68, 0); // lpfnHook 
        WriteDWORD(72, 0); // lpTemplateName 
        WriteDWORD(76, 0); // pvReserved 
        WriteDWORD(80, 0); // dwReserved 
        WriteDWORD(84, 0); // FlagsEx 
    } with OpenFileName 
    ret = Interop.Call("comdlg32.dll", "GetOpenFileNameW", OpenFileName); 
    if (ret == 0) { 
        return; 
    } 
} 
function WriteMultiStringW (datablock, string) { 
    var pos = 0; 
    datablock.WriteString(0, string); 
    pos = string.indexOf("|", pos); 
    while (pos != -1) { 
        datablock.WriteWORD(2 * pos, 0); 
        pos = string.indexOf("|", pos + 1); 
    } 
} 
function Space (number) { 
    var i; 
    var s = ""; 
    for (i = 0; i < number; i++) { 
        s += " "; 
    } 
    return s; 
}
   
 This post was edited on 04-11-2011 at 12:28 PM by matty.
 |   
 | 
 
| 06-24-2006 02:19 AM | 
 | 
 
  | 
 
Volv 
Skinning Contest Winner 
     
  
  
 
Posts: 1233 Reputation: 31 
36 /   /   
Joined: Oct 2004 
 | 
O.P.  RE: Browse For File
Thanks a lot Matty & Choli, works great    
 |   
 | 
 
| 06-24-2006 05:16 AM | 
 | 
 
  | 
 
Choli 
Elite Member 
     
  
  
Choli
  
Posts: 4714 Reputation: 42 
44 /   /   
Joined: Jan 2003 
 | 
 RE: Browse For File
yeah, that's it   
you can change the filter and put, for example:
 
"Text files|*.txt|All files|*.*||"
 
For more help, read this:  GetOpenFileName and  OPENFILENAME.  
 |   
 | 
 
| 06-24-2006 09:32 AM | 
 | 
 
  | 
 
CookieRevised 
Elite Member 
     
  
  
 
Posts: 15494 Reputation: 173 
– /   /   
Joined: Jul 2003
 
Status: Away
 
 | 
 RE: Browse For File
Since this recently came up again, I'll post my own variation/fix of the above code here. 
Note the word 'variation', as this kind of code is very very generic and can be found all over the net already in various forms. It is simply a matter of filling a structure with the needed stuff and calling the proper Windows API, thus not realy something special.
Some small notes first:
 - Choli's variation has some things in it which are specific for his Translator tool and should not be copied as-is. Nevertheless I have seen his code cropping up in various places and scripts without those needed changes. Aka, those copies will not always function properly.
 
 
 - Matti has made a better variation in the post: Matti's reply to CommonDialog help
 
However, that too still contains bugs and one or two things which could be done better. 
 
So here is my variation, based upon Matti's variation of Choli's snippet. It is of course different, but not that different to be completely 'new'. As such, I've also tried to keep most of the structure and variable names used in the previous variations. However, due to the change of order of the parameters and the change in format of the returned value of the function, you can't simply replace your old  BrowseForFile function with this one though. You will need to change the order of the parameters in your code and change how you handle the return value in your code.
 The code itself:
js code: /* FUNCION: BrowseForFile (CookieRevised variation) 
 
    Original code by Choli from the Messenger Plus! Translator script 
    Modified by Matti to be more versatile (eg: including "Save as" dialog function) 
    Modified by CookieRevised to optimize it a bit and fix some bugs 
 
    Description: 
        Opens a "Browse for file" dialog with the given settings 
 
    Parameters (all parameters are now optional): 
        save        (boolean) / true is "Save as" dialog, false is "Open" dialog 
        title       (string)  / Dialog title 
        dir         (string)  / Start directory 
        file        (string)  / File to display as default 
        filter      (string)  / Filter message. Example: "JavaScript Files (*.JS)|*.JS|Text Files (*.TXT;*.LOG)|*.TXT;*.LOG|" 
        ext         (string)  / Default extension to append to the filename when no extension is specified 
        multiselect (boolean) / true to allow multiple file selection in an "Open" dialog  
        hwnd_owner  (number)  / Handle of the owner window, used to copy window icon etc. 
 
 
 
    Return value: 
        >>>A (string) array of full filepath names.<<< 
        Note that this will also be an array if just 1 file was selected (in that case an array with just 1 element). 
        If no files were selected or the dialog was canceled, the array will be empty. 
        I think this is more consistant and versatile across multiple implementations of the function. 
*/ 
>>>function BrowseForFile(save, title, dir, file, filter, ext, multiselect, hwnd_owner) {<<< 
    // see http://msdn.microsoft.com/en-us/library/ms646839(v=vs.85).aspx 
    var OFN_OVERWRITEPROMPT =    0x2; 
    var OFN_HIDEREADONLY =        0x4; 
    >>>var OFN_NOCHANGEDIR =        0x8;<<< 
    var OFN_ALLOWMULTISELECT =    0x200; 
    var OFN_PATHMUSTEXIST =        0x800; 
    var OFN_FILEMUSTEXIST =        0x1000; 
    >>>var OFN_NONETWORKBUTTON =    0x20000;<<< 
    var OFN_EXPLORER =            0x80000; 
    var OFN_LONGNAMES =            0x200000; 
    var OFN_ENABLESIZING =        0x800000; 
    >>>var OFN_DONTADDTORECENT =    0x2000000;<<< 
 
    var OpenFileName = Interop.Allocate(88); 
    with (OpenFileName) { 
 
        save = save == true; 
        >>>multiselect = (multiselect == true) && !save;<<< 
        >>>hwnd_owner = hwnd_owner ? 1 * hwnd_owner : 0;<<< 
         
        >>>if (typeof filter !== "string") filter = "All Files (*.*)|*.*|";<<< 
        >>>var s_filter = Interop.Allocate(2 * (filter.length + 1) + 4);<<< 
        >>>s_filter.WriteBSTR(0, filter.replace(/\|/g, '\0'));<<< 
 
        if (typeof file !== "string") file = ""; 
        >>>var s_file = Interop.Allocate(2 * (Math.max(file.length, 16383) + 1));<<< 
        s_file.WriteString(0, file); 
 
        if (typeof dir === "string") { 
            var s_dir = Interop.Allocate(2 * (dir.length + 1)); 
            s_dir.WriteString(0, dir); 
            WriteDWORD(44, s_dir.DataPtr);    // lpstrInitialDir 
        } 
        if (typeof title === "string") { 
            var s_title = Interop.Allocate(2 * (title.length + 1)); 
            s_title.WriteString(0, title); 
            WriteDWORD(48, s_title.DataPtr);    // lpstrTitle 
        } 
        if (typeof ext === "string") { 
            var s_ext = Interop.Allocate(2 * (ext.length + 1)); 
            s_ext.WriteString(0, ext); 
            WriteDWORD(60, s_ext.DataPtr);    // lpstrDefExt 
        } 
        WriteDWORD(0, Size);                // lStructSize 
        WriteDWORD(4, hwnd_owner);            // hwndOwner 
        >>>WriteDWORD(12, s_filter.DataPtr + 4);    // lpstrFilter<<< 
        WriteDWORD(24, 1);                    // nFilterIndex 
        WriteDWORD(28, s_file.DataPtr);        // lpstrFile 
        >>>WriteDWORD(32, s_file.Size / 2);        // nMaxFile<<< 
        >>>WriteDWORD(52, OFN_DONTADDTORECENT | OFN_ENABLESIZING | OFN_EXPLORER | OFN_HIDEREADONLY | OFN_LONGNAMES | OFN_PATHMUSTEXIST | (save ? OFN_OVERWRITEPROMPT : OFN_FILEMUSTEXIST) | (multiselect ? OFN_ALLOWMULTISELECT : 0)); // Flags<<< 
    } 
 
    var result = Interop.Call("COMDLG32.DLL", (save ? "GetSaveFileNameW" : "GetOpenFileNameW"), OpenFileName); 
    if (result) { 
        var p_path = s_file.ReadString(0); 
        var p_files = new Array(); 
        if (multiselect) { 
            var p_file = ""; 
            var pos = 2 * (p_path.length + 1); 
            while (true) { 
                p_file = s_file.ReadString(pos); 
                if (p_file.length > 0) { 
                    >>>p_files.push(p_path + (p_path.slice(-1) !== "\\" ? "\\" : "") + p_file);<<< 
                    pos += 2 * (p_file.length + 1); 
                } else break; 
            } 
        } 
        >>>return p_files.length ? p_files : [p_path];<<< 
    } else { 
        >>>return [];<<< 
    } 
}
  Major changes highlighted
Examples:
js code: // Save File Dialog 
// Opens up in C:\, file filters are 'Text Files' (*.txt and *.log) and 'All Files' (*.*). 
var aFile = BrowseForFile(true, "Save file as", "C:\\", "test.txt", "Text Files (*.TXT;*.LOG)|*.TXT;*.LOG|All Files (*.*)|*.*|"); 
if (aFile.length) { 
    // User specified a valid save location. Do something useful here. 
    Debug.Trace(aFile[0]) 
} else { 
    // User didn't specify a file to save to or pressed Cancel. 
}
  js code: // Open File Dialog 
// Opens up in C:\Windows, multiple selections are allowed, file filters are 'PNG Files' (*.png) and 'All Files' (*.*). 
var aFile = BrowseForFile(false, "Select PNG", "C:\\Windows", null, "PNG Files (*.PNG)|*.PNG|All Files (*.*)|*.*|", null, true); 
if (aFile.length) { 
    // User selected some files. Do something useful here. 
    for (var i in aFile) { 
        Debug.Trace(aFile[i]) 
    } 
} else { 
    // User didn't selected any files to open or pressed Cancel. 
}
  
Stuff changed compared to Matti's and Choli's (also see highlights in the code):
 - Made order of parameters a bit more logical, also in regards to optional paramater usage.
 
 - Changed the format of the returned value of the function. Now it always return an array with the full filepath names of the selected file(s). I think this is much more versatile and consistant in regards to multiple file selections, looping, etc. It is also very easy now to check if a file is returned or not, no matter the amount of files (just check the length of the array being 0 or not).
 
 
thus beware, you can't simply replace your old BrowseForFile function with this one. See examples above. 
 
 - Fixed the behaviour of the parameters so that they are now all optional. They weren't before in the sense that the code would fail if the file or dir parameter were not specified (was a big bug in Matti's variation). This was solved by removing the Datablock.Size = 0 lines at the end of the function. They are not needed as datablocks will be removed automatically by the garbage collector of Plus! when the function ends anyways.
 
 - Made hwnd_owner parameter also behave properly when not specified (was a potential bug). All parameters are now truely optional; you don't need to specify them.
 
 - Added the optional multiselect parameter (boolean).
 
 - Added some extra constants.
 
 - Replaced Choli's WriteMultiStringW function with Datablock::WriteBSTR() function and thus highly optimized the parsing of the filter parameter.
 
 - Removed Choli's Space() function.
 
 - Removed all unneeded Datablock::WriteDWORD(x, 0); lines. They are not needed because a Datablock will always be zero-filled anyways when you allocate it.
 
 - Added proper initial filepath name length check before writing to the filepath buffer. (was a potential bug)
 
 - Increased the filepath buffer drastically. 256 like in Choli's code is way too small. Even 1024 characters is small-ish, especially considering multiple file selections. There is no reason not to have a massive buffer for this.
 
 - Fixed nMaxFile calculation (size should include the null-character).
 
 - Added OFN_DONTADDTORECENT flag. This prevents files from being added to Windows' Recent Documents list, which is otherwise highly annoying in many cases. If you explicitly have a reason to add the opened/saved files in that list, simply remove that flag again in the code (on the line starting with WriteDWORD(52, ...).
 
 - Maybe some other tid bits not worth to mention.
  
 
 This post was edited on 04-11-2011 at 08:43 PM by CookieRevised.
.-= A 'frrrrrrrituurrr' for Wacky =-.  
 |   
 | 
 
| 04-11-2011 07:46 AM | 
 | 
 
  | 
 
Choli 
Elite Member 
     
  
  
Choli
  
Posts: 4714 Reputation: 42 
44 /   /   
Joined: Jan 2003 
 | 
 RE: Browse For File
  Cookie... this thread is 5 years old...
 quote: Originally posted by CookieRevised 
256 like in Choli's code is way too small.
  Sure, but if I remember well, I think that old versions of Windows (maybe 98, or 2000) don't allow more than that, do they?. Or something like that    
 |   
 | 
 
| 04-11-2011 06:41 PM | 
 | 
 
  | 
 
CookieRevised 
Elite Member 
     
  
  
 
Posts: 15494 Reputation: 173 
– /   /   
Joined: Jul 2003
 
Status: Away
 
 | 
 RE: Browse For File
quote: Originally posted by Choli 
  Cookie... this thread is 5 years old...
  Yup, the '90s are coming back   
Nah, but joking aside, as I said, the request to have a 'BrowseForFile' dialog pops up now and then and will continue to pop up in the future no doubt. And apparently people keep on referring to this thread and/or use code from this thread (which is main reason why I posted this here and not in that other thread). I found many links pointing to Matty's post here, even in very recent posts. So, nothing wrong with (finaly) updating it a bit in that case imho.
 quote: Originally posted by Choli 
quote: Originally posted by CookieRevised 
256 like in Choli's code is way too small.
  Sure, but if I remember well, I think that old versions of Windows (maybe 98, or 2000) don't allow more than that, do they?. Or something like that  
  Not exactly; +-256 (or rather 260, which is MAX_PATH) is the absolute required minimum (eg: when you are sure you don't return multiple selections and with short file names). It's the minimum required size to hold exactly one complete path and file name (in short name notation.... because in long name notation the name itself can even be MAX_PATH characters). So, even back in the old days, the buffer could be (and better should be) much much bigger to hold both the returned path and filename.
 
For your Translator tool this was never a real problem. But since people copy that code without changing anything in it and using it as-is, problems do arise though.  
 This post was edited on 04-11-2011 at 08:51 PM by CookieRevised.
.-= A 'frrrrrrrituurrr' for Wacky =-.  
 |   
 | 
 
| 04-11-2011 08:13 PM | 
 | 
 
  | 
 
Amec 
Junior Member 
  
  
 
Posts: 19 
33 /   /   
Joined: Sep 2008 
 | 
 | 
 
| 04-14-2011 06:54 PM | 
 | 
 
  | 
 
matty 
Scripting Guru 
     
  
 
Posts: 8327 Reputation: 109 
40 /   /   
Joined: Dec 2002
 
Status: Away
 
 | 
 | 
 
| 04-14-2011 07:06 PM | 
 | 
 
  | 
 
CookieRevised 
Elite Member 
     
  
  
 
Posts: 15494 Reputation: 173 
– /   /   
Joined: Jul 2003
 
Status: Away
 
 | 
 RE: Browse For File
quote: Originally posted by Amec 
quote: Originally posted by CookieRevised 
 
js code: with (OpenFileName) {
  
  Every time you use a with statement, a teddy bear cries. 
 
http://www.yuiblog.com/blog/2006/04/11/with-statement-considered-harmful/
  Yeah, well, you're 5 years to late....
 
Although I agree for 50%, it is mostly also a matter of schematics. There is essentially nothing wrong with using  with() if you know what the code will do. In the code snippet it is also used for the exact purpose that  with() statement was invented and there are enough  readDWORD() statements to justify the use of  with() imo.
 
May I also quote that very same page you linked to: quote: If you can’t read a program and be confident that you know what it is going to do, you can’t have confidence that it is going to work correctly. For this reason, the with statement should be avoided.
  I can read the program and I am 100% confident in knowing what it is going to do and that it is going to work correctly.
 
Lastly, it is not my code: quote: Originally posted by CookieRevised 
So here is my variation, based upon Matti's variation of Choli's snippet. It is of course different, but not that different to be completely 'new'. As such, I've also tried to keep most of the structure and variable names used in the previous variations.
  Note that there are also other parts in the code which could be made shorter/smarter/cleaner/etc. But that was not the purpose of showing or updating that code.  
 This post was edited on 04-14-2011 at 07:53 PM by CookieRevised.
.-= A 'frrrrrrrituurrr' for Wacky =-.  
 |   
 | 
 
| 04-14-2011 07:40 PM | 
 | 
 
  | 
 
| 
Pages: (2): 
« First
  
 [ 1 ]
 2
 
»
 
Last »
 | 
 
| 
 |  
 
 |