Real Variants in WIN32OLE

Ruby 1.9 has proper WIN32OLE variants! Thank you very much, Masaki Suketa!

A week ago if I had read that in someone’s blog it wouldn’t have meant anything to me. But then I had to use WIN32OLE to call a method whose arguments were variants, and whose behaviour changed depending on the type of data being passed. If a date is passed, the method returns data pertaining to that date. If an integer is passed, the method returns a range of data pertaining to that number of days prior to today. No matter what value I tried to pass, it was never interpreted as a date by the COM object I was talking to. I tried Ruby dates, times, datetimes, strings in any date format I could think of and floats and integers which represented Excel dates. No joy. I tried small integers and floats, to see if I could get the other interpretation to work. No joy there, either. Then I started experimenting with ._invoke and passing WIN32OLE::VARIANT constants such as VT_DATE (those were there in Ruby 1.8) to specify the kind of data I was passing. That didn’t help, except to generate some very interesting errors. I spent hours reading… okay, staring at… the C code in winole32.c looking for inspiration.

Finally, a search turned up a thread written in Japanese of which 2 terms in western characters stood out: “1.9″ and “WIN32OLE_VARIANT.new”. Now that I knew what to search for, I was able to find a few more fragmentary references to upcoming support for variants. I downloaded the Windows version of Ruby 1.9, and before long I was creating and passing date and integer variants and getting back exactly the information I was looking for.

WIN32OLE_VARIANT.new("2007-10-10", VT_DATE)

WIN32OLE_VARIANT.new(1, VT_I4)

There are lots of good examples in the unit tests for WIN32OLE (in the test_win32ole_variant.rb file which is in trunk/test/WIN32OLE of the Ruby subversion repository). There’s also a short explanation of the various VT_ types in the Perl documentation for Perl’s WIN32::OLE::Variant.

One thing to watch for, the method I call should return an Array of values, but if a WIN32OLERuntimeError has occurred, it quietly returns a WIN32OLE::PROPERTY object instead. Calling .value on this object raises the WIN32OLERuntimeError. I want to raise these errors so I call:

response.value if response.kind_of?(WIN32OLE::PROPERTY)