/ lib / win32com / HTML / variant.html
variant.html
  1  <HTML>
  2  <HEAD>
  3      <TITLE>win32com.client.VARIANT</TITLE>
  4  </HEAD>
  5  <BODY>
  6  
  7  <H2>Introduction</H2>
  8  <p>
  9  win32com attempts to provide a seamless COM interface and hide many COM 
 10  implementation details, including the use of COM VARIANT structures.  This 
 11  means that in most cases, you just call a COM object using normal Python 
 12  objects as parameters and get back normal Python objects as results.
 13  </p>
 14  
 15  <p>
 16  However, in some cases this doesn't work very well, particularly when using
 17  "dynamic" (aka late-bound) objects, or when using "makepy" (aka early-bound)
 18  objects which only declare a parameter is a VARIANT.
 19  </p>
 20  
 21  <p>
 22  The <code>win32com.client.VARIANT</code> object is designed to overcome these 
 23  problems.
 24  </p>
 25  
 26  <h2>Drawbacks</h2>
 27  The primary issue with this approach is that the programmer must learn more 
 28  about COM VARIANTs than otherwise - they need to know concepts such as 
 29  variants being <em>byref</em>, holding arrays, or that some may hold 32bit 
 30  unsigned integers while others hold 64bit signed ints, and they need to 
 31  understand this in the context of a single method call.  In short, this is
 32  a relatively advanced feature.  The good news though is that use of these
 33  objects should never cause your program to hard-crash - the worst you should
 34  expect are Python or COM exceptions being thrown.
 35  
 36  <h2>The VARIANT object</h2>
 37  
 38  The VARIANT object lives in <code>win32com.client</code>.  The constructor 
 39  takes 2 parameters - the 'variant type' and the value.  The 'variant type' is 
 40  an integer and can be one or more of the <code>pythoncom.VT_*</code> values,
 41  possibly or'd together.
 42  
 43  <p>For example, to create a VARIANT object which defines a byref array of 
 44  32bit integers, you could use:
 45  
 46  <pre>
 47  >>> from win32com.client import VARIANT
 48  >>> import pythoncom
 49  >>> v = VARIANT(pythoncom.VT_BYREF | pythoncom.VT_ARRAY | pythoncom.VT_I4,
 50  ...             [1,2,3,4])
 51  >>> v
 52  win32com.client.VARIANT(24579, [1, 2, 3, 4])
 53  >>>
 54  </pre>
 55  
 56  This variable can then be used whereever a COM VARIANT is expected.
 57  
 58  <h2>Example usage with dynamic objects.</h2>
 59  
 60  For this example we will use the COM object used for win32com testing, 
 61  <code>PyCOMTest.PyCOMTest</code>.  This object defines a method which is
 62  defined in IDL as:
 63  <pre>
 64  HRESULT DoubleInOutString([in,out] BSTR *str);
 65  </pre>
 66  
 67  As you can see, it takes a single string parameter which is also used as
 68  an "out" parameter - the single parameter will be updated after the call.
 69  The implementation of the method simply "doubles" the string.
 70  
 71  <p>If the object has a type-library, this method works fine with makepy
 72  generated support.  For example:
 73  
 74  <pre>
 75  >>> from win32com.client.gencache import EnsureDispatch
 76  >>> ob = EnsureDispatch("PyCOMTest.PyCOMTest")
 77  >>> ob.DoubleInOutString("Hello")
 78  u'HelloHello'
 79  >>>
 80  </pre>
 81  
 82  However, if makepy support is not available the method does not work as
 83  expected.  For the next example we will use <code>DumbDispatch</code> to
 84  simulate the object not having a type-library.
 85  
 86  <pre>
 87  >>> import win32com.client.dynamic
 88  >>> ob = win32com.client.dynamic.DumbDispatch("PyCOMTest.PyCOMTest")
 89  >>> ob.DoubleInOutString("Hello")
 90  >>>
 91  </pre>
 92  
 93  As you can see, no result came back from the function.  This is because
 94  win32com has no type information available to use, so doesn't know the
 95  parameter should be passed as a <code>byref</code> parameter.  To work
 96  around this, we can use the <code>VARIANT</code> object.
 97  
 98  <p>The following example explicitly creates a VARIANT object with a
 99  variant type of a byref string and a value 'Hello'.  After making the
100  call with this VARIANT the value is updated.
101  
102  <pre>
103  >>> import win32com.client.dynamic
104  >>> from win32com.client import VARIANT
105  >>> import pythoncom
106  >>> ob = win32com.client.dynamic.DumbDispatch("PyCOMTest.PyCOMTest")
107  >>> variant = VARIANT(pythoncom.VT_BYREF | pythoncom.VT_BSTR, "Hello")
108  >>> variant.value # check the value before the call.
109  'Hello'
110  >>> ob.DoubleInOutString(variant)
111  >>> variant.value
112  u'HelloHello'
113  >>>
114  </pre>
115  
116  <h2>Usage with generated objects</h2>
117  
118  In most cases, objects with makepy support (ie, 'generated' objects) don't 
119  need to use the VARIANT object - the type information means win32com can guess
120  the right thing to pass.  However, in some cases the VARIANT object can still
121  be useful.
122  
123  Imagine a poorly specified object with IDL like:
124  
125  <pre>
126  HRESULT DoSomething([in] VARIANT value);
127  </pre>
128  
129  But also imagine that the object has a limitation that if the parameter is an 
130  integer, it must be a 32bit unsigned value - any other integer representation
131  will fail.
132  
133  <p>If you just pass a regular Python integer to this function, it will 
134  generally be passed as a 32bit signed integer and given the limitation above,
135  will fail.  The VARIANT object allows you to work around the limitation - just
136  create a variant object <code>VARIANT(pythoncom.VT_UI4, int_value)</code> and 
137  pass that - the function will then be called with the explicit type you 
138  specified and will succeed.
139  
140  <p>Note that you can not use a VARIANT object to override the types described
141  in a type library.  If a makepy generated class specifies that a VT_UI2 is 
142  expected, attempting to pass a VARIANT object will fail.  In this case you 
143  would need to hack around the problem.  For example, imagine <code>ob</code>
144  was a COM object which a method called <code>foo</code> and you wanted to 
145  override the type declaration for <code>foo</code> by passing a VARIANT.
146  You could do something like:
147  
148  <pre>
149  >>> import win32com.client.dynamic
150  >>> from win32com.client import VARIANT
151  >>> import pythoncom
152  >>> dumbob = win32com.client.dynamic.DumbDispatch(ob)
153  >>> variant = VARIANT(pythoncom.VT_BYREF | pythoncom.VT_BSTR, "Hello")
154  >>> dumbob.foo(variant)
155  </pre>
156  
157  The code above converts the makepy supported <code>ob</code> into a
158  'dumb' (ie, non-makepy supported) version of the object, which will then
159  allow you to use VARIANT objects for the problematic methods.
160  
161  </BODY>
162  </HTML>