Scripting in Microsoft Windows

 
   

Ruby Way
By Hal Fulton
Slots : 1.0
Table of Contents
 


Like the ski resort full of girls hunting for husbands and husbands hunting for girls, the situation is not as symmetrical as it might seem.

Alan Lindsay Mackay

It has been said that Ruby has a Unix bias. In a sense, this is true; it was conceived in a Unix environment and works best there. Yet there are other ports out there at the time of this writing, including DOS and Amiga; and there are others ports in progress, such as Macintosh and Palm OS. But if Unix is the primary platform for Ruby, the secondary platform is Windows.

Windows users certainly aren't left out in the cold. Windows-based tools and libraries are in existence, and more are being created. Much of Ruby is platform-independent anyhow, even the threading capabilities; most of the platform difficulties occur in the areas of I/O, process management, and other similar low-level operations.

One problem for Windows users is that different variants of Ruby exist for the Windows platforms. These have little to do with differing versions of Ruby or differing versions of Windows; rather they have to do with how the interpreter was built. It might have been built with gcc or Visual C; it might or might not depend on the Cygwin DLL, and so on.

The environment is changing too rapidly to document at this point. But we will mention a few of the high points in Windows scripting and automation. These techniques and utilities should work for anyone, and if there are problems, the online support community is very helpful with such things.

Using Win32API

The Win32API is exceptionally powerful if you want to code at a fairly low level. Essentially it allows access to any Windows API function in any DLL, making it callable from Ruby code.

The specified function is instantiated as an object, with relevant parameters precisely describing the function being passed into the new method. The first parameter, a string, identifies the DLL containing the function (such as crtdll). The second parameter is the name of the function itself. The third parameter is an array of strings identifying the types of the function parameters (the import array); and the fourth is a string specifying the function's return type.

The import array can contain these (not case sensitive) values:

 

 I    Integer L    Number N    Number P    Pointer to a string 

The export string can also contain any one of these. Additionally it can take the value V, meaning void.

After we have created this object, we can invoke its call method to call the Windows function. Note that Call is an alias.

Here we call the Windows function GetCursorPos, which returns a pointer to a POINT structure. This structure consists of two long fields; we can use unpack to examine these fields and retrieve their values.

 

 result = "0"*8   # Eight bytes (enough for two longs) getCursorXY = Win32API.new("user32","GetCursorPos",["P"],"V") getCursorXY.call(result) x, y = result.unpack("LL")  # Two longs 

Sometimes we need to pass in complex binary data, whereas in this case it was passed back to us. In that case, we could obviously use pack to pack the data into a string.

There are obviously many possible applications for this technique. Two other code fragments can be seen in the section "Grabbing a Character from the Keyboard," from Chapter 4 and the section "Using system and exec" in this chapter.

Using Win32OLE

The Win32OLE extension library (actually spelled in lowercase, win32ole) provides an interface to Windows OLE automation. Your Ruby code can act as a client for any OLE automation server such as Microsoft Word, Outlook, Internet Explorer, and many third-party software products.

To interact with an external application, we first create a new object of the WIN32OLE class. This object is used to access all the exposed properties and methods of the specified application.

In this example, we associate an object with the Microsoft Word application. We set the visible attribute to true, and eventually we quit, exiting the application.

 

 require "win32ole" word = WIN32OLE.new "Word.Application" word.visible = true # ... word.quit 

Every property of the automation server is reflected as an attribute of the object. These can be set or examined at will.

An alternate notation uses a hash-like construct to access these properties.

 

 player["FileName"] = "file.wav" name = player["FileName"] # Equivalent to these statements: # player.FileName = "file.wav" # name = player.FileName 

One advantage of this is that it can easily handle the more programmatic situations as shown in this contrived example:

 

 puts "Enter the property name" prop = gets puts "Enter the new value" val = gets old = obj[prop] obj[prop] = val puts "#{ prop}  was #{ old} ... now is #{ obj[prop]} " 

But let's look at some more concrete examples. Here is a code fragment that takes a filename from the command line, passes it into Microsoft Word, and prints the file:

 

 require "win32ole" print "Enter the filename to print: " docfile = gets word = WIN32OLE.new "Word.Application" word.visible = true word.documents.open docfile word.options.printBackground = false # We could also set printBackground to true, but we # would have to sleep until the file all got sent to # the printer buffer before we quit... word.activeDocument.printOut word.quit 

Here is an example of playing a WAV file. It has the disadvantage of an arbitrary sleep at the end rather than waiting for the output to finish. Fixing this is left as an exercise.

 

 require "win32ole" sound = WIN32OLE.new("MCI.MMcontrol") wav = "c:\\windows\\media\\ The Microsoft Sound.wav" sound.fileName = wav sound.autoEnable = true sound.command = "Open" sound.command = "Play" sleep 7 

In Listing 8.2, we use Internet Explorer to generate a text input box for us.

Listing 8.2 Browser Text Input Box
 require "win32ole" def ieInputBox( msg, default )   ie = WIN32OLE.new("InternetExplorer.Application");   ie.visible  = false   sleep 0.01 while (ie.busy)   script = ie.Document.Script;   result = script.prompt(msg,default);    ie.quit    result end # Main... result = ieInputBox( "Please enter your name",                      "Dave Bowman") if result   puts result else   puts "User pressed Cancel" end 

In Listing 8.3, we open a small IE window and write HTML to it.

Listing 8.3 Writing to a Browser Window
 require "win32ole" html = <<EOF <html> <body> <h3>And now for something</h3> <h2>completely</h2> <h1>different...</h1> </body>  </html>  EOF ie = WIN32OLE.new("InternetExplorer.Application"); ie.left       = 150 ie.top        = 150 ie.height     = 200 ie.width      = 300 ie.menubar    = 0 ie.toolbar    = 0 ie.navigate "about:blank" ie.visible=TRUE; ie.document.open ie.document.write html ie.document.close sleep 5 ie.quit 

Here we open a file dialog box and allow the user to select a file from a list:

 

 require "win32ole" cd = WIN32OLE.new("MSComDlg.CommonDialog") # Set file filter cd.filter = "All Files(*.*)|*.*" +             "|Ruby Files(*.rb)|*.rb" cd.filterIndex = 2 cd.maxFileSize = 128    # Set MaxFileSize cd.showOpen() file = cd.fileName      # Retrieve file, path if not file or file==""    puts "No filename entered." else    puts "The user selected: #{ file} \n" end 

And finally, here is a little fragment that will discover the IP address of the local machine:

 

 require "win32ole" ws = WIN32OLE.new "MSWinsock.Winsock" # Retrieve LocalIP property ipAddress = ws.localIP puts "The local IP is : #{ ipAddress} " 

As you can see, the possibilities are limitless. Have fun, and don't forget to share your code with others.

Using ActiveScriptRuby

You have probably used Internet Explorer at some point to view a Web page that contained embedded JavaScript or VBScript code. (We'll ignore the differences between JScript and JavaScript here.)

You can do the same thing with ActiveScriptRuby, which is like a bridge between COM and Ruby. For example, we can embed Ruby in an HTML page (as seen in Listing 8.4).

Listing 8.4 Ruby Embedded in HTML
 <html> <script language="RubyScript">   # This is Ruby code...   def helloMethod     @window.alert "Running Ruby Inside!"   end </script> <body> Here is an input button... <input id=Hello type=button onclick="helloMethod"        language="RubyScript"> </body> </html> 

Using this technique of embedding Ruby, we can call Ruby code from any native Windows application that supports the IActiveScript interface, such as Internet Explorer or WScript (the WSH executable).


   

 

 



The Ruby Way
The Ruby Way, Second Edition: Solutions and Techniques in Ruby Programming (2nd Edition)
ISBN: 0672328844
EAN: 2147483647
Year: 2000
Pages: 119
Authors: Hal Fulton

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net