"Universal Gateway"
Neil Hodgson
nhodgson at bigpond.net.au
Tue Nov 5 06:32:08 EST 2002
Paul Moore:
> If so, is there a way to *call* an arbitrary interface?
> (Actually, I imagine that this should be possible using calldll plus a
> reasonable amount of arcane pointer arithmetic, but it sounds like it
> could be a bit messy and error prone...)
Looks like my posts that include attachments are no longer propagating.
Bruce Dodson:
> I, too, salivated when I first heard about universal gateway. However, on
> closer inspection, I found that it is outbound only: while it will allow
you
> to _implement_ just about any arbitrary interface in a Python server, it
> will not allow your Python code to _access_ those custom interfaces as a
> client.
Way back in 1997, I published some very low level code for calling
arbitrary COM vtable interfaces using calldll on the Pythonwin sig mailing
list and it is visible at
http://groups.yahoo.com/group/pythonwin-sig/message/490
Unfortunately the yahoo interface flattens the code and calldll has
changed since then, and ni has gone away :-( , so the code, resurrected
a bit, is at the end of this post and available from
http://www.scintilla.org/COMVtable.py
You can get copies of calldll and npstruct for Python 2.2 from
http://www.activestate.com/PPMPackages/PyPPM/2.2+/packages/
It is a very ugly way to do COM.
Neil
import pythoncom
import calldll
import string
import npstruct
METH_QI = 0
METH_ADDREF = 1
METH_RELEASE = 2
METH_UPDATE = 13
METH_IS_UPTODATE = 14
class dwordbuf:
def __init__(self):
self.mb = calldll.membuf(4)
def address(self):
return self.mb.address()
def value(self):
return calldll.read_long(self.address())
class Unknown:
def __init__(self, address, iid, fNeedAddRef = 1):
self.address = address
self.iid = iid
# External use needs to addref, not needed if created by
# internal QueryInterface
if fNeedAddRef:
self.AddRef()
def __del__(self):
self.Release()
def Call(self, methnum, args = (), argdesc = "*", retdesc = "l"):
if argdesc == "*": # intuit argument types
argdesc = 'l'*len(args)
#print 'Call ' + `methnum` + ' ' + `self.address`
vtable = calldll.read_long(self.address)
vtmeth = calldll.read_long(vtable+methnum * 4)
# Prepend interface pointer to arg list
argdesc = "l" + argdesc
args = (self.address, ) + args
#print args
hres = calldll.call_foreign_function(vtmeth, argdesc, retdesc, args)
return hres
def QueryInterface(self, iid): # iid is a membuf holding a GUID
bufPunk = dwordbuf()
hres = self.Call(METH_QI, (iid.address(), bufPunk.address()))
addrnewunk = bufPunk.value()
return Unknown(addrnewunk, iid, 0)
def AddRef(self):
return self.Call(METH_ADDREF)
def Release(self):
return self.Call(METH_RELEASE)
def GetCOMAddress(unk):
# Ugly way to get address of COM object represented by a
# PyIUnknown by asking for its string representation.
cdesc = `unk`
cpt = string.atoi(cdesc[36:-1],16)
return cpt
def GUIDBuf(guid):
buf = calldll.membuf(16)
gs = npstruct.pack('Llhhbbbbbbbb',(
eval('0x' + guid[1:1+8]),
string.atoi(guid[10:10+4],16),
string.atoi(guid[15:15+4],16),
string.atoi(guid[20:20+2],16),
string.atoi(guid[22:22+2],16),
string.atoi(guid[25:25+2],16),
string.atoi(guid[27:27+2],16),
string.atoi(guid[29:29+2],16),
string.atoi(guid[31:31+2],16),
string.atoi(guid[33:33+2],16),
string.atoi(guid[35:35+2],16)))
buf.write(gs,0,16)
return buf
StdPict =
pythoncom.CoCreateInstance('{00000316-0000-0000-C000-000000000046}',
None, 1, pythoncom.IID_IUnknown)
StdPictOle =
StdPict.QueryInterface('{00000112-0000-0000-C000-000000000046}', 1)
iidOleObject = GUIDBuf('{00000112-0000-0000-C000-000000000046}')
pictOle = Unknown(GetCOMAddress(StdPictOle), iidOleObject)
hres = pictOle.Call(METH_IS_UPTODATE)
print 'HRESULT = ' + hex(hres)
# Destroy it now to avoid problems in automatic tear down
pictOle = None
More information about the Python-list
mailing list