[Win32utils-devel] How to initialize and pass a VARIANT to IAccessible::get_accName?

Bill Agee billagee at gmail.com
Tue Dec 14 15:13:52 EST 2010


Hi all,

First off, thanks for Win32Utils!  The libraries have been really beneficial
for me.

I have a question (hope this is an appropriate place for it):

I'm trying to write some demo scripts that use the IAccessible interface:

http://msdn.microsoft.com/en-us/library/dd318466%28v=vs.85%29.aspx

I've had some success so far (for example, I can successfully call the
"IAccessible::get_accChildCount" method).

But I'm stuck on IAccessible::get_accName.

In fact, any method like get_accName that takes a VARIANT (note: not a
VARIANT*) seems to be failing for me.

Does anyone have experience using win32-api to define and call a function
that takes a VARIANT?

In the case of get_accName, I can't get it to return successfully...

Either ruby.exe crashes (when I pass a 16-byte packed string as the VARIANT)
or I get the HRESULT 'The parameter is incorrect.' (when I use a >=28-byte
packed string as the VARIANT).


I'm wondering if the problem is one of:

- the Win32::API function prototype I'm using for the VARIANT param is
wrong, or:

- the way I'm initializing the VARIANT before passing it is incorrect

I'd be really grateful if anyone could weigh in on how to achieve this. :)

Right now I'm treating the VARIANT as a pointer in the get_accName prototype
(note the full example program this came from is at the end of the email):

  Get_accName = Win32::API::Function.new(table[10], 'PPP', 'L')

The C prototype for the function (from OleAcc.h) is:

  /* [id][propget][hidden] */ HRESULT ( STDMETHODCALLTYPE *get_accName )(
      __RPC__in IAccessible * This,
      /* [optional][in] */ VARIANT varChild,
      /* [retval][out] */ __RPC__deref_out_opt BSTR *pszName);


I combed through the windows-pr code looking for examples of functions that
take a VARIANT param, but so far I've only found functions that take a
pointer-to-VARIANT.

Also, I suspect this code, which initializes my VARIANT, might be causing my
problem (it was cobbled together from snippets on the win32utils-devel list
and the pr-win32ole source):

  # Initialize VARIANT that holds CHILDID_SELF
  self_var = 0.chr * 16
  VariantInit(self_var)
  self_var[0, 2] = [VT_I4].pack('S')
  self_var[2, 2] = [0].pack('S')
  self_var[4, 2] = [0].pack('S')
  self_var[6, 2] = [0].pack('S')
  self_var[8, 4] = [CHILDID_SELF].pack('L')
  self_var[12, 4] = [0].pack('L')


Here's a complete script that shows the get_accName problem - please let me
know if there are any questions I could answer that might help resolve the
issue.  If it would help I also have a working C demo program where
get_accName is used.

# print_desktop_name.rb

require 'rubygems'
require 'win32/api'
require 'windows/com'
require 'windows/com/variant'
require 'windows/error'
require 'windows/msvcrt/buffer'
require 'windows/unicode'
require 'windows/window'
require 'windows/window/menu'

include Windows::COM
include Windows::COM::Variant
include Windows::Error
include Windows::MSVCRT::Buffer
include Windows::Unicode
include Windows::Window
include Windows::Window::Menu

IID_IAccessible = [0x618736e0, 0x3c3d, 0x11cf, 0x81, 0x0c, 0x00, 0xaa, 0x00,
0x38, 0x9b, 0x71].pack('LSSC8')
CHILDID_SELF = 0

CoInitialize(nil) # Initialize COM

desktop_hwnd = GetDesktopWindow.call() # Get the desktop's HWND

# Use the HWND to get the desktop's IAccessible object
AccessibleObjectFromWindow = Win32::API.new('AccessibleObjectFromWindow',
                                            'LLPP', 'L', 'oleacc')
desktop_iacc = 0.chr * 4
hr = AccessibleObjectFromWindow.call(desktop_hwnd,
                                     OBJID_WINDOW,
                                     IID_IAccessible,
                                     desktop_iacc)
raise "Failed to instantiate IAcc object!" if (hr != S_OK)

# Get the memory address of the IAcc pointer - need to use it later as a
# 'this' pointer to pass to get_accName
desktop_iacc_ptr = desktop_iacc.unpack('L').first

# Get the IAccessibleVtbl C interface. It contains 28 functions (see
OleAcc.h).
lpVtbl = 0.chr * 4
table = 0.chr * (4 * 28)

# Unpack the IAccessibleVtbl:
memcpy(lpVtbl, desktop_iacc_ptr, 4)
memcpy(table, lpVtbl.unpack('L').first, 4 * 28)
table = table.unpack('L*')

# Define get_accName
Get_accName = Win32::API::Function.new(table[10], 'PPP', 'L')

# Create buffer for the BSTR that will receive the IAcc object name
name_bstr = 0.chr * 4

# Initialize CHILDID_SELF variant
self_var = 0.chr * 16
VariantInit(self_var)
self_var[0, 2] = [VT_I4].pack('S')
self_var[2, 2] = [0].pack('S')
self_var[4, 2] = [0].pack('S')
self_var[6, 2] = [0].pack('S')
self_var[8, 4] = [CHILDID_SELF].pack('L')
self_var[12, 4] = [0].pack('L')

# This segfaults on XP and Win7:
# (using ruby 1.8.7 i386-mingw32, 2010-08-16 patchlevel 302)
hr = Get_accName.call(desktop_iacc_ptr, self_var, name_bstr)
puts "HRESULT from get_accName is: " + hr.to_s
puts "HRESULT message is: '#{get_last_error(hr)}'"
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://rubyforge.org/pipermail/win32utils-devel/attachments/20101214/3005e52c/attachment-0001.html>


More information about the win32utils-devel mailing list