123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 |
- """ General Server side utilities
- """
- import pythoncom
- import winerror
-
- from . import policy
- from .exception import COMException
-
-
- def wrap(ob, iid=None, usePolicy=None, useDispatcher=None):
- """Wraps an object in a PyGDispatch gateway.
-
- Returns a client side PyI{iid} interface.
-
- Interface and gateway support must exist for the specified IID, as
- the QueryInterface() method is used.
-
- """
- if usePolicy is None:
- usePolicy = policy.DefaultPolicy
- if useDispatcher == 1: # True will also work here.
- import win32com.server.dispatcher
-
- useDispatcher = win32com.server.dispatcher.DefaultDebugDispatcher
- if useDispatcher is None or useDispatcher == 0:
- ob = usePolicy(ob)
- else:
- ob = useDispatcher(usePolicy, ob)
-
- # get a PyIDispatch, which interfaces to PyGDispatch
- ob = pythoncom.WrapObject(ob)
- if iid is not None:
- ob = ob.QueryInterface(iid) # Ask the PyIDispatch if it supports it?
- return ob
-
-
- def unwrap(ob):
- """Unwraps an interface.
-
- Given an interface which wraps up a Gateway, return the object behind
- the gateway.
- """
- ob = pythoncom.UnwrapObject(ob)
- # see if the object is a dispatcher
- if hasattr(ob, "policy"):
- ob = ob.policy
- return ob._obj_
-
-
- class ListEnumerator:
- """A class to expose a Python sequence as an EnumVARIANT.
-
- Create an instance of this class passing a sequence (list, tuple, or
- any sequence protocol supporting object) and it will automatically
- support the EnumVARIANT interface for the object.
-
- See also the @NewEnum@ function, which can be used to turn the
- instance into an actual COM server.
- """
-
- _public_methods_ = ["Next", "Skip", "Reset", "Clone"]
-
- def __init__(self, data, index=0, iid=pythoncom.IID_IEnumVARIANT):
- self._list_ = data
- self.index = index
- self._iid_ = iid
-
- def _query_interface_(self, iid):
- if iid == self._iid_:
- return 1
-
- def Next(self, count):
- result = self._list_[self.index : self.index + count]
- self.Skip(count)
- return result
-
- def Skip(self, count):
- end = self.index + count
- if end > len(self._list_):
- end = len(self._list_)
- self.index = end
-
- def Reset(self):
- self.index = 0
-
- def Clone(self):
- return self._wrap(self.__class__(self._list_, self.index))
-
- def _wrap(self, ob):
- return wrap(ob)
-
-
- class ListEnumeratorGateway(ListEnumerator):
- """A List Enumerator which wraps a sequence's items in gateways.
-
- If a sequence contains items (objects) that have not been wrapped for
- return through the COM layers, then a ListEnumeratorGateway can be
- used to wrap those items before returning them (from the Next() method).
-
- See also the @ListEnumerator@ class and the @NewEnum@ function.
- """
-
- def Next(self, count):
- result = self._list_[self.index : self.index + count]
- self.Skip(count)
- return map(self._wrap, result)
-
-
- def NewEnum(
- seq,
- cls=ListEnumerator,
- iid=pythoncom.IID_IEnumVARIANT,
- usePolicy=None,
- useDispatcher=None,
- ):
- """Creates a new enumerator COM server.
-
- This function creates a new COM Server that implements the
- IID_IEnumVARIANT interface.
-
- A COM server that can enumerate the passed in sequence will be
- created, then wrapped up for return through the COM framework.
- Optionally, a custom COM server for enumeration can be passed
- (the default is @ListEnumerator@), and the specific IEnum
- interface can be specified.
- """
- ob = cls(seq, iid=iid)
- return wrap(ob, iid, usePolicy=usePolicy, useDispatcher=useDispatcher)
-
-
- class Collection:
- "A collection of VARIANT values."
-
- _public_methods_ = ["Item", "Count", "Add", "Remove", "Insert"]
-
- def __init__(self, data=None, readOnly=0):
- if data is None:
- data = []
- self.data = data
-
- # disable Add/Remove if read-only. note that we adjust _public_methods_
- # on this instance only.
- if readOnly:
- self._public_methods_ = ["Item", "Count"]
-
- # This method is also used as the "default" method.
- # Thus "print ob" will cause this to be called with zero
- # params. Handle this slightly more elegantly here.
- # Ideally the policy should handle this.
- def Item(self, *args):
- if len(args) != 1:
- raise COMException(scode=winerror.DISP_E_BADPARAMCOUNT)
-
- try:
- return self.data[args[0]]
- except IndexError as desc:
- raise COMException(scode=winerror.DISP_E_BADINDEX, desc=str(desc))
-
- _value_ = Item
-
- def Count(self):
- return len(self.data)
-
- def Add(self, value):
- self.data.append(value)
-
- def Remove(self, index):
- try:
- del self.data[index]
- except IndexError as desc:
- raise COMException(scode=winerror.DISP_E_BADINDEX, desc=str(desc))
-
- def Insert(self, index, value):
- try:
- index = int(index)
- except (ValueError, TypeError):
- raise COMException(scode=winerror.DISP_E_TYPEMISMATCH)
- self.data.insert(index, value)
-
- def _NewEnum(self):
- return NewEnum(self.data)
-
-
- def NewCollection(seq, cls=Collection):
- """Creates a new COM collection object
-
- This function creates a new COM Server that implements the
- common collection protocols, including enumeration. (_NewEnum)
-
- A COM server that can enumerate the passed in sequence will be
- created, then wrapped up for return through the COM framework.
- Optionally, a custom COM server for enumeration can be passed
- (the default is @Collection@).
- """
- return pythoncom.WrapObject(
- policy.DefaultPolicy(cls(seq)), pythoncom.IID_IDispatch, pythoncom.IID_IDispatch
- )
-
-
- class FileStream:
- _public_methods_ = ["Read", "Write", "Clone", "CopyTo", "Seek"]
- _com_interfaces_ = [pythoncom.IID_IStream]
-
- def __init__(self, file):
- self.file = file
-
- def Read(self, amount):
- return self.file.read(amount)
-
- def Write(self, data):
- self.file.write(data)
- return len(data)
-
- def Clone(self):
- return self._wrap(self.__class__(self.file))
-
- def CopyTo(self, dest, cb):
- data = self.file.read(cb)
- cbread = len(data)
- dest.Write(data) ## ??? Write does not currently return the length ???
- return cbread, cbread
-
- def Seek(self, offset, origin):
- # how convient that the 'origin' values are the same as the CRT :)
- self.file.seek(offset, origin)
- return self.file.tell()
-
- def _wrap(self, ob):
- return wrap(ob)
|