Rublargh
September 21, 2006 2:40 AM   Subscribe

How do I select a directory with Ruby?

This is very frustrating. I want to select a directory in Windows and pass the directory name to a Ruby script as an argument.

I know I need Win32API,
I know I need to call SHBrowseForFolder

but:
1. I cannot figure out what this reference to the new method for WinAPI32 wants me to do (what's up with that l and p and i and v? What?)
and
2. I cannot figure out what arguments to pass to SHBrowseForFolder, as Microsoft's reference is even more obscure to me (lpbi? what?).

Is my brain pea sized or is this really all not explaining it very well? Is there a better reference the Win32 API? I've been looking for one all morning.

I mean, I see this for Python and I'm thinking, it's probably just as simple in Ruby - it has to be, right?
posted by Skyanth to Computers & Internet (5 answers total)
 
Response by poster: Just to clarify (and to prove that I have tried ;), what I understand of the above documentation is that I would have to execute this:

require 'Win32API'
fSelect = Win32API.new('shell32', 'SHBrowseForFolder', [], 'P')
fName = fSelect.call()
puts fName

to return on screen the name of the selected folder. Because I gather that SHBrowseForFolder does not need arguments and it returns a pointer to a string (whatever that means). But I get a segmentation fault. Why?
posted by Skyanth at 3:35 AM on September 21, 2006


SHBrowseForFolder takes a pointer to a BROWSEINFO and returns a pointer to an ITEMIDLIST. This will make your second line:

fSelect = Win32API.new("shell32", "SHBrowseForFolder", ['P'], 'P')

To convert the ITEMIDLIST into a string, you can use SHGetPathFromIDList, like your Python example does.

You'll need to somehow create and initialize a BROWSEINFO structure to feed to SHBrowseForFolder. Hopefully somebody with nonzero knowledge of Ruby can help out with this (looks like it'll involve a string that's sizeof(BROWSEINFO) characters long?).

A pointer, BTW, is an address in memory. This is kind of like an "address" in real life; if I give you the address of my apartment, you are not carrying my apartment, but if you want to go pick it up (uh, somehow), you know where to find it. A pointer to a string is not an actual string, but it tells you where a string can be found. Take a look at what they're doing with GetCursorPos in your first link (the "unpack" part, particularly); this is what you'll need to do with the pointer to string that SHGetPath[...] will give you, and it's the reverse of what you'll be doing with the BROWSEINFO.
posted by equalpants at 4:30 AM on September 21, 2006


Yup, looks like you'll want to make string that's equivilent to a BROWSEINFO structure, probably using Array#pack. Something like:

SHBrowseForFolder = Win32API.new("shell32", "SHBrowseForFolder", 'P', 'P')
browseinfo = [0,0,0,'My title',0,0,0,0].pack('LLLpLLLL')
itemidlist = SHBrowseForFolder.call(browseinfo)


I've not managed to make SHGetPathFromIDList do anything useful yet though. To be honest I'd probably be looking at a real C extension for stuff like this. Maybe swin or something could be of use? [example?]
posted by Freaky at 7:23 AM on September 21, 2006


Best answer: This seems to work:

require 'swin'
folder = SWin::CommonDialog.selectDirectory(nil)
puts folder
posted by tremendo at 1:16 PM on September 21, 2006


Response by poster: swin. Never heard of it, but thanks a bunch. Plus I learned a whole lot about Win32API today. :)
posted by Skyanth at 1:44 PM on September 21, 2006


« Older Content Management System Help:   |   Healthy romantic relationships after sexual abuse... Newer »
This thread is closed to new comments.