我曾经也遇到同样的问题,但现在我已经想出了一个对我有效的解决方案。
我创建了一个名为ComWrapper的类,用它来包装Excel COM对象。当在ComWrapper中调用嵌套对象和函数时,每个对象和函数都会自动进行包装和拆包处理。该包装程序通过捕获“调用被被叫方拒绝”异常并重试调用直到达到顶部定义的超时时间。如果达到超时时间,最后会在包装对象外抛出异常。
针对已包装对象的函数调用将自动包装到一个名为_com_call_wrapper的函数中,魔术就是在这里发生的。
要使其正常工作,只需使用ComWrapper从Dispatch中包装com对象,然后像代码底部那样一样使用即可。如果有问题,请留言。
import win32com.client
from pywintypes import com_error
import time
import logging
_DELAY = 0.05
_TIMEOUT = 60.0
def _com_call_wrapper(f, *args, **kwargs):
"""
COMWrapper support function.
Repeats calls when 'Call was rejected by callee.' exception occurs.
"""
args = [arg._wrapped_object if isinstance(arg, ComWrapper) else arg for arg in args]
kwargs = dict([(key, value._wrapped_object)
if isinstance(value, ComWrapper)
else (key, value)
for key, value in dict(kwargs).items()])
start_time = None
while True:
try:
result = f(*args, **kwargs)
except com_error as e:
if e.strerror == 'Call was rejected by callee.':
if start_time is None:
start_time = time.time()
logging.warning('Call was rejected by callee.')
elif time.time() - start_time >= _TIMEOUT:
raise
time.sleep(_DELAY)
continue
raise
break
if isinstance(result, win32com.client.CDispatch) or callable(result):
return ComWrapper(result)
return result
class ComWrapper(object):
"""
Class to wrap COM objects to repeat calls when 'Call was rejected by callee.' exception occurs.
"""
def __init__(self, wrapped_object):
assert isinstance(wrapped_object, win32com.client.CDispatch) or callable(wrapped_object)
self.__dict__['_wrapped_object'] = wrapped_object
def __getattr__(self, item):
return _com_call_wrapper(self._wrapped_object.__getattr__, item)
def __getitem__(self, item):
return _com_call_wrapper(self._wrapped_object.__getitem__, item)
def __setattr__(self, key, value):
_com_call_wrapper(self._wrapped_object.__setattr__, key, value)
def __setitem__(self, key, value):
_com_call_wrapper(self._wrapped_object.__setitem__, key, value)
def __call__(self, *args, **kwargs):
return _com_call_wrapper(self._wrapped_object.__call__, *args, **kwargs)
def __repr__(self):
return 'ComWrapper<{}>'.format(repr(self._wrapped_object))
_xl = win32com.client.dynamic.Dispatch('Excel.Application')
xl = ComWrapper(_xl)
我在这里给一个新问题提供了同样的答案:
https://dev59.com/N7Hma4cB1Zd3GeqPMYDO#55892457