123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 |
- <HTML>
- <HEAD>
- <TITLE>win32com.client.VARIANT</TITLE>
- </HEAD>
- <BODY>
-
- <H2>Introduction</H2>
- <p>
- win32com attempts to provide a seamless COM interface and hide many COM
- implementation details, including the use of COM VARIANT structures. This
- means that in most cases, you just call a COM object using normal Python
- objects as parameters and get back normal Python objects as results.
- </p>
-
- <p>
- However, in some cases this doesn't work very well, particularly when using
- "dynamic" (aka late-bound) objects, or when using "makepy" (aka early-bound)
- objects which only declare a parameter is a VARIANT.
- </p>
-
- <p>
- The <code>win32com.client.VARIANT</code> object is designed to overcome these
- problems.
- </p>
-
- <h2>Drawbacks</h2>
- The primary issue with this approach is that the programmer must learn more
- about COM VARIANTs than otherwise - they need to know concepts such as
- variants being <em>byref</em>, holding arrays, or that some may hold 32bit
- unsigned integers while others hold 64bit signed ints, and they need to
- understand this in the context of a single method call. In short, this is
- a relatively advanced feature. The good news though is that use of these
- objects should never cause your program to hard-crash - the worst you should
- expect are Python or COM exceptions being thrown.
-
- <h2>The VARIANT object</h2>
-
- The VARIANT object lives in <code>win32com.client</code>. The constructor
- takes 2 parameters - the 'variant type' and the value. The 'variant type' is
- an integer and can be one or more of the <code>pythoncom.VT_*</code> values,
- possibly or'd together.
-
- <p>For example, to create a VARIANT object which defines a byref array of
- 32bit integers, you could use:
-
- <pre>
- >>> from win32com.client import VARIANT
- >>> import pythoncom
- >>> v = VARIANT(pythoncom.VT_BYREF | pythoncom.VT_ARRAY | pythoncom.VT_I4,
- ... [1,2,3,4])
- >>> v
- win32com.client.VARIANT(24579, [1, 2, 3, 4])
- >>>
- </pre>
-
- This variable can then be used whereever a COM VARIANT is expected.
-
- <h2>Example usage with dynamic objects.</h2>
-
- For this example we will use the COM object used for win32com testing,
- <code>PyCOMTest.PyCOMTest</code>. This object defines a method which is
- defined in IDL as:
- <pre>
- HRESULT DoubleInOutString([in,out] BSTR *str);
- </pre>
-
- As you can see, it takes a single string parameter which is also used as
- an "out" parameter - the single parameter will be updated after the call.
- The implementation of the method simply "doubles" the string.
-
- <p>If the object has a type-library, this method works fine with makepy
- generated support. For example:
-
- <pre>
- >>> from win32com.client.gencache import EnsureDispatch
- >>> ob = EnsureDispatch("PyCOMTest.PyCOMTest")
- >>> ob.DoubleInOutString("Hello")
- u'HelloHello'
- >>>
- </pre>
-
- However, if makepy support is not available the method does not work as
- expected. For the next example we will use <code>DumbDispatch</code> to
- simulate the object not having a type-library.
-
- <pre>
- >>> import win32com.client.dynamic
- >>> ob = win32com.client.dynamic.DumbDispatch("PyCOMTest.PyCOMTest")
- >>> ob.DoubleInOutString("Hello")
- >>>
- </pre>
-
- As you can see, no result came back from the function. This is because
- win32com has no type information available to use, so doesn't know the
- parameter should be passed as a <code>byref</code> parameter. To work
- around this, we can use the <code>VARIANT</code> object.
-
- <p>The following example explicitly creates a VARIANT object with a
- variant type of a byref string and a value 'Hello'. After making the
- call with this VARIANT the value is updated.
-
- <pre>
- >>> import win32com.client.dynamic
- >>> from win32com.client import VARIANT
- >>> import pythoncom
- >>> ob = win32com.client.dynamic.DumbDispatch("PyCOMTest.PyCOMTest")
- >>> variant = VARIANT(pythoncom.VT_BYREF | pythoncom.VT_BSTR, "Hello")
- >>> variant.value # check the value before the call.
- 'Hello'
- >>> ob.DoubleInOutString(variant)
- >>> variant.value
- u'HelloHello'
- >>>
- </pre>
-
- <h2>Usage with generated objects</h2>
-
- In most cases, objects with makepy support (ie, 'generated' objects) don't
- need to use the VARIANT object - the type information means win32com can guess
- the right thing to pass. However, in some cases the VARIANT object can still
- be useful.
-
- Imagine a poorly specified object with IDL like:
-
- <pre>
- HRESULT DoSomething([in] VARIANT value);
- </pre>
-
- But also imagine that the object has a limitation that if the parameter is an
- integer, it must be a 32bit unsigned value - any other integer representation
- will fail.
-
- <p>If you just pass a regular Python integer to this function, it will
- generally be passed as a 32bit signed integer and given the limitation above,
- will fail. The VARIANT object allows you to work around the limitation - just
- create a variant object <code>VARIANT(pythoncom.VT_UI4, int_value)</code> and
- pass that - the function will then be called with the explicit type you
- specified and will succeed.
-
- <p>Note that you can not use a VARIANT object to override the types described
- in a type library. If a makepy generated class specifies that a VT_UI2 is
- expected, attempting to pass a VARIANT object will fail. In this case you
- would need to hack around the problem. For example, imagine <code>ob</code>
- was a COM object which a method called <code>foo</code> and you wanted to
- override the type declaration for <code>foo</code> by passing a VARIANT.
- You could do something like:
-
- <pre>
- >>> import win32com.client.dynamic
- >>> from win32com.client import VARIANT
- >>> import pythoncom
- >>> dumbob = win32com.client.dynamic.DumbDispatch(ob)
- >>> variant = VARIANT(pythoncom.VT_BYREF | pythoncom.VT_BSTR, "Hello")
- >>> dumbob.foo(variant)
- </pre>
-
- The code above converts the makepy supported <code>ob</code> into a
- 'dumb' (ie, non-makepy supported) version of the object, which will then
- allow you to use VARIANT objects for the problematic methods.
-
- </BODY>
- </HTML>
|