[PyKDE] PyQt ActiveX support: can't pass some types of parameters

Mike Thompson mike.spam.filter at day8.com.au
Tue Oct 12 00:53:17 BST 2004


I'm trying to manipulate ActiveX objects using pyQt, but I've hit the 
following brick wall:

    Methods on ActiveX objects can only be called with parameters that
    can be wrapped by QVariant. Which is a show-stopper of an issue
    unless there is a work around.

You can call methods (on activeX objects) with parameters which are 
strings, ints and dates - they are all wrapable by QVariant - but you 
can't pass one ActiveX object to another's method as a parameter because 
QVariant can't wrap a QaxObject.

To demonstrate what I'm struggling with, consider the following python 
code fragment written in terms of Mark Hammond's semi-official 
'win32com' package (http://www.python.org/windows/win32com/)

#-----------------------------------------------------------------------
# Try to initialise a 'RecordSet' (represents rows in a database table)
# from an in-memory xml document which specifies table schema and some
# rows.
# Both 'ReacordSet' and 'Stream' are stock-standard ActiveX components
# from Microsoft.
#

import win32com.client    # http://www.python.org/windows/win32com/

# real string content omitted because its large and complicated
aStringWhichContinsXmlInRightFormat = "..."

# STEP 1: create and initialise the Stream object, so it
#         contains the xml document.
streamObj = win32com.client.Dispatch("ADODB.Stream")
streamObj.Open()
streamObj.WriteText(aStringWhichContinsXmlInRightFormat)
streamObj.Position = 0

# STEP 2: create and intialise a RecordSet object
#         from the xml document in the stream object.
#
recordSetObj = win32com.client.Dispatch("ADODB.Recordset")
recordSetObj.Open(streamObj)      # XXXXXXX note: object parameter

# print out what's in the RecordSet
while not recordSetObj.EOF:
     strFieldValues = [str(f) for f in recordSetObj.Fields]
     print "\t".join(strFieldValues)
     recordSetObj.MoveNext()

#-----------------------------------------------------------------------

This win32com-based code works well enough.

My attempt to emulate this code with pyQt looks like this ....

#-----------------------------------------------------------------------
import qt
import qtaxcontainer


# STEP 1: create and initialise the Stream object, so it
#         contains the xml document.
#
streamObj = qtaxcontainer.QAxObject("ADODB.Stream")
streamObj.dynamicCall( "Open()" );
streamObj.dynamicCall( "WriteText(QString&)", 
qt.QVariant(aStringWhichContinsXmlInRightFormat) );
streamObj.dynamicCall( "SetPosition(int)", qt.QVariant(0) );

# STEP 2: create and intialise a RecordSet object
#         from the xml document in the stream object.
#
recordSetObj  = qtaxcontainer.QAxObject("ADODB.Recordset")
paramObj = qt.QVariant(streamObj)		# YYYYYYYYY
recordSetObj.dynamicCall( "Open(IDispatch*)",  paramObj);

#.... haven't tried to emulate the win32com final loop yet

#-----------------------------------------------------------------------

This script fails on the line marked YYYYYYY with the error:

      TypeError: too many arguments to QVariant(), 0 at most expected

which is because QVariant can't wrap 'streamObj' which is a QAxObject.

Am I missing something about ActiveX method calls?  Is there a work 
around?  It seems to mne that Qt MUST provide this sort of functionality 
if its serious about ActiveX support, but I've had a look into the Qt 
documentation and it simply acknowledges the issue - but there's no 
solution.

Why do I need this?  Why not just use win32com?  Well, I need the 
occasional ActiveX component in the pyQt GUI's I build, which means
I need to manipulate QAxObjects.

Solutions:
     1.  Obvious:  find a way to pass one QAxObject to another's
         method.
     2.  Perhaps: find a way to grab the "IDispatch*" out of the
         QAxObject and then wrap it in win32com.  (This is stretching
         my thin ActiveX understanding).
     3.  other?

--
Mike

BTW, in the interests of suppling all the code, here is the full
definition of 'aStringWhichContinsXmlInRightFormat' which I omitted
from the code fragments.

aStringWhichContinsXmlInRightFormat="""<xml 
xmlns:s='uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882'
	xmlns:dt='uuid:C2F41010-65B3-11d1-A29F-00AA00C14882'
	xmlns:rs='urn:schemas-microsoft-com:rowset'
	xmlns:z='#RowsetSchema'>
<s:Schema id='RowsetSchema'>
	<s:ElementType name='row' content='eltOnly'>
		<s:AttributeType name='CustomerID' rs:number='1' rs:nullable='true' 
rs:maydefer='true' rs:writeunknown='true'>
			<s:datatype dt:type='string' dt:maxLength='5'/>
		</s:AttributeType>
		<s:AttributeType name='Company' rs:number='2' rs:nullable='true' 
rs:maydefer='true' rs:writeunknown='true'>
			<s:datatype dt:type='string' dt:maxLength='40'/>
		</s:AttributeType>
		<s:AttributeType name='ContactName' rs:number='3' rs:nullable='true' 
rs:maydefer='true' rs:writeunknown='true'>
			<s:datatype dt:type='string' dt:maxLength='30'/>
		</s:AttributeType>
		<s:extends type='rs:rowbase'/>
	</s:ElementType>
</s:Schema>
<rs:data>
	<z:row CustomerID='ALFKI' Company='Alfreds' ContactName='Maria Anders'  />
	<z:row CustomerID='AROUT' Company='Horn Inc' ContactName='Thomas Hardy'  />
	<z:row CustomerID='BLAUS' Company='Delikates' ContactName='Hanna Moos'  />
	<z:row CustomerID='BOTTM' Company='Dollar Markets' ContactName='Eliz 
Lincoln' />
	<z:row CustomerID='WILMK' Company='Wilman Kala' ContactName='Matti Kart'/>
	<z:row CustomerID='WOLZA' Company='Wolski Zajazd' ContactName='Zbyszek 
Piest' />
</rs:data>
</xml>
"""






More information about the PyQt mailing list