Thursday, August 27, 2009

WIN32API

If you plan on doing Ruby programming that needs to access some Windows 32 API functions directly, or that needs to use the entry points in some other DLLs, we've got good news for you-- the Win32API library.

As an example,here's some code that's part of a larger Windows application used by our fulfillment system to download and print invoices and receipts. A Web application generates a PDF file, which the Ruby script running on Windows downloads into a local file. The script then uses the print shell command under Windows to print this file.

arg = "ids=#{resp.intl_orders.join(",")}"
fname = "/temp/invoices.pdf"
site = Net::HTTP.new(HOST, PORT)
site.use_ssl = true
http_resp, = site.get2("/fulfill/receipt.cgi?"+ arg,
'Authorization'=> 'Basic ' +
["name:passwd"].pack('m').strip )
File.open(fname, :wb") {|f| f.puts(http_resp.body) }

shell = Win32API.new("shell32","ShellExecute",
['L','P','P','P','P','L'], 'L' )
shell.Call(0, "print", fname, 0,0, SW_SHOWNORMAL)

You create a Win32API object that represents a call to a particular DLL entry point by specifying the name of the function, the name of the DLL contains the function, and the function signature(argument types and return type). In the previous example, the variable shell wraps the Windows function ShellExecute in the shell32DLL. It takes six parameters (a number, four string pointers, and a number) and returns a number. the resulting object can then be used to make the call to print the file that we downloaded.

Many of the arguments to DLL function are binary structures of some form.Win32API handles this by using Ruby String objects to pass the binary data back and forth. You will need to pack and unpack these strings as necessary.

The Win32API module allows access to any arbitrary Windows 32 functions. Many of these function take or return a Pointer data type- a region of memory corresponding to a C string or structure type.

In Ruby, these pointers are represented using class String, which contains a sequence of 8-bit bytes. It is up to you to pack and unpack the bits in the String.

Parameters 3 and 4 of the new call specify the parameter and return types of the method to be called. The type specifiers are n and 1 for numbers, i for integers, p for pointers to data stored in a string, and v for the void type (used for export parameters only). These strings are case-intensentive. Method parameters are specified as an array of strings, and the return type is a single string.

The functionality of Win32API is also provided using the d1/win32 library. As the DL library is newer, this may be a sign that the original Win32API may be phased out over time.

This example is the from the Ruby distribution, in ext/Win32API

require 'Win32API'

get_cursor_pos = Win32API.new("users32", "GetCursorPos", ['P'], 'V')
lpPoint = "" * 8 # store two LONGs
get_cursor_pos.Call(lpPoint)
x, y = lpPoint.unpack("LL") # get the actual values
print "x: ", x, "\n"
print "y: ", y, "\n"
ods = Win32API.new("kernel32", "OutputDebugString", ['P'], 'V'])
ods.Call("Hello, World\n")

GetDesktopWindow = Win32API.new("user32", "GetDekstopWindow", [], 'L')
GetActiveWindow = Win32API.new("users32", "GetActiveWindow", [], 'L')
SendMessage = Win32.new('users32", "SendMessage", [L'] * 4, 'L')
SendMessage.Call(GetDesktopWindow.Call, 274, 0xf140, 0)

No comments:

Post a Comment