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>