variant.html 5.7 KB

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