Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

util.py 6.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. """ General Server side utilities
  2. """
  3. import pythoncom
  4. import winerror
  5. from . import policy
  6. from .exception import COMException
  7. def wrap(ob, iid=None, usePolicy=None, useDispatcher=None):
  8. """Wraps an object in a PyGDispatch gateway.
  9. Returns a client side PyI{iid} interface.
  10. Interface and gateway support must exist for the specified IID, as
  11. the QueryInterface() method is used.
  12. """
  13. if usePolicy is None:
  14. usePolicy = policy.DefaultPolicy
  15. if useDispatcher == 1: # True will also work here.
  16. import win32com.server.dispatcher
  17. useDispatcher = win32com.server.dispatcher.DefaultDebugDispatcher
  18. if useDispatcher is None or useDispatcher == 0:
  19. ob = usePolicy(ob)
  20. else:
  21. ob = useDispatcher(usePolicy, ob)
  22. # get a PyIDispatch, which interfaces to PyGDispatch
  23. ob = pythoncom.WrapObject(ob)
  24. if iid is not None:
  25. ob = ob.QueryInterface(iid) # Ask the PyIDispatch if it supports it?
  26. return ob
  27. def unwrap(ob):
  28. """Unwraps an interface.
  29. Given an interface which wraps up a Gateway, return the object behind
  30. the gateway.
  31. """
  32. ob = pythoncom.UnwrapObject(ob)
  33. # see if the object is a dispatcher
  34. if hasattr(ob, "policy"):
  35. ob = ob.policy
  36. return ob._obj_
  37. class ListEnumerator:
  38. """A class to expose a Python sequence as an EnumVARIANT.
  39. Create an instance of this class passing a sequence (list, tuple, or
  40. any sequence protocol supporting object) and it will automatically
  41. support the EnumVARIANT interface for the object.
  42. See also the @NewEnum@ function, which can be used to turn the
  43. instance into an actual COM server.
  44. """
  45. _public_methods_ = ["Next", "Skip", "Reset", "Clone"]
  46. def __init__(self, data, index=0, iid=pythoncom.IID_IEnumVARIANT):
  47. self._list_ = data
  48. self.index = index
  49. self._iid_ = iid
  50. def _query_interface_(self, iid):
  51. if iid == self._iid_:
  52. return 1
  53. def Next(self, count):
  54. result = self._list_[self.index : self.index + count]
  55. self.Skip(count)
  56. return result
  57. def Skip(self, count):
  58. end = self.index + count
  59. if end > len(self._list_):
  60. end = len(self._list_)
  61. self.index = end
  62. def Reset(self):
  63. self.index = 0
  64. def Clone(self):
  65. return self._wrap(self.__class__(self._list_, self.index))
  66. def _wrap(self, ob):
  67. return wrap(ob)
  68. class ListEnumeratorGateway(ListEnumerator):
  69. """A List Enumerator which wraps a sequence's items in gateways.
  70. If a sequence contains items (objects) that have not been wrapped for
  71. return through the COM layers, then a ListEnumeratorGateway can be
  72. used to wrap those items before returning them (from the Next() method).
  73. See also the @ListEnumerator@ class and the @NewEnum@ function.
  74. """
  75. def Next(self, count):
  76. result = self._list_[self.index : self.index + count]
  77. self.Skip(count)
  78. return map(self._wrap, result)
  79. def NewEnum(
  80. seq,
  81. cls=ListEnumerator,
  82. iid=pythoncom.IID_IEnumVARIANT,
  83. usePolicy=None,
  84. useDispatcher=None,
  85. ):
  86. """Creates a new enumerator COM server.
  87. This function creates a new COM Server that implements the
  88. IID_IEnumVARIANT interface.
  89. A COM server that can enumerate the passed in sequence will be
  90. created, then wrapped up for return through the COM framework.
  91. Optionally, a custom COM server for enumeration can be passed
  92. (the default is @ListEnumerator@), and the specific IEnum
  93. interface can be specified.
  94. """
  95. ob = cls(seq, iid=iid)
  96. return wrap(ob, iid, usePolicy=usePolicy, useDispatcher=useDispatcher)
  97. class Collection:
  98. "A collection of VARIANT values."
  99. _public_methods_ = ["Item", "Count", "Add", "Remove", "Insert"]
  100. def __init__(self, data=None, readOnly=0):
  101. if data is None:
  102. data = []
  103. self.data = data
  104. # disable Add/Remove if read-only. note that we adjust _public_methods_
  105. # on this instance only.
  106. if readOnly:
  107. self._public_methods_ = ["Item", "Count"]
  108. # This method is also used as the "default" method.
  109. # Thus "print ob" will cause this to be called with zero
  110. # params. Handle this slightly more elegantly here.
  111. # Ideally the policy should handle this.
  112. def Item(self, *args):
  113. if len(args) != 1:
  114. raise COMException(scode=winerror.DISP_E_BADPARAMCOUNT)
  115. try:
  116. return self.data[args[0]]
  117. except IndexError as desc:
  118. raise COMException(scode=winerror.DISP_E_BADINDEX, desc=str(desc))
  119. _value_ = Item
  120. def Count(self):
  121. return len(self.data)
  122. def Add(self, value):
  123. self.data.append(value)
  124. def Remove(self, index):
  125. try:
  126. del self.data[index]
  127. except IndexError as desc:
  128. raise COMException(scode=winerror.DISP_E_BADINDEX, desc=str(desc))
  129. def Insert(self, index, value):
  130. try:
  131. index = int(index)
  132. except (ValueError, TypeError):
  133. raise COMException(scode=winerror.DISP_E_TYPEMISMATCH)
  134. self.data.insert(index, value)
  135. def _NewEnum(self):
  136. return NewEnum(self.data)
  137. def NewCollection(seq, cls=Collection):
  138. """Creates a new COM collection object
  139. This function creates a new COM Server that implements the
  140. common collection protocols, including enumeration. (_NewEnum)
  141. A COM server that can enumerate the passed in sequence will be
  142. created, then wrapped up for return through the COM framework.
  143. Optionally, a custom COM server for enumeration can be passed
  144. (the default is @Collection@).
  145. """
  146. return pythoncom.WrapObject(
  147. policy.DefaultPolicy(cls(seq)), pythoncom.IID_IDispatch, pythoncom.IID_IDispatch
  148. )
  149. class FileStream:
  150. _public_methods_ = ["Read", "Write", "Clone", "CopyTo", "Seek"]
  151. _com_interfaces_ = [pythoncom.IID_IStream]
  152. def __init__(self, file):
  153. self.file = file
  154. def Read(self, amount):
  155. return self.file.read(amount)
  156. def Write(self, data):
  157. self.file.write(data)
  158. return len(data)
  159. def Clone(self):
  160. return self._wrap(self.__class__(self.file))
  161. def CopyTo(self, dest, cb):
  162. data = self.file.read(cb)
  163. cbread = len(data)
  164. dest.Write(data) ## ??? Write does not currently return the length ???
  165. return cbread, cbread
  166. def Seek(self, offset, origin):
  167. # how convient that the 'origin' values are the same as the CRT :)
  168. self.file.seek(offset, origin)
  169. return self.file.tell()
  170. def _wrap(self, ob):
  171. return wrap(ob)