Sunday, May 6, 2007

Automating the Windows Shell with Ruby

The Microsoft Windows Shell provides a set of objects and methods that allow you to automate the Windows Shell with Ruby. You can use these objects and methods to access many of the Shell's functions.

Let's start with an example involving accessing your CD-ROM drive...

As usual, we'll start by requiring the win32ole library...


require 'win32ole'

Next, we'll create an instance of the Windows Shell object...

shell = WIN32OLE.new("Shell.Application")

Now, we'll call the shell object's NameSpace method to obtain a reference to the "My Computer" folder...

my_computer = shell.NameSpace(17)

The value passed to the NameSpace method represents a special folder ("My Computer" = 17).

To obtain a reference to the drive object, we'll call the NameSpace object's ParseName method, passing it the drive letter string for the CD-ROM drive...

cdrom = my_computer.ParseName("E:\\")

Shell objects such as drives and folders have a collection of Verbs that can be called upon. We can see the list if verbs available for a drive by iterating over the drive's Verbs collection and printing out the Name value...

cdrom.Verbs.each do |verb|
puts verb.Name
end

The list of verbs may vary depending on the type of disc in the drive, but you may see something like this...

&Play
S&earch...
&Open
E&xplore
Auto&Play
Form&at
&Use with DLA
S&haring and Security...
Scan with &AVG Free
E&ject
&Copy
Create &Shortcut
P&roperties

Note the ampersand (&) in these verb names, which represent the context menu shortcut keys.

To perform an action represented by a Verb, locate the verb by Name, then call that Verb's doIt method. So, to eject your CD-ROM drive, you can do this...

cdrom.Verbs.each do |verb|
verb.doIt if verb.Name == "E&ject"
end

Putting it all together, we could whip up a little CdRom class that encapsulates such functionality...

class CdRom

attr_accessor :drive, :drive_letter, :verbs

def initialize(drive_letter)
my_computer = 17
@drive_letter = drive_letter
sh = WIN32OLE.new("Shell.Application")
@drive= sh.NameSpace(my_computer).ParseName("#{@drive_letter}")
@verbs = []
@drive.Verbs.each do |verb|
@verbs << verb.Name if verb.Name != ''
end
end

def invoke_verb(verb_name)
@drive.Verbs.each do |verb|
verb.doIt if verb.Name== verb_name
end
end

def eject
self.invoke_verb("E&ject")
end

def open
self.invoke_verb("&Open")
end

def explore
self.invoke_verb("E&xplore")
end

def play
self.invoke_verb("&Play")
end

end

...which could be used like this...

cd = CdRom.new('d:\\')
puts cd.verbs
cd.eject

A tip of the hat goes to Masaki Suketa, who informed me (via the comp.lang.ruby group) that the standard InvokeVerb method does not currently work in the win32ole library, and to use the verb.doIt method instead.

That's all for now. As always, feel free to comment here or email me if you have special requests.

Thanks for stopping by!

2 comments:

vasudevram said...

Hey, another good post!
Cool ...
The ideas in it could be the basis of a lot of useful tools.

Vasudev Ram
www.dancingbison.com

Anonymous said...

Hi

Is there a way i can get what all are the methods available to use with the Shell OLE server? Also any site where I can get the arguments for each and every method supported by it?

Thanks.