codekingpro/portable-devtools
114k
1"""General client side utilities.2 3This module contains utility functions, used primarily by advanced COM4programmers, or other COM modules.5"""6import pythoncom7from win32com.client import Dispatch, _get_good_object_8 9PyIDispatchType = pythoncom.TypeIIDs[pythoncom.IID_IDispatch]10 11 12def WrapEnum(ob, resultCLSID=None):13 """Wrap an object in a VARIANT enumerator.14 15 All VT_DISPATCHs returned by the enumerator are converted to wrapper objects16 (which may be either a class instance, or a dynamic.Dispatch type object).17 18 """19 if type(ob) != pythoncom.TypeIIDs[pythoncom.IID_IEnumVARIANT]:20 ob = ob.QueryInterface(pythoncom.IID_IEnumVARIANT)21 return EnumVARIANT(ob, resultCLSID)22 23 24class Enumerator:25 """A class that provides indexed access into an Enumerator26 27 By wrapping a PyIEnum* object in this class, you can perform28 natural looping and indexing into the Enumerator.29 30 Looping is very efficient, but it should be noted that although random31 access is supported, the underlying object is still an enumerator, so32 this will force many reset-and-seek operations to find the requested index.33 34 """35 36 def __init__(self, enum):37 self._oleobj_ = enum # a PyIEnumVARIANT38 self.index = -139 40 def __getitem__(self, index):41 return self.__GetIndex(index)42 43 def __call__(self, index):44 return self.__GetIndex(index)45 46 def __GetIndex(self, index):47 if type(index) != type(0):48 raise TypeError("Only integer indexes are supported for enumerators")49 # NOTE50 # In this context, self.index is users purely as a flag to say51 # "am I still in sequence". The user may call Next() or Reset() if they52 # so choose, in which case self.index will not be correct (although we53 # still want to stay in sequence)54 if index != self.index + 1:55 # Index requested out of sequence.56 self._oleobj_.Reset()57 if index:58 self._oleobj_.Skip(59 index60 ) # if asked for item 1, must skip 1, Python always zero based.61 self.index = index62 result = self._oleobj_.Next(1)63 if len(result):64 return self._make_retval_(result[0])65 raise IndexError("list index out of range")66 67 def Next(self, count=1):68 ret = self._oleobj_.Next(count)69 realRets = []70 for r in ret:71 realRets.append(self._make_retval_(r))72 return tuple(realRets) # Convert back to tuple.73 74 def Reset(self):75 return self._oleobj_.Reset()76 77 def Clone(self):78 return self.__class__(self._oleobj_.Clone(), self.resultCLSID)79 80 def _make_retval_(self, result):81 return result82 83 84class EnumVARIANT(Enumerator):85 def __init__(self, enum, resultCLSID=None):86 self.resultCLSID = resultCLSID87 Enumerator.__init__(self, enum)88 89 def _make_retval_(self, result):90 return _get_good_object_(result, resultCLSID=self.resultCLSID)91 92 93class Iterator:94 def __init__(self, enum, resultCLSID=None):95 self.resultCLSID = resultCLSID96 self._iter_ = iter(enum.QueryInterface(pythoncom.IID_IEnumVARIANT))97 98 def __iter__(self):99 return self100 101 def __next__(self):102 return _get_good_object_(next(self._iter_), resultCLSID=self.resultCLSID)103 