AIM-PIbd-32-Kurbanova-A-A/aimenv/Lib/site-packages/win32com/server/util.py

230 lines
6.5 KiB
Python
Raw Normal View History

2024-10-02 22:15:59 +04:00
""" 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)